1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
{-# LANGUAGE RankNTypes #-}
module Main (main) where
import Criterion.Main
import Common (commonMain)
import Control.Monad.Identity (Identity, runIdentity)
import Pipes
import qualified Pipes.Prelude as P
import Prelude hiding (enumFromTo)
defaultMax :: Int
defaultMax = 10000
main :: IO ()
main = commonMain defaultMax preludeBenchmarks
enumFromTo :: (Int -> a) -> Int -> Int -> Producer a Identity ()
enumFromTo f n1 n2 = loop n1
where
loop n =
if n <= n2
then do
yield $! f n
loop $! n + 1
else return ()
{-# INLINABLE enumFromTo #-}
drain :: Producer b Identity r -> r
drain p = runIdentity $ runEffect $ for p discard
msum :: (Monad m) => Producer Int m () -> m Int
msum = P.foldM (\a b -> return $ a + b) (return 0) return
scanMSum :: (Monad m) => Pipe Int Int m r
scanMSum = P.scanM (\x y -> return (x + y)) (return 0) return
-- Using runIdentity seems to reduce outlier counts.
preludeBenchmarks :: Int -> [Benchmark]
preludeBenchmarks vmax =
let applyBench b = b benchEnum_p
benchEnum_p = enumFromTo id 1 vmax
in
[
bgroup "Folds" $ map applyBench
[
bench "all" . whnf (runIdentity . P.all (<= vmax))
, bench "any" . whnf (runIdentity . P.any (> vmax))
, bench "find" . whnf (runIdentity . P.find (== vmax))
, bench "findIndex" . whnf (runIdentity . P.findIndex (== vmax))
, bench "fold" . whnf (runIdentity . P.fold (+) 0 id)
, bench "foldM" . whnf (runIdentity . msum)
, bench "head" . nf (runIdentity . P.head)
, bench "index" . nf (runIdentity . P.index (vmax-1))
, bench "last" . nf (runIdentity . P.last)
, bench "length" . whnf (runIdentity . P.length)
, bench "null" . whnf (runIdentity . P.null)
, bench "toList" . nf P.toList
]
, bgroup "Pipes" $ map applyBench
[
bench "chain" . whnf (drain . (>-> P.chain (\_ -> return ())))
, bench "drop" . whnf (drain . (>-> P.drop vmax))
, bench "dropWhile" . whnf (drain . (>-> P.dropWhile (<= vmax)))
, bench "filter" . whnf (drain . (>-> P.filter even))
, bench "findIndices" . whnf (drain . (>-> P.findIndices (<= vmax)))
, bench "map" . whnf (drain . (>-> P.map id))
, bench "mapM" . whnf (drain . (>-> P.mapM return))
, bench "take" . whnf (drain . (>-> P.take vmax))
, bench "takeWhile" . whnf (drain . (>-> P.takeWhile (<= vmax)))
, bench "scan" . whnf (drain . (>-> P.scan (+) 0 id))
, bench "scanM" . whnf (drain . (>-> scanMSum))
] ++ [
bench "concat" $ whnf (drain . (>-> P.concat)) $ enumFromTo Just 1 vmax
]
, bgroup "Zips" $ map applyBench
[
bench "zip" . whnf (drain . P.zip benchEnum_p)
, bench "zipWith" . whnf (drain . P.zipWith (+) benchEnum_p)
]
, bgroup "enumFromTo.vs.each"
[
bench "enumFromTo" $ whnf (drain . enumFromTo id 1) vmax
, bench "each" $ whnf (drain . each) [1..vmax]
]
]
|