{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (main) where
import Prelude ()
import Prelude.Compat
import Control.DeepSeq
import Criterion.Main
import Data.Hashable
import Data.Proxy (Proxy (..))
import Data.Tagged (Tagged (..))
import qualified "aeson" Data.Aeson as A
import qualified "aeson-benchmarks" Data.Aeson as B
import qualified "aeson-benchmarks" Data.Aeson.Types as B (fromJSONKeyCoerce)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as M
import qualified Data.Text as T
value :: Int -> HM.HashMap T.Text T.Text
value n = HM.fromList $ map f [1..n]
where
f m = let t = T.pack (show m) in (t, t)
-------------------------------------------------------------------------------
-- Orphans
-------------------------------------------------------------------------------
instance Hashable b => Hashable (Tagged a b) where
hashWithSalt salt (Tagged a) = hashWithSalt salt a
-------------------------------------------------------------------------------
-- Text
-------------------------------------------------------------------------------
newtype T1 = T1 T.Text
deriving (Eq, Ord)
instance NFData T1 where
rnf (T1 t) = rnf t
instance Hashable T1 where
hashWithSalt salt (T1 t) = hashWithSalt salt t
instance B.FromJSON T1 where
parseJSON = B.withText "T1" $ pure . T1
instance B.FromJSONKey T1 where
fromJSONKey = B.FromJSONKeyText T1
-------------------------------------------------------------------------------
-- Coerce
-------------------------------------------------------------------------------
newtype T2 = T2 T.Text
deriving (Eq, Ord)
instance NFData T2 where
rnf (T2 t) = rnf t
instance Hashable T2 where
hashWithSalt salt (T2 t) = hashWithSalt salt t
instance B.FromJSON T2 where
parseJSON = B.withText "T2" $ pure . T2
instance B.FromJSONKey T2 where
fromJSONKey = B.fromJSONKeyCoerce
-------------------------------------------------------------------------------
-- TextParser
-------------------------------------------------------------------------------
newtype T3 = T3 T.Text
deriving (Eq, Ord)
instance NFData T3 where
rnf (T3 t) = rnf t
instance Hashable T3 where
hashWithSalt salt (T3 t) = hashWithSalt salt t
instance B.FromJSON T3 where
parseJSON = B.withText "T3" $ pure . T3
instance B.FromJSONKey T3 where
fromJSONKey = B.FromJSONKeyTextParser (pure . T3)
-------------------------------------------------------------------------------
-- Values
-------------------------------------------------------------------------------
value10, value100, value1000, value10000 :: HM.HashMap T.Text T.Text
value10 = value 10
value100 = value 100
value1000 = value 1000
value10000 = value 10000
encodedValue10 :: LBS.ByteString
encodedValue10 = B.encode value10
encodedValue100 :: LBS.ByteString
encodedValue100 = B.encode value100
encodedValue1000 :: LBS.ByteString
encodedValue1000 = B.encode value1000
encodedValue10000 :: LBS.ByteString
encodedValue10000 = B.encode value10000
-------------------------------------------------------------------------------
-- Helpers
-------------------------------------------------------------------------------
decodeHMB
:: (B.FromJSONKey k, Eq k, Hashable k)
=> Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
decodeHMB _ = B.decode
decodeHMA
:: (A.FromJSON (HM.HashMap k T.Text), Eq k, Hashable k)
=> Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
decodeHMA _ = A.decode
decodeMapB
:: (B.FromJSONKey k, Ord k)
=> Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
decodeMapB _ = B.decode
decodeMapA
:: (A.FromJSON (M.Map k T.Text), Ord k)
=> Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
decodeMapA _ = A.decode
proxyText :: Proxy T.Text
proxyText = Proxy
proxyT1 :: Proxy T1
proxyT1 = Proxy
proxyT2 :: Proxy T2
proxyT2 = Proxy
proxyT3 :: Proxy T3
proxyT3 = Proxy
proxyTagged :: Proxy a -> Proxy (Tagged () a)
proxyTagged _ = Proxy
-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------
benchDecodeHM
:: String
-> LBS.ByteString
-> Benchmark
benchDecodeHM name val = bgroup name
[ bench "Text" $ nf (decodeHMB proxyText) val
, bench "Identity" $ nf (decodeHMB proxyT1) val
, bench "Coerce" $ nf (decodeHMB proxyT2) val
, bench "Parser" $ nf (decodeHMB proxyT3) val
, bench "aeson-hackage" $ nf (decodeHMA proxyText) val
, bench "Tagged Text" $ nf (decodeHMB $ proxyTagged proxyText) val
, bench "Tagged Identity" $ nf (decodeHMB $ proxyTagged proxyT1) val
, bench "Tagged Coerce" $ nf (decodeHMB $ proxyTagged proxyT2) val
, bench "Tagged Parser" $ nf (decodeHMB $ proxyTagged proxyT3) val
]
benchDecodeMap
:: String
-> LBS.ByteString
-> Benchmark
benchDecodeMap name val = bgroup name
[ bench "Text" $ nf (decodeMapB proxyText) val
, bench "Identity" $ nf (decodeMapB proxyT1) val
, bench "Coerce" $ nf (decodeMapB proxyT2) val
, bench "Parser" $ nf (decodeMapB proxyT3) val
, bench "aeson-hackage" $ nf (decodeMapA proxyText) val
]
benchEncodeHM
:: String
-> HM.HashMap T.Text T.Text
-> Benchmark
benchEncodeHM name val = bgroup name
[ bench "Text" $ nf B.encode val
, bench "aeson-0.11" $ nf A.encode val
]
benchEncodeMap
:: String
-> HM.HashMap T.Text T.Text
-> Benchmark
benchEncodeMap name val = bgroup name
[ bench "Text" $ nf B.encode val'
, bench "aeson-0.11" $ nf A.encode val'
]
where
val' :: M.Map T.Text T.Text
val' = M.fromList . HM.toList $ val
main :: IO ()
main = defaultMain
[ bgroup "decode"
[ bgroup "HashMap"
[ benchDecodeHM "10" encodedValue10
, benchDecodeHM "100" encodedValue100
, benchDecodeHM "1000" encodedValue1000
, benchDecodeHM "10000" encodedValue10000
]
, bgroup "Map"
[ benchDecodeMap "10" encodedValue10
, benchDecodeMap "100" encodedValue100
, benchDecodeMap "1000" encodedValue1000
, benchDecodeMap "10000" encodedValue10000
]
]
, bgroup "encode"
[ bgroup "HashMap"
[ benchEncodeHM "100" value100
, benchEncodeHM "1000" value1000
, benchEncodeHM "10000" value10000
]
, bgroup "Map"
[ benchEncodeMap "100" value100
, benchEncodeMap "1000" value1000
, benchEncodeMap "10000" value10000
]
]
]