1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
module Micro
( benchmarks -- :: [Benchmark]
) where
import Criterion.Main
import Control.DeepSeq
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BS
import Foreign
import Codec.CBOR.Magic
import qualified Micro.MemSize
import Micro.DeepSeq ()
import qualified Micro.Load as Micro.Load
import qualified Micro.Types as Micro.Types ()
import qualified Micro.ReadShow as Micro.ReadShow
import qualified Micro.PkgBinary as Micro.PkgBinary
import qualified Micro.PkgCereal as Micro.PkgCereal
import qualified Micro.PkgStore as Micro.PkgStore
import qualified Micro.PkgAesonGeneric as Micro.PkgAesonGeneric
import qualified Micro.PkgAesonTH as Micro.PkgAesonTH
import qualified Micro.CBOR as Micro.CBOR
--------------------------------------------------------------------------------
-- A simple driver, for running every set of benchmarks.
benchmarks :: [Benchmark]
benchmarks =
[ bgroup "reference"
[ bench "deepseq" (whnf rnf tstdata)
, bench "memSize" (whnf (flip Micro.MemSize.memSize 0) tstdata)
]
, bgroup "encoding" $ deepseq tstdata
[ bench "binary" (whnf perfEncodeBinary tstdata)
, bench "cereal" (whnf perfEncodeCereal tstdata)
, bench "aeson generic" (whnf perfEncodeAesonGeneric tstdata)
, bench "aeson TH" (whnf perfEncodeAesonTH tstdata)
, bench "read/show" (whnf perfEncodeReadShow tstdata)
, bench "store" (whnf perfEncodeStore tstdata)
, bench "cbor" (whnf perfEncodeCBOR tstdata)
]
, bgroup "decoding" $ deepseq (tstdataB, tstdataC, tstdataA, tstdataS,
tstdataR)
[ bench "binary" (whnf perfDecodeBinary tstdataB)
, bench "cereal" (whnf perfDecodeCereal tstdataC)
, bench "aeson generic" (whnf perfDecodeAesonGeneric tstdataA)
, bench "aeson TH" (whnf perfDecodeAesonTH tstdataA)
, bench "read/show" (whnf perfDecodeReadShow tstdataS)
, bench "store" (whnf perfDecodeStore tstdataP)
, bench "cbor" (whnf perfDecodeCBOR tstdataR)
]
, bgroup "decoding + deepseq" $ deepseq (tstdataB, tstdataC, tstdataA,
tstdataS, tstdataR)
[ bench "binary" (nf perfDecodeBinary tstdataB)
, bench "cereal" (nf perfDecodeCereal tstdataC)
, bench "aeson generic" (nf perfDecodeAesonGeneric tstdataA)
, bench "aeson TH" (nf perfDecodeAesonTH tstdataA)
, bench "read/show" (nf perfDecodeReadShow tstdataS)
, bench "store" (nf perfDecodeStore tstdataP)
, bench "cbor" (nf perfDecodeCBOR tstdataR)
]
, env lowlevelPtrEnv $ \ptr ->
bgroup "lowlevel"
[ bench "grabWord16" (nf grabWord16 ptr)
, bench "grabWord32" (nf grabWord32 ptr)
, bench "grabWord64" (nf grabWord64 ptr)
]
]
where
-- Input data
tstdata = Micro.Load.mkBigTree 16 -- tree of size 2^16
!tstdataB = combineChunks $ Micro.PkgBinary.serialise tstdata
!tstdataC = combineChunks $ Micro.PkgCereal.serialise tstdata
!tstdataA = combineChunks $ Micro.PkgAesonTH.serialise tstdata
!tstdataS = combineChunks $ Micro.ReadShow.serialise tstdata
!tstdataP = Micro.PkgStore.serialise tstdata
!tstdataR = combineChunks $ Micro.CBOR.serialise tstdata
-- Encoding tests
perfEncodeBinary = BS.length . Micro.PkgBinary.serialise
perfEncodeCereal = BS.length . Micro.PkgCereal.serialise
perfEncodeAesonGeneric = BS.length . Micro.PkgAesonGeneric.serialise
perfEncodeAesonTH = BS.length . Micro.PkgAesonTH.serialise
perfEncodeReadShow = BS.length . Micro.ReadShow.serialise
perfEncodeStore = B.length . Micro.PkgStore.serialise
perfEncodeCBOR = BS.length . Micro.CBOR.serialise
-- Decoding tests
perfDecodeBinary = Micro.PkgBinary.deserialise
perfDecodeCereal = Micro.PkgCereal.deserialise
perfDecodeAesonGeneric = Micro.PkgAesonGeneric.deserialise
perfDecodeAesonTH = Micro.PkgAesonTH.deserialise
perfDecodeReadShow = Micro.ReadShow.deserialise
perfDecodeStore = Micro.PkgStore.deserialise
perfDecodeCBOR = Micro.CBOR.deserialise
-- | Allocate an 8-byte pointer, write a 64-bit word into
-- it, and return a @'Ptr' ()@ to be used by the low-level routines.
lowlevelPtrEnv :: IO (Ptr ())
lowlevelPtrEnv = do
ptr <- mallocBytes 8
poke ptr (0xDEADBEEFCAFEBABE :: Word64)
return (castPtr ptr)
-- Create lazy bytestring that contains single chunk, from the
-- bytestring that may contain multiple chunks.
combineChunks :: BS.ByteString -> BS.ByteString
combineChunks = BS.fromStrict . BS.toStrict
--------------------------------------------------------------------------------
-- An NFData instance for Ptr is in deepseq HEAD/1.4.2, but it's not released.
#if !MIN_VERSION_deepseq(1,4,2)
instance NFData (Ptr a) where rnf !_ = ()
#endif
|