wireform-proto-0.1.0.0: bench/compare/Main.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- | Criterion benchmark: wireform vs proto-lens (real generated code).
Wireform side uses @Proto.CodeGen@ output (@Proto.Bench.Wireform.Messages@)
including the sorted-tag @inOrderStage@ decode fast path. Regenerate that
module after editing @bench/compare/gen-wireform/Messages.proto@:
> cabal run regen-compare-bench-wireform
Run: cabal bench compare-bench
-}
module Main where
import Criterion.Main
import Data.ByteString qualified as BS
import Data.Int (Int32, Int64)
import Data.ProtoLens (defMessage)
import Data.ProtoLens qualified as PLC
import Data.Text (Text)
import Data.Text qualified as T
import Data.Vector qualified as V
import Data.Vector.Unboxed qualified as VU
import Lens.Family2 ((&), (.~))
import Proto.Bench qualified as PL
import Proto.Bench.Wireform.Messages qualified as W
import Proto.Bench_Fields qualified as F
import Proto qualified as H
import Proto qualified as H
encSmallH :: W.Small -> BS.ByteString
encSmallH = H.encodeMessage
{-# NOINLINE encSmallH #-}
encMediumH :: W.Medium -> BS.ByteString
encMediumH = H.encodeMessage
{-# NOINLINE encMediumH #-}
encNestedH :: W.WithNested -> BS.ByteString
encNestedH = H.encodeMessage
{-# NOINLINE encNestedH #-}
encRepH :: W.WithRepeated -> BS.ByteString
encRepH = H.encodeMessage
{-# NOINLINE encRepH #-}
main :: IO ()
main =
defaultMain
[ bgroup
"Small"
[ bgroup
"encode"
[ bench "wireform" $ nf encSmallH smallHS
, bench "proto-lens" $ nf PLC.encodeMessage smallPL
]
, bgroup
"decode"
[ bench "wireform" $ nf decSmallH smallBytes
, bench "proto-lens" $ nf decSmallP smallBytes
]
, bgroup
"roundtrip"
[ bench "wireform" $ nf rtSmallH smallHS
, bench "proto-lens" $ nf rtSmallP smallPL
]
]
, bgroup
"Medium"
[ bgroup
"encode"
[ bench "wireform" $ nf encMediumH mediumHS
, bench "proto-lens" $ nf PLC.encodeMessage mediumPL
]
, bgroup
"decode"
[ bench "wireform" $ nf decMediumH mediumBytes
, bench "proto-lens" $ nf decMediumP mediumBytes
]
, bgroup
"roundtrip"
[ bench "wireform" $ nf rtMediumH mediumHS
, bench "proto-lens" $ nf rtMediumP mediumPL
]
]
, bgroup
"Nested"
[ bgroup
"encode"
[ bench "wireform" $ nf encNestedH nestedHS
, bench "proto-lens" $ nf PLC.encodeMessage nestedPL
]
, bgroup
"decode"
[ bench "wireform" $ nf decNestedH nestedBytes
, bench "proto-lens" $ nf decNestedP nestedBytes
]
, bgroup
"roundtrip"
[ bench "wireform" $ nf rtNestedH nestedHS
, bench "proto-lens" $ nf rtNestedP nestedPL
]
]
, bgroup
"Repeated"
[ bgroup
"encode"
[ bench "wireform" $ nf encRepH repeatedHS
, bench "proto-lens" $ nf PLC.encodeMessage repeatedPL
]
, bgroup
"decode"
[ bench "wireform" $ nf decRepH repeatedBytes
, bench "proto-lens" $ nf decRepP repeatedBytes
]
]
]
decSmallH :: BS.ByteString -> Either H.DecodeError W.Small
decSmallH = H.decodeMessage
{-# NOINLINE decSmallH #-}
decSmallP :: BS.ByteString -> Either String PL.Small
decSmallP = PLC.decodeMessage
{-# NOINLINE decSmallP #-}
rtSmallH :: W.Small -> Either H.DecodeError W.Small
rtSmallH m = H.decodeMessage (H.encodeMessage m)
{-# NOINLINE rtSmallH #-}
rtSmallP :: PL.Small -> Either String PL.Small
rtSmallP m = PLC.decodeMessage (PLC.encodeMessage m)
{-# NOINLINE rtSmallP #-}
decMediumH :: BS.ByteString -> Either H.DecodeError W.Medium
decMediumH = H.decodeMessage
{-# NOINLINE decMediumH #-}
decMediumP :: BS.ByteString -> Either String PL.Medium
decMediumP = PLC.decodeMessage
{-# NOINLINE decMediumP #-}
rtMediumH :: W.Medium -> Either H.DecodeError W.Medium
rtMediumH m = H.decodeMessage (H.encodeMessage m)
{-# NOINLINE rtMediumH #-}
rtMediumP :: PL.Medium -> Either String PL.Medium
rtMediumP m = PLC.decodeMessage (PLC.encodeMessage m)
{-# NOINLINE rtMediumP #-}
decNestedH :: BS.ByteString -> Either H.DecodeError W.WithNested
decNestedH = H.decodeMessage
{-# NOINLINE decNestedH #-}
decNestedP :: BS.ByteString -> Either String PL.WithNested
decNestedP = PLC.decodeMessage
{-# NOINLINE decNestedP #-}
rtNestedH :: W.WithNested -> Either H.DecodeError W.WithNested
rtNestedH m = H.decodeMessage (H.encodeMessage m)
{-# NOINLINE rtNestedH #-}
rtNestedP :: PL.WithNested -> Either String PL.WithNested
rtNestedP m = PLC.decodeMessage (PLC.encodeMessage m)
{-# NOINLINE rtNestedP #-}
decRepH :: BS.ByteString -> Either H.DecodeError W.WithRepeated
decRepH = H.decodeMessage
{-# NOINLINE decRepH #-}
decRepP :: BS.ByteString -> Either String PL.WithRepeated
decRepP = PLC.decodeMessage
{-# NOINLINE decRepP #-}
-- wireform test values (PrefixedFields codegen; keep in sync with proto-lens fixtures)
smallHS :: W.Small
smallHS =
W.Small
{ W.smallId = 42
, W.smallName = "hello world"
, W.smallActive = True
, W.smallUnknownFields = []
}
mediumHS :: W.Medium
mediumHS =
W.Medium
{ W.mediumTitle = "benchmark title"
, W.mediumCount = 100
, W.mediumScore = 3.14159
, W.mediumPayload = "payload\x00\x01\x02"
, W.mediumEnabled = True
, W.mediumTimestamp = 1708000000
, W.mediumDescription = "a medium description"
, W.mediumRatio = 0.75
, W.mediumUnknownFields = []
}
nestedHS :: W.WithNested
nestedHS =
W.WithNested
{ W.withNestedId = 99
, W.withNestedInner =
Just
( W.Small
{ W.smallId = 1
, W.smallName = "inner"
, W.smallActive = True
, W.smallUnknownFields = []
}
)
, W.withNestedLabel = "outer label"
, W.withNestedUnknownFields = []
}
repeatedHS :: W.WithRepeated
repeatedHS =
W.WithRepeated
{ W.withRepeatedValues = VU.fromList [1 .. 50]
, W.withRepeatedTags = V.fromList (fmap (\i -> "tag_" <> T.pack (show i)) [1 .. 20 :: Int])
, W.withRepeatedItems =
V.fromList
[ W.Small
{ W.smallId = fromIntegral i
, W.smallName = "item" <> T.pack (show i)
, W.smallActive = even i
, W.smallUnknownFields = []
}
| i <- [1 .. 10 :: Int]
]
, W.withRepeatedUnknownFields = []
}
-- proto-lens test values (using the real generated field lenses)
smallPL :: PL.Small
smallPL =
(defMessage :: PL.Small)
& F.id .~ (42 :: Int64)
& F.name .~ ("hello world" :: Text)
& F.active .~ True
mediumPL :: PL.Medium
mediumPL =
(defMessage :: PL.Medium)
& F.title .~ ("benchmark title" :: Text)
& F.count .~ (100 :: Int32)
& F.score .~ (3.14159 :: Double)
& F.payload .~ ("payload\x00\x01\x02" :: BS.ByteString)
& F.enabled .~ True
& F.timestamp .~ (1708000000 :: Int64)
& F.description .~ ("a medium description" :: Text)
& F.ratio .~ (0.75 :: Float)
nestedPL :: PL.WithNested
nestedPL =
let inner =
(defMessage :: PL.Small)
& F.id .~ (1 :: Int64)
& F.name .~ ("inner" :: Text)
& F.active .~ True
in (defMessage :: PL.WithNested)
& F.id .~ (99 :: Int64)
& F.inner .~ inner
& F.label .~ ("outer label" :: Text)
repeatedPL :: PL.WithRepeated
repeatedPL =
let mkItem :: Int -> PL.Small
mkItem i =
(defMessage :: PL.Small)
& F.id .~ (fromIntegral i :: Int64)
& F.name .~ (("item" <> T.pack (show i)) :: Text)
& F.active .~ (even i :: Bool)
in (defMessage :: PL.WithRepeated)
& F.vec'values .~ VU.fromList ([1 .. 50] :: [Int32])
& F.vec'tags .~ V.fromList (fmap (\i -> ("tag_" <> T.pack (show i)) :: Text) [1 .. 20 :: Int])
& F.vec'items .~ V.fromList (fmap mkItem [1 .. 10])
-- Pre-encoded bytes (wireform canonical encoding for the fixtures above)
smallBytes, mediumBytes, nestedBytes, repeatedBytes :: BS.ByteString
smallBytes = encSmallH smallHS
mediumBytes = encMediumH mediumHS
nestedBytes = encNestedH nestedHS
repeatedBytes = encRepH repeatedHS