packages feed

ptr-peeker-0.2.0.1: src/bench/Main.hs

module Main (main) where

import Criterion.Main
import Data.Serialize qualified as Cereal
import Data.Store qualified as Store
import Data.Vector qualified as V
import Data.Vector.Unboxed qualified as Vu
import GHC.Stack (HasCallStack)
import PtrPeeker qualified as PtrPeeker
import Test.Tasty.HUnit qualified as Tasty
import Prelude

main :: IO ()
main = do
  putStrLn "Testing"
  groups <-
    sequence
      [ let input = Cereal.runPut $ do
              Cereal.putInt32le 1
              Cereal.putInt32le 2
              Cereal.putInt32le 3
            correctDecoding = (1, 2, 3)
            subjects =
              [ ( "ptr-peeker/fixed",
                  hush . PtrPeeker.runVariableOnByteString (PtrPeeker.fixed $ (,,) <$> PtrPeeker.leSignedInt4 <*> PtrPeeker.leSignedInt4 <*> PtrPeeker.leSignedInt4)
                ),
                ( "ptr-peeker/variable",
                  hush . PtrPeeker.runVariableOnByteString ((,,) <$> PtrPeeker.fixed PtrPeeker.leSignedInt4 <*> PtrPeeker.fixed PtrPeeker.leSignedInt4 <*> PtrPeeker.fixed PtrPeeker.leSignedInt4)
                ),
                ( "store",
                  hush . Store.decode @(Int32, Int32, Int32)
                ),
                ( "cereal",
                  hush . Cereal.runGet ((,,) <$> Cereal.getInt32le <*> Cereal.getInt32le <*> Cereal.getInt32le)
                )
              ]
         in initGroup "int32-le-triplet" input correctDecoding subjects,
        let input =
              Cereal.runPut
                $ Cereal.putInt32le 100
                <> replicateM_ 100 (Cereal.putInt32le (-1))
            correctDecoding =
              Vu.replicate 100 (-1)
            subjects =
              [ ( "ptr-peeker",
                  let decoder = do
                        size <- PtrPeeker.fixed PtrPeeker.leSignedInt4
                        PtrPeeker.fixed $ PtrPeeker.fixedArray @Vu.Vector PtrPeeker.leSignedInt4 $ fromIntegral size
                   in hush . PtrPeeker.runVariableOnByteString decoder
                ),
                ( "store",
                  let decoder = do
                        size <- Store.peek @Int32
                        Vu.replicateM (fromIntegral size) $ Store.peek @Int32
                   in hush . Store.decodeWith decoder
                ),
                ( "cereal",
                  let decoder = do
                        size <- Cereal.getInt32le
                        Vu.replicateM (fromIntegral size) $ Cereal.getInt32le
                   in hush . Cereal.runGet decoder
                )
              ]
         in initGroup "array-of-int4" input correctDecoding subjects,
        let input = Cereal.runPut $ do
              Cereal.putInt64le 100
              replicateM_ 100 $ do
                Cereal.putInt64le 3
                Cereal.putByteString "abc"
            correctDecoding = V.replicate 100 "abc"
            subjects =
              [ ( "ptr-peeker",
                  let decoder = do
                        size <- PtrPeeker.fixed PtrPeeker.leSignedInt8
                        PtrPeeker.variableArray @V.Vector byteStringDecoder $ fromIntegral size
                      byteStringDecoder = do
                        size <- PtrPeeker.fixed PtrPeeker.leSignedInt8
                        PtrPeeker.fixed $ PtrPeeker.byteArrayAsByteString $ fromIntegral size
                   in hush . PtrPeeker.runVariableOnByteString decoder
                ),
                ( "store",
                  hush . Store.decode
                ),
                ( "cereal",
                  let decoder = do
                        size <- Cereal.getInt64le
                        V.replicateM (fromIntegral size) $ do
                          size <- Cereal.getInt64le
                          Cereal.getByteString $ fromIntegral size
                   in hush . Cereal.runGet decoder
                )
              ]
         in initGroup "array-of-byte-arrays" input correctDecoding subjects
      ]

  putStrLn "Benchmarking"
  defaultMain groups

-- | Test functions and create a benchmark group out of them.
initGroup :: (HasCallStack) => (Eq a, Show a, NFData a) => String -> ByteString -> a -> [(String, ByteString -> Maybe a)] -> IO Benchmark
initGroup name input correctDecoding subjects = do
  fmap (bgroup name) . forM subjects $ \(name, f) -> do
    Tasty.assertEqual name (Just correctDecoding) (f input)
    return $ bench name $ nf f input

-- | Suppress the 'Left' value of an 'Either'
hush :: Either a b -> Maybe b
hush = either (const Nothing) Just