packages feed

loop-0.2.0: bench/FoldlAndIORefAreSlow.hs

{-# LANGUAGE BangPatterns #-}

module Main (main) where

import           Control.Monad.State.Strict
import           Criterion.Main
import           Data.List (foldl')
import           Data.IORef
import qualified Data.Vector as V
import           Data.Word


main :: IO ()
main = do

  -- Warning: -fllvm can compile away the `unsafe` loops to complete no-ops.

  defaultMain
    [ bgroup "sum32"       [ bench "sumW32loopIORef"     $ nfIO (sumW32loopIORef                          1000000)
                           , bench "sumW32StrictState"   $ whnf (\n -> execState (sumW32StrictState n) 0) 1000000
                           , bench "foldlW32"            $ whnf (\n -> foldl' (+) 0 [0..n::Word32])       1000000
                           , bench "V.foldlW32"          $ whnf (\n -> V.foldl' (+) 0 (V.enumFromTo 0 (n::Word32))) 1000000
                           , bench "sumIntloopIORef"     $ nfIO (sumIntloopIORef                          1000000)
                           , bench "sumIntStrictState"   $ whnf (\n -> execState (sumIntStrictState n) 0) 1000000
                           , bench "foldlInt"            $ whnf (\n -> foldl' (+) 0 [0..n::Int])          1000000
                           , bench "V.foldlInt"          $ whnf (\n -> V.foldl' (+) 0 (V.enumFromTo 0 (n::Int)))    1000000
                           ]
    ]



forLoop :: (Monad m) => a -> (a -> Bool) -> (a -> a) -> (a -> m ()) -> m ()
forLoop start cond inc f = go start
  where
    go !x | cond x    = f x >> go (inc x)
          | otherwise = return ()

{-# INLINE forLoop #-}


sumW32loopIORef :: Word32 -> IO Word32
sumW32loopIORef n = do
  ref <- newIORef 0
  forLoop (0 :: Word32) (< n) (+1) $ \i -> do
    modifyIORef' ref (+i)
  readIORef ref


sumW32StrictState :: Word32 -> State Word32 ()
sumW32StrictState n = do
  forLoop (0 :: Word32) (< n) (+1) $ \i -> do
    x <- get
    put $! x + i


sumIntloopIORef :: Int -> IO Int
sumIntloopIORef n = do
  ref <- newIORef 0
  forLoop (0 :: Int) (< n) (+1) $ \i -> do
    modifyIORef' ref (+i)
  readIORef ref


sumIntStrictState :: Int -> State Int ()
sumIntStrictState n = do
  forLoop (0 :: Int) (< n) (+1) $ \i -> do
    x <- get
    put $! x + i