packages feed

ac-library-hs-1.5.2.1: benchmarks/Bench/Vector/ConcatMapM.hs

module Bench.Vector.ConcatMapM (benches) where

import BenchLib.Vector.ConcatMapM qualified as ConcatMapM
import Control.Monad.Primitive (PrimMonad)
import Control.Monad.ST (runST)
import Control.Monad.State.Class (MonadState, modify')
import Control.Monad.Trans.State.Strict (StateT (..), evalState, evalStateT)
import Criterion
import Data.Vector.Unboxed qualified as VU
import Data.Vector.Unboxed.Mutable qualified as VUM
import System.Random

benches :: Benchmark
benches =
  bgroup
    "concatMapM"
    [ -- FIXME: too fast, something is wrong.
      bench "list" $ nf (concatMap fList) (VU.toList vec),
      bench "prim    IO" $ nfIO (prim1 vec),
      bench "monad 1 IO" $ nfIO (io1 vec),
      bench "monad 2 IO" $ nfIO (io2 vec),
      bench "prim    ST" $ nf (\xs -> runST (prim1 xs)) vec,
      bench "monad 1 ST" $ nf st1 vec,
      bench "monad 2 ST" $ nf st2 vec,
      bench "prim    StateT" $ nf (\vec -> runST $ (`evalStateT` (0 :: Int)) (ConcatMapM.primConcatMapM1 g vec)) vec,
      bench "monad 1 State" $ nf ((`evalState` (0 :: Int)) . ConcatMapM.concatMapM1 g) vec,
      bench "monad 2 State" $ nf ((`evalState` (0 :: Int)) . ConcatMapM.concatMapM2 g) vec,
      bench "prime   StateT + IO" $ nfIO (evalStateT (primStateT1 vec) (0 :: Int)),
      bench "monad 1 StateT + IO" $ nfIO (evalStateT (stateT1 vec) (0 :: Int)),
      bench "monad 2 StateT + IO" $ nfIO (evalStateT (stateT2 vec) (0 :: Int))
    ]
  where
    n = 10 ^ 3 :: Int
    vec :: VU.Vector Int
    vec = VU.unfoldrExactN n (uniformR (0, n - 1)) (mkStdGen (1 + 123456789))

    f :: Int -> VU.Vector Int
    f x = VU.fromList [x, x, x, x, x]

    fList :: Int -> [Int]
    fList x = [x, x, x, x, x]

    g :: (MonadState Int m) => Int -> m (VU.Vector Int)
    g x = do
      modify' (+ 1)
      pure $ f x

    prim1 :: (PrimMonad m) => VU.Vector Int -> m (VU.Vector Int)
    prim1 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.primConcatMapM1
        ( \x -> do
            VUM.modify ref (+ 1) 0
            pure $ f x
        )
        vec

    io1 :: VU.Vector Int -> IO (VU.Vector Int)
    io1 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM1
        ( \x -> do
            VUM.modify ref (+ 1) 0
            pure $ f x
        )
        vec

    io2 :: VU.Vector Int -> IO (VU.Vector Int)
    io2 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM2
        ( \x -> do
            VUM.modify ref (+ 1) 0
            pure $ f x
        )
        vec

    st1 :: VU.Vector Int -> VU.Vector Int
    st1 vec = runST $ do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM1
        ( \x -> do
            VUM.modify ref (+ 1) 0
            pure $ f x
        )
        vec

    st2 :: VU.Vector Int -> VU.Vector Int
    st2 vec = runST $ do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM2
        ( \x -> do
            VUM.modify ref (+ 1) 0
            pure $ f x
        )
        vec

    stateT1 :: VU.Vector Int -> StateT Int IO (VU.Vector Int)
    stateT1 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM1
        ( \x -> do
            VUM.modify ref (+ 1) 0
            modify' (+ 1)
            pure $ f x
        )
        vec

    stateT2 :: VU.Vector Int -> StateT Int IO (VU.Vector Int)
    stateT2 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.concatMapM2
        ( \x -> do
            VUM.modify ref (+ 1) 0
            modify' (+ 1)
            pure $ f x
        )
        vec

    primStateT1 :: VU.Vector Int -> StateT Int IO (VU.Vector Int)
    primStateT1 vec = do
      ref <- VUM.replicate 1 (0 :: Int)
      ConcatMapM.primConcatMapM1
        ( \x -> do
            VUM.modify ref (+ 1) 0
            modify' (+ 1)
            pure $ f x
        )
        vec