packages feed

antigen-0.4.0.0: bench/Main.hs

{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Main (main) where

import Control.DeepSeq (deepseq)
import Criterion.Main (Benchmarkable, bench, bgroup, defaultMain, nfIO)
import qualified Data.Text as T
import Test.AntiGen.Internal (
  AntiGen,
  ZapResult (..),
  evalPartial,
  evalToPartial,
  withAnnotation,
  zapAt,
  (|!),
 )
import Test.QuickCheck (Arbitrary (..), generate)
import Test.QuickCheck.GenT (MonadGen (..))

bindList :: Int -> AntiGen [Int]
bindList 1 = (: []) <$> liftGen arbitrary
bindList n
  | n <= 0 = pure []
  | otherwise = do
      rest <- bindList (n - 1)
      case rest of
        x : xs -> do
          y <- pure (succ x) |! pure (pred x)
          pure $ y : x : xs
        [] -> error "Got empty list"

-- Version with annotations on each decision point
bindListAnnotated :: Int -> AntiGen [Int]
bindListAnnotated 1 = (: []) <$> liftGen arbitrary
bindListAnnotated n
  | n <= 0 = pure []
  | otherwise = do
      rest <- bindListAnnotated (n - 1)
      case rest of
        x : xs -> do
          y <- withAnnotation (T.pack (show n)) $ pure (succ x) |! pure (pred x)
          pure $ y : x : xs
        [] -> error "Got empty list"

-- Only force the value
bindListZapValue :: Int -> Int -> Benchmarkable
bindListZapValue len i =
  nfIO . generate . variant (12345 :: Int) . fmap (evalPartial . zrValue) $
    zapAt (fromIntegral i) =<< evalToPartial (bindList len)

-- Force value, annotation, and zapped count
bindListZapAll :: Int -> Int -> Benchmarkable
bindListZapAll len i =
  nfIO . generate . variant (12345 :: Int) . fmap forceAll $
    zapAt (fromIntegral i) =<< evalToPartial (bindList len)
  where
    forceAll ZapResult {..} =
      zrAnnotation `deepseq` (evalPartial zrValue, zrZapped)

-- Annotated versions
annotatedZapValue :: Int -> Int -> Benchmarkable
annotatedZapValue len i =
  nfIO . generate . variant (12345 :: Int) . fmap (evalPartial . zrValue) $
    zapAt (fromIntegral i) =<< evalToPartial (bindListAnnotated len)

annotatedZapAll :: Int -> Int -> Benchmarkable
annotatedZapAll len i =
  nfIO . generate . variant (12345 :: Int) . fmap forceAll $
    zapAt (fromIntegral i) =<< evalToPartial (bindListAnnotated len)
  where
    forceAll ZapResult {..} =
      zrAnnotation `deepseq` (evalPartial zrValue, zrZapped)

main :: IO ()
main =
  defaultMain
    [ bgroup
        "value only"
        [ bench "10_000 zap at 0" $ bindListZapValue 10_000 0
        , bench "10_000 zap at 9_000" $ bindListZapValue 10_000 9_000
        , bench "1_000_000 zap at 0" $ bindListZapValue 1_000_000 0
        , bench "1_000_000 zap at 900_000" $ bindListZapValue 1_000_000 900_000
        ]
    , bgroup
        "force all"
        [ bench "10_000 zap at 0" $ bindListZapAll 10_000 0
        , bench "10_000 zap at 9_000" $ bindListZapAll 10_000 9_000
        , bench "1_000_000 zap at 0" $ bindListZapAll 1_000_000 0
        , bench "1_000_000 zap at 900_000" $ bindListZapAll 1_000_000 900_000
        ]
    , bgroup
        "annotated value only"
        [ bench "10_000 zap at 0" $ annotatedZapValue 10_000 0
        , bench "10_000 zap at 9_000" $ annotatedZapValue 10_000 9_000
        ]
    , bgroup
        "annotated force all"
        [ bench "10_000 zap at 0" $ annotatedZapAll 10_000 0
        , bench "10_000 zap at 9_000" $ annotatedZapAll 10_000 9_000
        ]
    ]