ppad-bolt1-0.0.1: bench/Main.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Criterion.Main
import qualified Data.ByteString as BS
import Data.Word (Word16, Word32, Word64)
import Data.Int (Int8, Int16, Int32, Int64)
import Lightning.Protocol.BOLT1
import Lightning.Protocol.BOLT1.Codec
import Lightning.Protocol.BOLT1.TLV (encodeInitTlvs, encodeTlvRecord, parseInitTlvs)
-- Fixtures --------------------------------------------------------------------
-- Prevent constant folding by marking fixtures as NOINLINE.
{-# NOINLINE u16Val #-}
u16Val :: Word16
u16Val = 0x1234
{-# NOINLINE u32Val #-}
u32Val :: Word32
u32Val = 0x12345678
{-# NOINLINE u64Val #-}
u64Val :: Word64
u64Val = 0x123456789ABCDEF0
{-# NOINLINE s8Val #-}
s8Val :: Int8
s8Val = -42
{-# NOINLINE s16Val #-}
s16Val :: Int16
s16Val = -1234
{-# NOINLINE s32Val #-}
s32Val :: Int32
s32Val = -12345678
{-# NOINLINE s64Val #-}
s64Val :: Int64
s64Val = -123456789012345
-- Truncated values
{-# NOINLINE tu16Zero #-}
tu16Zero :: Word16
tu16Zero = 0
{-# NOINLINE tu16Small #-}
tu16Small :: Word16
tu16Small = 0x42
{-# NOINLINE tu16Max #-}
tu16Max :: Word16
tu16Max = 0xFFFF
{-# NOINLINE tu32Zero #-}
tu32Zero :: Word32
tu32Zero = 0
{-# NOINLINE tu32Small #-}
tu32Small :: Word32
tu32Small = 0x42
{-# NOINLINE tu32Max #-}
tu32Max :: Word32
tu32Max = 0xFFFFFFFF
{-# NOINLINE tu64Zero #-}
tu64Zero :: Word64
tu64Zero = 0
{-# NOINLINE tu64Small #-}
tu64Small :: Word64
tu64Small = 0x42
{-# NOINLINE tu64Max #-}
tu64Max :: Word64
tu64Max = 0xFFFFFFFFFFFFFFFF
-- MinSigned values
{-# NOINLINE ms0 #-}
ms0 :: Int64
ms0 = 0
{-# NOINLINE ms127 #-}
ms127 :: Int64
ms127 = 127
{-# NOINLINE ms128 #-}
ms128 :: Int64
ms128 = 128
{-# NOINLINE msNeg128 #-}
msNeg128 :: Int64
msNeg128 = -128
{-# NOINLINE msNeg129 #-}
msNeg129 :: Int64
msNeg129 = -129
-- BigSize values
{-# NOINLINE bs0 #-}
bs0 :: Word64
bs0 = 0
{-# NOINLINE bs252 #-}
bs252 :: Word64
bs252 = 252
{-# NOINLINE bs253 #-}
bs253 :: Word64
bs253 = 253
{-# NOINLINE bs65535 #-}
bs65535 :: Word64
bs65535 = 65535
{-# NOINLINE bs65536 #-}
bs65536 :: Word64
bs65536 = 65536
{-# NOINLINE bsLarge #-}
bsLarge :: Word64
bsLarge = 0x100000000
-- Encoded bytes for decode benchmarks
{-# NOINLINE encodedU16 #-}
encodedU16 :: BS.ByteString
encodedU16 = encodeU16 u16Val
{-# NOINLINE encodedU32 #-}
encodedU32 :: BS.ByteString
encodedU32 = encodeU32 u32Val
{-# NOINLINE encodedU64 #-}
encodedU64 :: BS.ByteString
encodedU64 = encodeU64 u64Val
{-# NOINLINE encodedS8 #-}
encodedS8 :: BS.ByteString
encodedS8 = encodeS8 s8Val
{-# NOINLINE encodedS16 #-}
encodedS16 :: BS.ByteString
encodedS16 = encodeS16 s16Val
{-# NOINLINE encodedS32 #-}
encodedS32 :: BS.ByteString
encodedS32 = encodeS32 s32Val
{-# NOINLINE encodedS64 #-}
encodedS64 :: BS.ByteString
encodedS64 = encodeS64 s64Val
{-# NOINLINE encodedTu16Small #-}
encodedTu16Small :: BS.ByteString
encodedTu16Small = encodeTu16 tu16Small
{-# NOINLINE encodedTu32Small #-}
encodedTu32Small :: BS.ByteString
encodedTu32Small = encodeTu32 tu32Small
{-# NOINLINE encodedTu64Small #-}
encodedTu64Small :: BS.ByteString
encodedTu64Small = encodeTu64 tu64Small
{-# NOINLINE encodedMs127 #-}
encodedMs127 :: BS.ByteString
encodedMs127 = encodeMinSigned ms127
{-# NOINLINE encodedMsNeg129 #-}
encodedMsNeg129 :: BS.ByteString
encodedMsNeg129 = encodeMinSigned msNeg129
{-# NOINLINE encodedBs0 #-}
encodedBs0 :: BS.ByteString
encodedBs0 = encodeBigSize bs0
{-# NOINLINE encodedBs253 #-}
encodedBs253 :: BS.ByteString
encodedBs253 = encodeBigSize bs253
{-# NOINLINE encodedBs65536 #-}
encodedBs65536 :: BS.ByteString
encodedBs65536 = encodeBigSize bs65536
{-# NOINLINE encodedBsLarge #-}
encodedBsLarge :: BS.ByteString
encodedBsLarge = encodeBigSize bsLarge
-- TLV fixtures
{-# NOINLINE tlvRec1 #-}
tlvRec1 :: TlvRecord
tlvRec1 = TlvRecord 1 "test"
{-# NOINLINE tlvRec3 #-}
tlvRec3 :: TlvRecord
tlvRec3 = TlvRecord 3 "addr"
{-# NOINLINE tlvRec5 #-}
tlvRec5 :: TlvRecord
tlvRec5 = TlvRecord 5 "value"
{-# NOINLINE tlvStream1 #-}
tlvStream1 :: TlvStream
tlvStream1 = unsafeTlvStream [tlvRec1]
{-# NOINLINE tlvStream5 #-}
tlvStream5 :: TlvStream
tlvStream5 = unsafeTlvStream
[ TlvRecord 1 "one"
, TlvRecord 3 "three"
, TlvRecord 5 "five"
, TlvRecord 7 "seven"
, TlvRecord 9 "nine"
]
{-# NOINLINE tlvStream20 #-}
tlvStream20 :: TlvStream
tlvStream20 = unsafeTlvStream
[ TlvRecord (2*i + 1) (BS.replicate 10 (fromIntegral i))
| i <- [0..19]
]
{-# NOINLINE encodedTlvStream1 #-}
encodedTlvStream1 :: BS.ByteString
encodedTlvStream1 = encodeTlvStream tlvStream1
{-# NOINLINE encodedTlvStream5 #-}
encodedTlvStream5 :: BS.ByteString
encodedTlvStream5 = encodeTlvStream tlvStream5
{-# NOINLINE encodedTlvStream20 #-}
encodedTlvStream20 :: BS.ByteString
encodedTlvStream20 = encodeTlvStream tlvStream20
-- Init TLV fixtures
{-# NOINLINE chainHash1 #-}
chainHash1 :: ChainHash
chainHash1 = case chainHash (BS.replicate 32 0x01) of
Just ch -> ch
Nothing -> error "impossible"
{-# NOINLINE initTlvNetworks #-}
initTlvNetworks :: [InitTlv]
initTlvNetworks = [InitNetworks [chainHash1]]
{-# NOINLINE initTlvRemoteAddr #-}
initTlvRemoteAddr :: [InitTlv]
initTlvRemoteAddr = [InitRemoteAddr "127.0.0.1"]
{-# NOINLINE encodedInitTlvs #-}
encodedInitTlvs :: BS.ByteString
encodedInitTlvs = encodeTlvStream (encodeInitTlvs initTlvNetworks)
-- Message fixtures
{-# NOINLINE initMinimal #-}
initMinimal :: Init
initMinimal = Init BS.empty BS.empty []
{-# NOINLINE initWithTlvs #-}
initWithTlvs :: Init
initWithTlvs = Init (BS.pack [0x00, 0x01]) (BS.pack [0x02, 0x03]) initTlvNetworks
{-# NOINLINE errorMinimal #-}
errorMinimal :: Error
errorMinimal = Error allChannels BS.empty
{-# NOINLINE errorWithData #-}
errorWithData :: Error
errorWithData = Error allChannels "Connection reset by peer"
{-# NOINLINE warningMsg #-}
warningMsg :: Warning
warningMsg = Warning allChannels "Low disk space"
{-# NOINLINE pingMinimal #-}
pingMinimal :: Ping
pingMinimal = Ping 64 BS.empty
{-# NOINLINE pingWithPadding #-}
pingWithPadding :: Ping
pingWithPadding = Ping 64 (BS.replicate 64 0x00)
{-# NOINLINE pongMsg #-}
pongMsg :: Pong
pongMsg = Pong (BS.replicate 64 0x00)
{-# NOINLINE peerStorageMsg #-}
peerStorageMsg :: PeerStorage
peerStorageMsg = PeerStorage (BS.replicate 100 0xAB)
{-# NOINLINE peerStorageRetMsg #-}
peerStorageRetMsg :: PeerStorageRetrieval
peerStorageRetMsg = PeerStorageRetrieval (BS.replicate 100 0xCD)
-- Encoded messages for decode benchmarks
{-# NOINLINE encodedInitMinimal #-}
encodedInitMinimal :: BS.ByteString
encodedInitMinimal = case encodeInit initMinimal of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedInitWithTlvs #-}
encodedInitWithTlvs :: BS.ByteString
encodedInitWithTlvs = case encodeInit initWithTlvs of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedErrorMinimal #-}
encodedErrorMinimal :: BS.ByteString
encodedErrorMinimal = case encodeError errorMinimal of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedErrorWithData #-}
encodedErrorWithData :: BS.ByteString
encodedErrorWithData = case encodeError errorWithData of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedWarning #-}
encodedWarning :: BS.ByteString
encodedWarning = case encodeWarning warningMsg of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedPingMinimal #-}
encodedPingMinimal :: BS.ByteString
encodedPingMinimal = case encodePing pingMinimal of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedPingWithPadding #-}
encodedPingWithPadding :: BS.ByteString
encodedPingWithPadding = case encodePing pingWithPadding of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedPong #-}
encodedPong :: BS.ByteString
encodedPong = case encodePong pongMsg of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedPeerStorage #-}
encodedPeerStorage :: BS.ByteString
encodedPeerStorage = case encodePeerStorage peerStorageMsg of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedPeerStorageRet #-}
encodedPeerStorageRet :: BS.ByteString
encodedPeerStorageRet = case encodePeerStorageRetrieval peerStorageRetMsg of
Right bs -> bs
Left _ -> error "impossible"
-- Envelope fixtures
{-# NOINLINE msgInit #-}
msgInit :: Message
msgInit = MsgInitVal initMinimal
{-# NOINLINE msgPing #-}
msgPing :: Message
msgPing = MsgPingVal pingMinimal
{-# NOINLINE encodedEnvelopeNoExt #-}
encodedEnvelopeNoExt :: BS.ByteString
encodedEnvelopeNoExt = case encodeEnvelope msgPing Nothing of
Right bs -> bs
Left _ -> error "impossible"
{-# NOINLINE encodedEnvelopeWithExt #-}
encodedEnvelopeWithExt :: BS.ByteString
encodedEnvelopeWithExt = case encodeEnvelope msgPing (Just tlvStream5) of
Right bs -> bs
Left _ -> error "impossible"
-- Main ------------------------------------------------------------------------
main :: IO ()
main = defaultMain
[ bgroup "prim/encode"
[ bench "encodeU16" $ whnf encodeU16 u16Val
, bench "encodeU32" $ whnf encodeU32 u32Val
, bench "encodeU64" $ whnf encodeU64 u64Val
, bench "encodeS8" $ whnf encodeS8 s8Val
, bench "encodeS16" $ whnf encodeS16 s16Val
, bench "encodeS32" $ whnf encodeS32 s32Val
, bench "encodeS64" $ whnf encodeS64 s64Val
, bench "encodeTu16/0" $ whnf encodeTu16 tu16Zero
, bench "encodeTu16/small" $ whnf encodeTu16 tu16Small
, bench "encodeTu16/max" $ whnf encodeTu16 tu16Max
, bench "encodeTu32/0" $ whnf encodeTu32 tu32Zero
, bench "encodeTu32/small" $ whnf encodeTu32 tu32Small
, bench "encodeTu32/max" $ whnf encodeTu32 tu32Max
, bench "encodeTu64/0" $ whnf encodeTu64 tu64Zero
, bench "encodeTu64/small" $ whnf encodeTu64 tu64Small
, bench "encodeTu64/max" $ whnf encodeTu64 tu64Max
, bench "encodeMinSigned/0" $ whnf encodeMinSigned ms0
, bench "encodeMinSigned/127" $ whnf encodeMinSigned ms127
, bench "encodeMinSigned/128" $ whnf encodeMinSigned ms128
, bench "encodeMinSigned/-128" $ whnf encodeMinSigned msNeg128
, bench "encodeMinSigned/-129" $ whnf encodeMinSigned msNeg129
, bench "encodeBigSize/0" $ whnf encodeBigSize bs0
, bench "encodeBigSize/252" $ whnf encodeBigSize bs252
, bench "encodeBigSize/253" $ whnf encodeBigSize bs253
, bench "encodeBigSize/65535" $ whnf encodeBigSize bs65535
, bench "encodeBigSize/65536" $ whnf encodeBigSize bs65536
, bench "encodeBigSize/large" $ whnf encodeBigSize bsLarge
]
, bgroup "prim/decode"
[ bench "decodeU16" $ nf decodeU16 encodedU16
, bench "decodeU32" $ nf decodeU32 encodedU32
, bench "decodeU64" $ nf decodeU64 encodedU64
, bench "decodeS8" $ nf decodeS8 encodedS8
, bench "decodeS16" $ nf decodeS16 encodedS16
, bench "decodeS32" $ nf decodeS32 encodedS32
, bench "decodeS64" $ nf decodeS64 encodedS64
, bench "decodeTu16" $ nf (decodeTu16 1) encodedTu16Small
, bench "decodeTu32" $ nf (decodeTu32 1) encodedTu32Small
, bench "decodeTu64" $ nf (decodeTu64 1) encodedTu64Small
, bench "decodeMinSigned/1" $ nf (decodeMinSigned 1) encodedMs127
, bench "decodeMinSigned/2" $ nf (decodeMinSigned 2) encodedMsNeg129
, bench "decodeBigSize/0" $ nf decodeBigSize encodedBs0
, bench "decodeBigSize/253" $ nf decodeBigSize encodedBs253
, bench "decodeBigSize/65536" $ nf decodeBigSize encodedBs65536
, bench "decodeBigSize/large" $ nf decodeBigSize encodedBsLarge
]
, bgroup "tlv/encode"
[ bench "encodeTlvRecord" $ whnf encodeTlvRecord tlvRec1
, bench "encodeTlvStream/1" $ whnf encodeTlvStream tlvStream1
, bench "encodeTlvStream/5" $ whnf encodeTlvStream tlvStream5
, bench "encodeTlvStream/20" $ whnf encodeTlvStream tlvStream20
, bench "encodeInitTlvs" $ nf encodeInitTlvs initTlvNetworks
]
, bgroup "tlv/decode"
[ bench "decodeTlvStreamRaw/1" $ nf decodeTlvStreamRaw encodedTlvStream1
, bench "decodeTlvStreamRaw/5" $ nf decodeTlvStreamRaw encodedTlvStream5
, bench "decodeTlvStreamRaw/20" $ nf decodeTlvStreamRaw encodedTlvStream20
, bench "decodeTlvStream" $ nf decodeTlvStream encodedInitTlvs
, bench "decodeTlvStreamWith" $
nf (decodeTlvStreamWith (const True)) encodedTlvStream5
, bench "parseInitTlvs" $
nf parseInitTlvs (encodeInitTlvs initTlvNetworks)
]
, bgroup "message/encode"
[ bench "encodeInit/minimal" $ nf encodeInit initMinimal
, bench "encodeInit/with-tlvs" $ nf encodeInit initWithTlvs
, bench "encodeError/minimal" $ nf encodeError errorMinimal
, bench "encodeError/with-data" $ nf encodeError errorWithData
, bench "encodeWarning" $ nf encodeWarning warningMsg
, bench "encodePing/minimal" $ nf encodePing pingMinimal
, bench "encodePing/with-padding" $ nf encodePing pingWithPadding
, bench "encodePong" $ nf encodePong pongMsg
, bench "encodePeerStorage" $ nf encodePeerStorage peerStorageMsg
, bench "encodePeerStorageRetrieval" $
nf encodePeerStorageRetrieval peerStorageRetMsg
]
, bgroup "message/decode"
[ bench "decodeInit/minimal" $ nf decodeInit encodedInitMinimal
, bench "decodeInit/with-tlvs" $ nf decodeInit encodedInitWithTlvs
, bench "decodeError/minimal" $ nf decodeError encodedErrorMinimal
, bench "decodeError/with-data" $ nf decodeError encodedErrorWithData
, bench "decodeWarning" $ nf decodeWarning encodedWarning
, bench "decodePing/minimal" $ nf decodePing encodedPingMinimal
, bench "decodePing/with-padding" $ nf decodePing encodedPingWithPadding
, bench "decodePong" $ nf decodePong encodedPong
, bench "decodePeerStorage" $ nf decodePeerStorage encodedPeerStorage
, bench "decodePeerStorageRetrieval" $
nf decodePeerStorageRetrieval encodedPeerStorageRet
]
, bgroup "envelope"
[ bench "encodeEnvelope/no-ext" $ nf (encodeEnvelope msgPing) Nothing
, bench "encodeEnvelope/with-ext" $
nf (encodeEnvelope msgPing) (Just tlvStream5)
, bench "decodeEnvelope/no-ext" $ nf decodeEnvelope encodedEnvelopeNoExt
, bench "decodeEnvelope/with-ext" $
nf decodeEnvelope encodedEnvelopeWithExt
, bench "decodeEnvelopeWith" $
nf (decodeEnvelopeWith (const True)) encodedEnvelopeWithExt
]
, bgroup "roundtrip"
[ bench "init/minimal" $ nf (decodeInit . forceRight . encodeInit)
initMinimal
, bench "init/with-tlvs" $ nf (decodeInit . forceRight . encodeInit)
initWithTlvs
, bench "error" $ nf (decodeError . forceRight . encodeError) errorWithData
, bench "warning" $ nf (decodeWarning . forceRight . encodeWarning)
warningMsg
, bench "ping" $ nf (decodePing . forceRight . encodePing) pingWithPadding
, bench "pong" $ nf (decodePong . forceRight . encodePong) pongMsg
, bench "peer-storage" $
nf (decodePeerStorage . forceRight . encodePeerStorage) peerStorageMsg
, bench "peer-storage-retrieval" $
nf (decodePeerStorageRetrieval . forceRight . encodePeerStorageRetrieval)
peerStorageRetMsg
, bench "envelope" $ nf
(decodeEnvelope . forceRight . encodeEnvelope msgPing) (Just tlvStream5)
]
]
-- Helper for roundtrip benchmarks
forceRight :: Either a b -> b
forceRight (Right b) = b
forceRight (Left _) = error "forceRight: Left"
{-# INLINE forceRight #-}