on master help sign in
Add benchmarks for SmallArray.
f44543bPranay Sashank
benchmark/Streamly/Benchmark/Data/Array.hs+1−1
@@ -54,7 +54,7 @@ mkString = "[1" ++ concat (replicate Ops.value ",1") ++ "]"
54main :: IO ()
54main :: IO ()
55main =
55main =
56 defaultMain
56 defaultMain
57− [ bgroup "array"
57+ [ bgroup "Data.Array"
58 [ bgroup "generation"
58 [ bgroup "generation"
59 [ benchIOSrc "writeN . intFromTo" Ops.sourceIntFromTo
59 [ benchIOSrc "writeN . intFromTo" Ops.sourceIntFromTo
60 , benchIOSrc "write . intFromTo" Ops.sourceIntFromToFromStream
60 , benchIOSrc "write . intFromTo" Ops.sourceIntFromToFromStream
benchmark/Streamly/Benchmark/Data/SmallArray.hsnew file+95
@@ -0,0 +1,95 @@
1+-- |
2+-- Module : Main
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+-- Stability : experimental
8+-- Portability : GHC
9+
10+{-# LANGUAGE CPP #-}
11+
12+module Main (main) where
13+
14+import Control.DeepSeq (NFData(..), deepseq)
15+import System.Random (randomRIO)
16+
17+import qualified Streamly.Benchmark.Data.SmallArrayOps as Ops
18+import qualified Streamly.Data.SmallArray as A
19+import qualified Streamly.Prelude as S
20+
21+import Gauge
22+
23+-------------------------------------------------------------------------------
24+--
25+-------------------------------------------------------------------------------
26+
27+{-# INLINE benchIO #-}
28+benchIO :: NFData b => String -> (Int -> IO a) -> (a -> b) -> Benchmark
29+benchIO name src f = bench name $ nfIO $
30+ randomRIO (1,1) >>= src >>= return . f
31+
32+-- Drain a source that generates an array in the IO monad
33+{-# INLINE benchIOSrc #-}
34+benchIOSrc :: (NFData a)
35+ => String -> (Int -> IO (Ops.Stream a)) -> Benchmark
36+benchIOSrc name src = benchIO name src id
37+
38+{-# INLINE benchPureSink #-}
39+benchPureSink :: NFData b => String -> (Ops.Stream Int -> b) -> Benchmark
40+benchPureSink name f = benchIO name Ops.sourceIntFromTo f
41+
42+{-# INLINE benchIO' #-}
43+benchIO' :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
44+benchIO' name src f = bench name $ nfIO $
45+ randomRIO (1,1) >>= src >>= f
46+
47+{-# INLINE benchIOSink #-}
48+benchIOSink :: NFData b => String -> (Ops.Stream Int -> IO b) -> Benchmark
49+benchIOSink name f = benchIO' name Ops.sourceIntFromTo f
50+
51+mkString :: String
52+mkString =
53+ "fromListN " ++
54+ show (Ops.value + 1) ++ " [1" ++ concat (replicate Ops.value ",1") ++ "]"
55+
56+main :: IO ()
57+main =
58+ defaultMain
59+ [ bgroup "SmallArray"
60+ [ bgroup "generation"
61+ [ benchIOSrc "writeN . intFromTo" Ops.sourceIntFromTo
62+ , benchIOSrc "fromList . intFromTo" Ops.sourceIntFromToFromList
63+ , benchIOSrc "writeN . unfoldr" Ops.sourceUnfoldr
64+ , benchIOSrc "writeN . fromList" Ops.sourceFromList
65+ , mkString `deepseq` (bench "read" $ nf Ops.readInstance mkString)
66+ , benchPureSink "show" Ops.showInstance
67+ ]
68+ , bgroup "elimination"
69+ [ benchPureSink "id" id
70+ , benchPureSink "==" Ops.eqInstance
71+ , benchPureSink "/=" Ops.eqInstanceNotEq
72+ , benchPureSink "<" Ops.ordInstance
73+ , benchPureSink "min" Ops.ordInstanceMin
74+ -- length is used to check for foldr/build fusion
75+ -- , benchPureSink "length . IsList.toList" (length . GHC.toList)
76+ , benchIOSink "foldl'" Ops.pureFoldl'
77+ , benchIOSink "read" (S.drain . S.unfold A.read)
78+ , benchIOSink "toStreamRev" (S.drain . A.toStreamRev)
79+#ifdef DEVBUILD
80+ , benchPureSink "foldable/foldl'" Ops.foldableFoldl'
81+ , benchPureSink "foldable/sum" Ops.foldableSum
82+#endif
83+ ]
84+ , bgroup "transformation"
85+ [ benchIOSink "scanl'" (Ops.scanl' 1)
86+ , benchIOSink "scanl1'" (Ops.scanl1' 1)
87+ , benchIOSink "map" (Ops.map 1)
88+ ]
89+ , bgroup "transformationX4"
90+ [ benchIOSink "scanl'" (Ops.scanl' 4)
91+ , benchIOSink "scanl1'" (Ops.scanl1' 4)
92+ , benchIOSink "map" (Ops.map 4)
93+ ]
94+ ]
95+ ]
benchmark/Streamly/Benchmark/Data/SmallArrayOps.hsnew file+136
@@ -0,0 +1,136 @@
1+-- |
2+-- Module : Streamly.Benchmark.Data.SmallArrayOps
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+-- Stability : experimental
8+-- Portability : GHC
9+
10+{-# LANGUAGE CPP #-}
11+{-# LANGUAGE DeriveAnyClass #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE FlexibleContexts #-}
14+{-# LANGUAGE ScopedTypeVariables #-}
15+
16+module Streamly.Benchmark.Data.SmallArrayOps where
17+
18+import Control.Monad.IO.Class (MonadIO)
19+import Prelude (Int, Bool, (+), ($), (==), (>), (.), Maybe(..), undefined)
20+import qualified Prelude as P
21+#ifdef DEVBUILD
22+import qualified Data.Foldable as F
23+#endif
24+
25+import qualified Streamly as S hiding (foldMapWith, runStream)
26+import qualified Streamly.Data.SmallArray as A
27+import qualified Streamly.Prelude as S
28+
29+value :: Int
30+value = 128
31+
32+-------------------------------------------------------------------------------
33+-- Benchmark ops
34+-------------------------------------------------------------------------------
35+
36+-------------------------------------------------------------------------------
37+-- Stream generation and elimination
38+-------------------------------------------------------------------------------
39+
40+type Stream = A.SmallArray
41+
42+{-# INLINE sourceUnfoldr #-}
43+sourceUnfoldr :: MonadIO m => Int -> m (Stream Int)
44+sourceUnfoldr n = S.fold (A.writeN value) $ S.unfoldr step n
45+ where
46+ step cnt =
47+ if cnt > n + value
48+ then Nothing
49+ else (Just (cnt, cnt + 1))
50+
51+{-# INLINE sourceIntFromTo #-}
52+sourceIntFromTo :: MonadIO m => Int -> m (Stream Int)
53+sourceIntFromTo n = S.fold (A.writeN value) $ S.enumerateFromTo n (n + value)
54+
55+{-# INLINE sourceIntFromToFromList #-}
56+sourceIntFromToFromList :: MonadIO m => Int -> m (Stream Int)
57+sourceIntFromToFromList n = P.return $ (A.fromListN value) $ [n..n + value]
58+
59+{-# INLINE sourceFromList #-}
60+sourceFromList :: MonadIO m => Int -> m (Stream Int)
61+sourceFromList n = S.fold (A.writeN value) $ S.fromList [n..n+value]
62+
63+-------------------------------------------------------------------------------
64+-- Transformation
65+-------------------------------------------------------------------------------
66+
67+{-# INLINE composeN #-}
68+composeN :: P.Monad m
69+ => Int -> (Stream Int -> m (Stream Int)) -> Stream Int -> m (Stream Int)
70+composeN n f x =
71+ case n of
72+ 1 -> f x
73+ 2 -> f x P.>>= f
74+ 3 -> f x P.>>= f P.>>= f
75+ 4 -> f x P.>>= f P.>>= f P.>>= f
76+ _ -> undefined
77+
78+{-# INLINE scanl' #-}
79+{-# INLINE scanl1' #-}
80+{-# INLINE map #-}
81+
82+scanl', scanl1', map
83+ :: MonadIO m => Int -> Stream Int -> m (Stream Int)
84+
85+{-# INLINE onArray #-}
86+onArray
87+ :: MonadIO m => (S.SerialT m Int -> S.SerialT m Int)
88+ -> Stream Int
89+ -> m (Stream Int)
90+onArray f arr = S.fold (A.writeN value) $ f $ (S.unfold A.read arr)
91+
92+scanl' n = composeN n $ onArray $ S.scanl' (+) 0
93+scanl1' n = composeN n $ onArray $ S.scanl1' (+)
94+map n = composeN n $ onArray $ S.map (+1)
95+
96+{-# INLINE eqInstance #-}
97+eqInstance :: Stream Int -> Bool
98+eqInstance src = src == src
99+
100+{-# INLINE eqInstanceNotEq #-}
101+eqInstanceNotEq :: Stream Int -> Bool
102+eqInstanceNotEq src = src P./= src
103+
104+{-# INLINE ordInstance #-}
105+ordInstance :: Stream Int -> Bool
106+ordInstance src = src P.< src
107+
108+{-# INLINE ordInstanceMin #-}
109+ordInstanceMin :: Stream Int -> Stream Int
110+ordInstanceMin src = P.min src src
111+
112+{-# INLINE showInstance #-}
113+showInstance :: Stream Int -> P.String
114+showInstance src = P.show src
115+
116+{-# INLINE readInstance #-}
117+readInstance :: P.String -> Stream Int
118+readInstance str =
119+ let r = P.reads str
120+ in case r of
121+ [(x,"")] -> x
122+ _ -> P.error "readInstance: no parse"
123+
124+{-# INLINE pureFoldl' #-}
125+pureFoldl' :: MonadIO m => Stream Int -> m Int
126+pureFoldl' = S.foldl' (+) 0 . S.unfold A.read
127+
128+#ifdef DEVBUILD
129+{-# INLINE foldableFoldl' #-}
130+foldableFoldl' :: Stream Int -> Int
131+foldableFoldl' = F.foldl' (+) 0
132+
133+{-# INLINE foldableSum #-}
134+foldableSum :: Stream Int -> Int
135+foldableSum = P.sum
136+#endif
streamly.cabal+16
@@ -673,6 +673,22 @@ benchmark unpinned-array
673 build-depends:
673 build-depends:
674 transformers >= 0.4 && < 0.6
674 transformers >= 0.4 && < 0.6
675
675
676+benchmark small-array
677+ import: bench-options
678+ type: exitcode-stdio-1.0
679+ hs-source-dirs: benchmark
680+ main-is: Streamly/Benchmark/Data/SmallArray.hs
681+ other-modules: Streamly.Benchmark.Data.SmallArrayOps
682+ build-depends:
683+ streamly
684+ , base >= 4.8 && < 5
685+ , deepseq >= 1.4.1 && < 1.5
686+ , random >= 1.0 && < 2.0
687+ , gauge >= 0.2.4 && < 0.3
688+ if impl(ghc < 8.0)
689+ build-depends:
690+ transformers >= 0.4 && < 0.6
691+
676benchmark array
692benchmark array
677 import: bench-options
693 import: bench-options
678 type: exitcode-stdio-1.0
694 type: exitcode-stdio-1.0