argo-0.2022.2.2: source/benchmark/Main.hs
import qualified Argo
import qualified Control.DeepSeq as DeepSeq
import qualified Control.Exception as Exception
import qualified Control.Monad.Trans.Writer as Writer
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Builder as Builder
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.List as List
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Encoding
import qualified Test.Tasty as Tasty
import qualified Test.Tasty.Bench as Bench
main :: IO ()
main = Bench.defaultMain . Writer.execWriter $ do
group "encode" $ do
group "Null" $ do
bench "null" Argo.Null encode
group "Boolean" $ do
bench "false" (Argo.Boolean False) encode
bench "true" (Argo.Boolean True) encode
group "Number" $ do
bench "zero" (Argo.Number $ Argo.Decimal 0 0) encode
group "String" $ do
let f n = Argo.String . Text.replicate n $ Text.singleton 'a'
bench "empty" (f 0) encode
bench "1 character" (f 1) encode
bench "10 characters" (f 10) encode
bench "100 characters" (f 100) encode
bench "1000 characters" (f 1000) encode
bench "10000 characters" (f 10000) encode
group "Array" $ do
let f n = Argo.Array $ replicate n Argo.Null
bench "empty" (f 0) encode
bench "1 element" (f 1) encode
bench "10 elements" (f 10) encode
bench "100 elements" (f 100) encode
bench "1000 elements" (f 1000) encode
bench "10000 elements" (f 10000) encode
group "Object" $ do
let
f n = Argo.Object . replicate n $ Argo.Member
(Argo.Name Text.empty)
Argo.Null
bench "empty" (f 0) encode
bench "1 element" (f 1) encode
bench "10 elements" (f 10) encode
bench "100 elements" (f 100) encode
bench "1000 elements" (f 1000) encode
bench "10000 elements" (f 10000) encode
group "decode" $ do
group "Null" $ do
bench "null" (utf8 "null") decode
group "Boolean" $ do
bench "false" (utf8 "false") decode
bench "true" (utf8 "true") decode
group "Number" $ do
bench "zero" (utf8 "0") decode
group "String" $ do
let f n = utf8 . wrap "\"" "\"" $ replicate n 'a'
bench "empty" (f 0) decode
bench "one byte" (utf8 "\"$\"") decode
bench "two bytes" (utf8 "\"\xc2\xa2\"") decode
bench "three bytes" (utf8 "\"\xe2\x82\xac\"") decode
bench "four bytes" (utf8 "\"\xf0\x90\x8d\x88\"") decode
bench "short escape" (utf8 "\"\\n\"") decode
bench "long escape" (utf8 "\"\\u001f\"") decode
bench "surrogate pair" (utf8 "\"\\ud834\\udd1e\"") decode
bench "1 element" (f 1) decode
bench "10 elements" (f 10) decode
bench "100 elements" (f 100) decode
bench "1000 elements" (f 1000) decode
bench "10000 elements" (f 10000) decode
group "Array" $ do
let
f n = utf8 . wrap "[" "]" . List.intercalate "," $ replicate
n
"null"
bench "empty" (f 0) decode
bench "1 element" (f 1) decode
bench "10 elements" (f 10) decode
bench "100 elements" (f 100) decode
bench "1000 elements" (f 1000) decode
bench "10000 elements" (f 10000) decode
group "Object" $ do
let
f n = utf8 . wrap "{" "}" . List.intercalate "," $ replicate
n
"\"\":null"
bench "empty" (f 0) decode
bench "1 element" (f 1) decode
bench "10 elements" (f 10) decode
bench "100 elements" (f 100) decode
bench "1000 elements" (f 1000) decode
bench "10000 elements" (f 10000) decode
bench
:: (DeepSeq.NFData a, DeepSeq.NFData b)
=> String
-> a
-> (a -> IO b)
-> Writer.Writer [Bench.Benchmark] ()
bench name x f =
Writer.tell
. pure
. Tasty.withResource (Exception.evaluate $ DeepSeq.force x) discard
$ Bench.bench name
. Bench.nfIO
. (>>= f)
decode :: ByteString.ByteString -> IO Argo.Value
decode = either fail pure . Argo.decode
discard :: Applicative f => a -> f ()
discard = const $ pure ()
encode :: Argo.Value -> IO LazyByteString.ByteString
encode = pure . Builder.toLazyByteString . Argo.encode
group
:: String
-> Writer.Writer [Bench.Benchmark] a
-> Writer.Writer [Bench.Benchmark] ()
group x = Writer.tell . pure . Bench.bgroup x . Writer.execWriter
utf8 :: String -> ByteString.ByteString
utf8 = Encoding.encodeUtf8 . Text.pack
wrap :: Monoid a => a -> a -> a -> a
wrap l r x = l <> x <> r