on master help sign in
Move benchmarks of SmallArray out of common array benchmark mess
commitfd55f07b8cd3b15e7bb7cb23aa1d16b7259e46b6 authoradithyaov <adithya@composewell.com> dateSun 28 Nov 2021, 15:10 (5 years ago) parentef0a299
7 files changed+304−28
benchmark/Streamly/Benchmark/Data/Array.hs+1−8 benchmark/Streamly/Benchmark/Data/Array/Common.hs+188 benchmark/Streamly/Benchmark/Data/Array/CommonImports.hs+15 benchmark/Streamly/Benchmark/Data/Array/SmallArray.hs+94 benchmark/Streamly/Benchmark/Data/ArrayOps.hs+1−16 benchmark/streamly-benchmarks.cabal+2−4 streamly.cabal+3
benchmark/Streamly/Benchmark/Data/Array.hs+1−8
@@ -173,9 +173,7 @@ o_1_space_transformationX4 value =
173173 ]
174174
175175moduleName :: String
176−#ifdef DATA_SMALLARRAY
177−moduleName = "Data.SmallArray"
178−#elif defined(MEMORY_ARRAY)
176+#if defined(MEMORY_ARRAY)
179177moduleName = "Data.Array.Foreign"
180178#elif defined(DATA_ARRAY_PRIM)
181179moduleName = "Data.Array.Prim"
@@ -185,13 +183,8 @@ moduleName = "Data.Array.Prim.Pinned"
185183moduleName = "Data.Array"
186184#endif
187185
188−#ifdef DATA_SMALLARRAY
189−defStreamSize :: Int
190−defStreamSize = 128
191−#else
192186defStreamSize :: Int
193187defStreamSize = defaultStreamSize
194−#endif
195188
196189main :: IO ()
197190main = runWithCLIOpts defStreamSize allBenchmarks
benchmark/Streamly/Benchmark/Data/Array/Common.hsnew file+188
@@ -0,0 +1,188 @@
1+
2+
3+-------------------------------------------------------------------------------
4+-- Benchmark helpers
5+-------------------------------------------------------------------------------
6+
7+{-# INLINE benchIO #-}
8+benchIO :: NFData b => String -> (Int -> IO a) -> (a -> b) -> Benchmark
9+benchIO name src f = bench name $ nfIO $
10+ randomRIO (1,1) >>= src >>= return . f
11+
12+{-# INLINE benchPureSink #-}
13+benchPureSink :: NFData b => Int -> String -> (Stream Int -> b) -> Benchmark
14+benchPureSink value name f = benchIO name (sourceIntFromTo value) f
15+
16+{-# INLINE benchIO' #-}
17+benchIO' :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
18+benchIO' name src f = bench name $ nfIO $
19+ randomRIO (1,1) >>= src >>= f
20+
21+{-# INLINE benchIOSink #-}
22+benchIOSink :: NFData b => Int -> String -> (Stream Int -> IO b) -> Benchmark
23+benchIOSink value name f = benchIO' name (sourceIntFromTo value) f
24+
25+-------------------------------------------------------------------------------
26+-- Bench Ops
27+-------------------------------------------------------------------------------
28+
29+{-# INLINE sourceUnfoldr #-}
30+sourceUnfoldr :: MonadIO m => Int -> Int -> m (Stream Int)
31+sourceUnfoldr value n = S.fold (A.writeN value) $ S.unfoldr step n
32+ where
33+ step cnt =
34+ if cnt > n + value
35+ then Nothing
36+ else (Just (cnt, cnt + 1))
37+
38+{-# INLINE sourceIntFromTo #-}
39+sourceIntFromTo :: MonadIO m => Int -> Int -> m (Stream Int)
40+sourceIntFromTo value n = S.fold (A.writeN value) $ S.enumerateFromTo n (n + value)
41+
42+{-# INLINE sourceFromList #-}
43+sourceFromList :: MonadIO m => Int -> Int -> m (Stream Int)
44+sourceFromList value n = S.fold (A.writeN value) $ S.fromList [n..n+value]
45+
46+-------------------------------------------------------------------------------
47+-- Transformation
48+-------------------------------------------------------------------------------
49+
50+{-# INLINE composeN #-}
51+composeN :: P.Monad m
52+ => Int -> (Stream Int -> m (Stream Int)) -> Stream Int -> m (Stream Int)
53+composeN n f x =
54+ case n of
55+ 1 -> f x
56+ 2 -> f x P.>>= f
57+ 3 -> f x P.>>= f P.>>= f
58+ 4 -> f x P.>>= f P.>>= f P.>>= f
59+ _ -> undefined
60+
61+{-# INLINE scanl' #-}
62+{-# INLINE scanl1' #-}
63+{-# INLINE map #-}
64+
65+scanl' , scanl1', map
66+ :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
67+
68+
69+{-# INLINE onArray #-}
70+onArray
71+ :: MonadIO m => Int -> (S.SerialT m Int -> S.SerialT m Int)
72+ -> Stream Int
73+ -> m (Stream Int)
74+onArray value f arr = S.fold (A.writeN value) $ f $ (S.unfold A.read arr)
75+
76+scanl' value n = composeN n $ onArray value $ S.scanl' (+) 0
77+scanl1' value n = composeN n $ onArray value $ S.scanl1' (+)
78+map value n = composeN n $ onArray value $ S.map (+1)
79+-- map n = composeN n $ A.map (+1)
80+
81+{-# INLINE eqInstance #-}
82+eqInstance :: Stream Int -> Bool
83+eqInstance src = src == src
84+
85+{-# INLINE eqInstanceNotEq #-}
86+eqInstanceNotEq :: Stream Int -> Bool
87+eqInstanceNotEq src = src P./= src
88+
89+{-# INLINE ordInstance #-}
90+ordInstance :: Stream Int -> Bool
91+ordInstance src = src P.< src
92+
93+{-# INLINE ordInstanceMin #-}
94+ordInstanceMin :: Stream Int -> Stream Int
95+ordInstanceMin src = P.min src src
96+
97+{-# INLINE showInstance #-}
98+showInstance :: Stream Int -> P.String
99+showInstance src = P.show src
100+
101+{-# INLINE pureFoldl' #-}
102+pureFoldl' :: MonadIO m => Stream Int -> m Int
103+pureFoldl' = S.foldl' (+) 0 . S.unfold A.read
104+
105+
106+-------------------------------------------------------------------------------
107+-- Elimination
108+-------------------------------------------------------------------------------
109+
110+{-# INLINE unfoldReadDrain #-}
111+unfoldReadDrain :: MonadIO m => Stream Int -> m ()
112+unfoldReadDrain = S.drain . S.unfold A.read
113+
114+{-# INLINE toStreamRevDrain #-}
115+toStreamRevDrain :: MonadIO m => Stream Int -> m ()
116+toStreamRevDrain = S.drain . A.toStreamRev
117+
118+-------------------------------------------------------------------------------
119+-- Bench groups
120+-------------------------------------------------------------------------------
121+
122+common_o_1_space_generation :: Int -> [Benchmark]
123+common_o_1_space_generation value =
124+ [ bgroup
125+ "generation"
126+ [ benchIOSrc "writeN . intFromTo" (sourceIntFromTo value)
127+ , benchIOSrc
128+ "fromList . intFromTo"
129+ (sourceIntFromToFromList value)
130+ , benchIOSrc "writeN . unfoldr" (sourceUnfoldr value)
131+ , benchIOSrc "writeN . fromList" (sourceFromList value)
132+ , benchPureSink value "show" showInstance
133+ ]
134+ ]
135+
136+common_o_1_space_elimination :: Int -> [Benchmark]
137+common_o_1_space_elimination value =
138+ [ bgroup "elimination"
139+ [ benchPureSink value "id" id
140+ , benchPureSink value "==" eqInstance
141+ , benchPureSink value "/=" eqInstanceNotEq
142+ , benchPureSink value "<" ordInstance
143+ , benchPureSink value "min" ordInstanceMin
144+ , benchIOSink value "foldl'" pureFoldl'
145+ , benchIOSink value "read" unfoldReadDrain
146+ , benchIOSink value "toStreamRev" toStreamRevDrain
147+ ]
148+ ]
149+
150+common_o_n_heap_serial :: Int -> [Benchmark]
151+common_o_n_heap_serial value =
152+ [ bgroup "elimination"
153+ [
154+ -- Converting the stream to an array
155+ benchFold "writeN" (S.fold (A.writeN value))
156+ (P.sourceUnfoldrM value)
157+ ]
158+ ]
159+
160+common_o_1_space_transformation :: Int -> [Benchmark]
161+common_o_1_space_transformation value =
162+ [ bgroup "transformation"
163+ [ benchIOSink value "scanl'" (scanl' value 1)
164+ , benchIOSink value "scanl1'" (scanl1' value 1)
165+ , benchIOSink value "map" (map value 1)
166+ ]
167+ ]
168+
169+common_o_1_space_transformationX4 :: Int -> [Benchmark]
170+common_o_1_space_transformationX4 value =
171+ [ bgroup "transformationX4"
172+ [ benchIOSink value "scanl'" (scanl' value 4)
173+ , benchIOSink value "scanl1'" (scanl1' value 4)
174+ , benchIOSink value "map" (map value 4)
175+ ]
176+ ]
177+
178+commonBenchmarks :: Int -> [Benchmark]
179+commonBenchmarks size =
180+ [ bgroup (o_1_space_prefix moduleName) $ concat
181+ [ common_o_1_space_generation size
182+ , common_o_1_space_elimination size
183+ , common_o_1_space_transformation size
184+ , common_o_1_space_transformationX4 size
185+ ]
186+ , bgroup (o_n_space_prefix moduleName) $
187+ common_o_n_heap_serial size
188+ ]
benchmark/Streamly/Benchmark/Data/Array/CommonImports.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+
3+import Control.DeepSeq (NFData(..))
4+import System.Random (randomRIO)
5+
6+import qualified Streamly.Prelude as S
7+
8+import Gauge
9+import Streamly.Benchmark.Common hiding (benchPureSrc)
10+import qualified Streamly.Benchmark.Prelude as P
11+
12+
13+import Control.Monad.IO.Class (MonadIO)
14+
15+import Prelude as P hiding (map)
benchmark/Streamly/Benchmark/Data/Array/SmallArray.hsnew file+94
@@ -0,0 +1,94 @@
1+{-# LANGUAGE CPP #-}
2+
3+#include "Streamly/Benchmark/Data/Array/CommonImports.hs"
4+
5+import Control.DeepSeq (deepseq)
6+
7+import qualified Streamly.Internal.Data.SmallArray as A
8+type Stream = A.SmallArray
9+
10+#include "Streamly/Benchmark/Data/Array/Common.hs"
11+
12+-------------------------------------------------------------------------------
13+-- Benchmark helpers
14+-------------------------------------------------------------------------------
15+
16+-- Drain a source that generates an array in the IO monad
17+{-# INLINE benchIOSrc #-}
18+benchIOSrc :: NFData a => String -> (Int -> IO (Stream a)) -> Benchmark
19+benchIOSrc name src = benchIO name src id
20+
21+-------------------------------------------------------------------------------
22+-- Bench Ops
23+-------------------------------------------------------------------------------
24+
25+{-# INLINE sourceIntFromToFromList #-}
26+sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
27+sourceIntFromToFromList value n = P.return $ A.fromListN value $ [n..n + value]
28+
29+{-# INLINE readInstance #-}
30+readInstance :: P.String -> Stream Int
31+readInstance str =
32+ let r = P.reads str
33+ in case r of
34+ [(x,"")] -> x
35+ _ -> P.error "readInstance: no parse"
36+
37+#ifdef DEVBUILD
38+{-
39+{-# INLINE foldableFoldl' #-}
40+foldableFoldl' :: Stream Int -> Int
41+foldableFoldl' = F.foldl' (+) 0
42+
43+{-# INLINE foldableSum #-}
44+foldableSum :: Stream Int -> Int
45+foldableSum = P.sum
46+-}
47+#endif
48+
49+-------------------------------------------------------------------------------
50+-- Bench groups
51+-------------------------------------------------------------------------------
52+
53+o_1_space_generation :: Int -> [Benchmark]
54+o_1_space_generation value =
55+ [ bgroup
56+ "generation"
57+ [ let testStr =
58+ "fromListN " ++
59+ show (value + 1) ++
60+ "[1" ++ concat (replicate value ",1") ++ "]"
61+ in testStr `deepseq` (bench "read" $ nf readInstance testStr)
62+ ]
63+ ]
64+
65+{-
66+o_1_space_elimination :: Int -> [Benchmark]
67+o_1_space_elimination value =
68+ [ bgroup "elimination"
69+ [
70+#ifdef DEVBUILD
71+{-
72+ benchPureSink value "foldable/foldl'" foldableFoldl'
73+ , benchPureSink value "foldable/sum" foldableSum
74+-}
75+#endif
76+ ]
77+ ]
78+-}
79+
80+moduleName :: String
81+moduleName = "Data.SmallArray"
82+
83+defStreamSize :: Int
84+defStreamSize = 128
85+
86+main :: IO ()
87+main = runWithCLIOpts defStreamSize allBenchmarks
88+
89+ where
90+
91+ allBenchmarks size =
92+ [ bgroup (o_1_space_prefix moduleName) $
93+ o_1_space_generation size
94+ ] ++ commonBenchmarks size
benchmark/Streamly/Benchmark/Data/ArrayOps.hs+1−16
@@ -14,7 +14,6 @@
1414-- DATA_ARRAY
1515-- DATA_ARRAY_PRIM
1616-- DATA_ARRAY_PRIM_PINNED
17−-- DATA_SMALLARRAY
1817
1918module Streamly.Benchmark.Data.ArrayOps where
2019
@@ -32,10 +31,7 @@ import qualified Data.Foldable as F
3231#endif
3332#endif
3433
35−#ifdef DATA_SMALLARRAY
36−import qualified Streamly.Internal.Data.SmallArray as A
37−type Stream = A.SmallArray
38−#elif defined(MEMORY_ARRAY)
34+#if defined(MEMORY_ARRAY)
3935import qualified GHC.Exts as GHC
4036import qualified Streamly.Data.Array.Foreign as A
4137import qualified Streamly.Internal.Data.Array.Foreign as A
@@ -65,7 +61,6 @@ type Stream = A.Array
6561-- DATA_ARRAY
6662-- DATA_ARRAY_PRIM
6763-- DATA_ARRAY_PRIM_PINNED
68−-- DATA_SMALLARRAY
6964-------------------------------------------------------------------------------
7065
7166{-# INLINE sourceUnfoldr #-}
@@ -85,15 +80,10 @@ sourceIntFromTo value n = S.fold (A.writeN value) $ S.enumerateFromTo n (n + val
8580sourceFromList :: MonadIO m => Int -> Int -> m (Stream Int)
8681sourceFromList value n = S.fold (A.writeN value) $ S.fromList [n..n+value]
8782
88−-- Different defination of sourceIntFromToFromList for DATA_SMALLARRAY
8983-- CPP:
9084{-# INLINE sourceIntFromToFromList #-}
9185sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
92−#ifndef DATA_SMALLARRAY
9386sourceIntFromToFromList value n = P.return $ A.fromList $ [n..n + value]
94−#else
95−sourceIntFromToFromList value n = P.return $ A.fromListN value $ [n..n + value]
96−#endif
9787
9888-------------------------------------------------------------------------------
9989-- CPP Common to:
@@ -104,11 +94,9 @@ sourceIntFromToFromList value n = P.return $ A.fromListN value $ [n..n + value]
10494-------------------------------------------------------------------------------
10595
10696-- CPP:
107−#ifndef DATA_SMALLARRAY
10897{-# INLINE sourceIntFromToFromStream #-}
10998sourceIntFromToFromStream :: MonadIO m => Int -> Int -> m (Stream Int)
11099sourceIntFromToFromStream value n = S.fold A.write $ S.enumerateFromTo n (n + value)
111−#endif
112100
113101-------------------------------------------------------------------------------
114102-- CPP Common to:
@@ -136,7 +124,6 @@ sourceIsString value n = GHC.fromString (P.replicate (n + value) 'a')
136124-- DATA_ARRAY
137125-- DATA_ARRAY_PRIM
138126-- DATA_ARRAY_PRIM_PINNED
139−-- DATA_SMALLARRAY
140127-------------------------------------------------------------------------------
141128
142129{-# INLINE composeN #-}
@@ -198,7 +185,6 @@ pureFoldl' = S.foldl' (+) 0 . S.unfold A.read
198185-- CPP Common to:
199186-- MEMORY_ARRAY
200187-- DATA_ARRAY
201−-- DATA_SMALLARRAY
202188-------------------------------------------------------------------------------
203189
204190-- CPP:
@@ -234,7 +220,6 @@ foldableSum = P.sum
234220-- DATA_ARRAY
235221-- DATA_ARRAY_PRIM
236222-- DATA_ARRAY_PRIM_PINNED
237−-- DATA_SMALLARRAY
238223-------------------------------------------------------------------------------
239224
240225{-# INLINE unfoldReadDrain #-}
benchmark/streamly-benchmarks.cabal+2−4
@@ -167,6 +167,7 @@ library
167167
168168common bench-options
169169 import: compile-options, optimization-options, bench-depends
170+ include-dirs: .
170171 ghc-options: -rtsopts
171172 if flag(limit-build-mem)
172173 ghc-options: +RTS -M512M -RTS
@@ -473,10 +474,7 @@ benchmark Data.Array.Prim
473474benchmark Data.SmallArray
474475 import: bench-options
475476 type: exitcode-stdio-1.0
476− hs-source-dirs: .
477− main-is: Streamly/Benchmark/Data/Array.hs
478− other-modules: Streamly.Benchmark.Data.ArrayOps
479− cpp-options: -DDATA_SMALLARRAY
477+ main-is: Streamly/Benchmark/Data/Array/SmallArray.hs
480478
481479benchmark Data.Array.Prim.Pinned
482480 import: bench-options
streamly.cabal+3
@@ -56,6 +56,9 @@ extra-source-files:
5656 benchmark/bench-report/bin/build-lib.sh
5757 benchmark/bench-report/cabal.project
5858 benchmark/Streamly/Benchmark/Data/*.hs
59+ benchmark/Streamly/Benchmark/Data/Array/Common.hs
60+ benchmark/Streamly/Benchmark/Data/Array/CommonImports.hs
61+ benchmark/Streamly/Benchmark/Data/Array/SmallArray.hs
5962 benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hs
6063 benchmark/Streamly/Benchmark/Data/Parser/*.hs
6164 benchmark/Streamly/Benchmark/Data/Stream/*.hs