on master help sign in
Add benchmarks for eagerEval option
0945bc3Harendra Kumar
benchmark/Streamly/Benchmark/Data/Stream/Async.hs+8−207
@@ -6,219 +6,20 @@
6-- License : BSD3
6-- License : BSD3
7-- Maintainer : streamly@composewell.com
7-- Maintainer : streamly@composewell.com
8
8
9−import Stream.Common
9+import Stream.AsyncCommon (allBenchmarks, interleaveBenchmarks)
10− (composeN, benchIO, benchIOSink, benchIOSrc, sourceUnfoldrM)
11−import Streamly.Data.Stream (Stream)
12−import Streamly.Internal.Data.Stream.Async (MonadAsync)
13−
14−import qualified Data.List as List
15−import qualified Streamly.Data.Fold as Fold
16−import qualified Streamly.Data.Stream as Stream
17−import qualified Streamly.Internal.Data.Stream.Async as Async
18−
19−import Gauge
20−import Prelude hiding (mapM)
21−import Streamly.Benchmark.Common
10+import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
22
11
23moduleName :: String
12moduleName :: String
24moduleName = "Data.Stream.Async"
13moduleName = "Data.Stream.Async"
25
14
26−-- XXX Write inspection tests to make sure no dictionaries are being passed
27−-- around to find specialization issues. Could be really bad for perf.
28−
29−-------------------------------------------------------------------------------
30−-- Mapping
31−-------------------------------------------------------------------------------
32−
33−{-# INLINE mapM #-}
34−mapM ::
35− MonadAsync m
36− => Int
37− -> Stream m Int
38− -> m ()
39−mapM n = composeN n $ Async.mapM return
40−
41−o_1_space_mapping :: Int -> [Benchmark]
42−o_1_space_mapping value =
43− [ bgroup "mapping"
44− [ benchIOSink value "mapM" $ mapM 1
45− ]
46− ]
47−
48−-------------------------------------------------------------------------------
49−-- Size conserving transformations (reordering, buffering, etc.)
50−-------------------------------------------------------------------------------
51−
52−o_n_heap_buffering :: Int -> [Benchmark]
53−o_n_heap_buffering value =
54− [ bgroup "buffered"
55− [benchIOSink value "mkAsync" (Stream.fold Fold.drain . Async.eval)]
56− ]
57−
58−-------------------------------------------------------------------------------
59−-- Joining
60−-------------------------------------------------------------------------------
61−
62−{-# INLINE async2 #-}
63−async2 :: Int -> Int -> IO ()
64−async2 count n =
65− Stream.fold Fold.drain $
66− sourceUnfoldrM count n `Async.append` sourceUnfoldrM count (n + 1)
67−
68−{-# INLINE concatAsync2 #-}
69−concatAsync2 :: Int -> Int -> IO ()
70−concatAsync2 count n =
71− Stream.fold Fold.drain $
72− Async.concatList [sourceUnfoldrM count n, sourceUnfoldrM count (n + 1)]
73−
74−{-# INLINE interleave2 #-}
75−interleave2 :: Int -> Int -> IO ()
76−interleave2 count n =
77− Stream.fold Fold.drain $
78− sourceUnfoldrM count n `Async.interleave` sourceUnfoldrM count (n + 1)
79−
80−o_1_space_joining :: Int -> [Benchmark]
81−o_1_space_joining value =
82− [ bgroup "joining"
83− [ benchIOSrc1 "async (2 of n/2)" (async2 (value `div` 2))
84− , benchIOSrc1 "concat async (2 of n/2)" (concatAsync2 (value `div` 2))
85− , benchIOSrc1 "interleave (2 of n/2)" (interleave2 (value `div` 2))
86− ]
87− ]
88−
89−-------------------------------------------------------------------------------
90−-- Concat
91−-------------------------------------------------------------------------------
92−
93−{-# INLINE sourceFoldMapWith #-}
94−sourceFoldMapWith :: Int -> Int -> Stream IO Int
95−sourceFoldMapWith value n =
96− Async.concatMap Stream.fromPure $ Stream.fromList [n..n+value]
97−
98−{-# INLINE sourceFoldMapWithStream #-}
99−sourceFoldMapWithStream :: Int -> Int -> Stream IO Int
100−sourceFoldMapWithStream value n =
101− Async.concatMap Stream.fromPure $ Stream.enumerateFromTo n (n + value)
102−
103−{-# INLINE concatFoldableWith #-}
104−concatFoldableWith :: Int -> Int -> Stream IO Int
105−concatFoldableWith value n =
106− let step x =
107− if x <= n + value
108− then Just (Stream.fromPure x, x + 1)
109− else Nothing
110− list = List.unfoldr step n
111− in Async.concatList list
112−
113−o_1_space_concatFoldable :: Int -> [Benchmark]
114−o_1_space_concatFoldable value =
115− [ bgroup "concat-foldable"
116− [ benchIOSrc "foldMapWith (<>) (List)"
117− (sourceFoldMapWith value)
118− , benchIOSrc "foldMapWith (<>) (Stream)"
119− (sourceFoldMapWithStream value)
120− , benchIOSrc "S.concatFoldableWith (<>) (List)"
121− (concatFoldableWith value)
122− ]
123− ]
124−
125−{-# INLINE concatMapStreamsWith #-}
126−concatMapStreamsWith
127− :: Int
128− -> Int
129− -> Int
130− -> IO ()
131−concatMapStreamsWith outer inner n =
132− Stream.fold Fold.drain
133− $ Async.concatMap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
134−
135−{-# INLINE concatFmapStreamsWith #-}
136−concatFmapStreamsWith
137− :: Int
138− -> Int
139− -> Int
140− -> IO ()
141−concatFmapStreamsWith outer inner n =
142− Stream.fold Fold.drain
143− $ Async.concat
144− $ fmap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
145−
146−{-# INLINE concatMapInterleaveStreamsWith #-}
147−concatMapInterleaveStreamsWith
148− :: Int
149− -> Int
150− -> Int
151− -> IO ()
152−concatMapInterleaveStreamsWith outer inner n =
153− Stream.fold Fold.drain
154− $ Async.concatMapInterleave
155− (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
156−
157−o_1_space_concatMap :: Int -> [Benchmark]
158−o_1_space_concatMap value =
159− value2 `seq`
160− [ bgroup "concat"
161− [ benchIO "concatMapWith (n of 1)"
162− (concatMapStreamsWith value 1)
163− , benchIO "concatMapWith (sqrt x of sqrt x)"
164− (concatMapStreamsWith value2 value2)
165− , benchIO "concatMapWith (1 of n)"
166− (concatMapStreamsWith 1 value)
167− , benchIO "concat . fmap (n of 1)"
168− (concatFmapStreamsWith value 1)
169− , benchIO "concatMapInterleaveWith (n of 1)"
170− (concatMapInterleaveStreamsWith value 1)
171− , benchIO "concatMapInterleaveWith (sqrt x of sqrt x)"
172− (concatMapInterleaveStreamsWith value2 value2)
173− , benchIO "concatMapInterleaveWith (1 of n)"
174− (concatMapInterleaveStreamsWith 1 value)
175− ]
176− ]
177−
178− where
179−
180− value2 = round $ sqrt (fromIntegral value :: Double)
181−
182−-------------------------------------------------------------------------------
183−-- Monadic outer product
184−-------------------------------------------------------------------------------
185−
186−{-# INLINE toNullAp #-}
187−toNullAp :: Int -> Int -> IO ()
188−toNullAp linearCount start =
189− Stream.fold Fold.drain
190− $ Async.apply
191− (fmap (+) (sourceUnfoldrM nestedCount2 start))
192− (sourceUnfoldrM nestedCount2 start)
193−
194− where
195−
196− nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
197−
198−o_1_space_outerProduct :: Int -> [Benchmark]
199−o_1_space_outerProduct value =
200− [ bgroup "monad-outer-product"
201− [ benchIO "toNullAp" $ toNullAp value
202− ]
203− ]
204−
205-------------------------------------------------------------------------------
15-------------------------------------------------------------------------------
206-- Main
16-- Main
207-------------------------------------------------------------------------------
17-------------------------------------------------------------------------------
208
18
209main :: IO ()
19main :: IO ()
20+main =
210−main = runWithCLIOpts defaultStreamSize allBenchmarks
21+ runWithCLIOpts defaultStreamSize
211−
22+ (\value ->
212−
23+ allBenchmarks moduleName id value
213− where
24+ <> interleaveBenchmarks moduleName id value
214−
25+ )
215− allBenchmarks value =
216− [ bgroup (o_1_space_prefix moduleName) $ concat
217− [ o_1_space_mapping value
218− , o_1_space_concatFoldable value
219− , o_1_space_concatMap value
220− , o_1_space_outerProduct value
221− , o_1_space_joining value
222− ]
223− , bgroup (o_n_heap_prefix moduleName) (o_n_heap_buffering value)
224− ]
benchmark/Streamly/Benchmark/Data/Stream/AsyncCommon.hsnew file+253
@@ -0,0 +1,253 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+-- |
3+-- Module : Main
4+-- Copyright : (c) 2018 Composewell Technologies
5+--
6+-- License : BSD3
7+-- Maintainer : streamly@composewell.com
8+
9+module Stream.AsyncCommon
10+ ( allBenchmarks
11+ , interleaveBenchmarks
12+ )
13+where
14+
15+import Stream.Common
16+ (composeN, benchIO, benchIOSink, benchIOSrc, sourceUnfoldrM)
17+import Streamly.Data.Stream (Stream)
18+import Streamly.Internal.Data.Stream.Async (MonadAsync, Config)
19+
20+import qualified Data.List as List
21+import qualified Streamly.Data.Fold as Fold
22+import qualified Streamly.Data.Stream as Stream
23+import qualified Streamly.Internal.Data.Stream.Async as Async
24+
25+import Gauge
26+import Prelude hiding (mapM)
27+import Streamly.Benchmark.Common
28+
29+-- XXX Write inspection tests to make sure no dictionaries are being passed
30+-- around to find specialization issues. Could be really bad for perf.
31+
32+-------------------------------------------------------------------------------
33+-- Mapping
34+-------------------------------------------------------------------------------
35+
36+{-# INLINE mapM #-}
37+mapM ::
38+ MonadAsync m
39+ => (Config -> Config)
40+ -> Int
41+ -> Stream m Int
42+ -> m ()
43+mapM f n = composeN n $ Async.mapMWith f return
44+
45+o_1_space_mapping :: Int -> (Config -> Config) -> [Benchmark]
46+o_1_space_mapping value f =
47+ [ bgroup "mapping"
48+ [ benchIOSink value "mapM" $ mapM f 1
49+ ]
50+ ]
51+
52+-------------------------------------------------------------------------------
53+-- Size conserving transformations (reordering, buffering, etc.)
54+-------------------------------------------------------------------------------
55+
56+o_n_heap_buffering :: Int -> (Config -> Config) -> [Benchmark]
57+o_n_heap_buffering value f =
58+ [ bgroup "buffered"
59+ [ benchIOSink value "mkAsync"
60+ (Stream.fold Fold.drain . Async.evalWith f)
61+ ]
62+ ]
63+
64+-------------------------------------------------------------------------------
65+-- Joining
66+-------------------------------------------------------------------------------
67+
68+{-# INLINE async2 #-}
69+async2 :: (Config -> Config) -> Int -> Int -> IO ()
70+async2 f count n =
71+ Stream.fold Fold.drain
72+ $ Async.appendWith f
73+ (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1))
74+
75+{-# INLINE concatAsync2 #-}
76+concatAsync2 :: (Config -> Config) -> Int -> Int -> IO ()
77+concatAsync2 f count n =
78+ Stream.fold Fold.drain
79+ $ Async.concatWith f
80+ $ Stream.fromList
81+ [sourceUnfoldrM count n, sourceUnfoldrM count (n + 1)]
82+
83+{-# INLINE interleave2 #-}
84+interleave2 :: (Config -> Config) -> Int -> Int -> IO ()
85+interleave2 f count n =
86+ Stream.fold Fold.drain
87+ $ Async.interleaveWith f
88+ (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1))
89+
90+o_1_space_joining :: Int -> (Config -> Config) -> [Benchmark]
91+o_1_space_joining value f =
92+ [ bgroup "joining"
93+ [ benchIOSrc1 "async (2 of n/2)" (async2 f (value `div` 2))
94+ , benchIOSrc1 "concat async (2 of n/2)" (concatAsync2 f (value `div` 2))
95+ , benchIOSrc1 "interleave (2 of n/2)" (interleave2 f (value `div` 2))
96+ ]
97+ ]
98+
99+-------------------------------------------------------------------------------
100+-- Concat
101+-------------------------------------------------------------------------------
102+
103+{-# INLINE sourceFoldMapWith #-}
104+sourceFoldMapWith :: (Config -> Config) -> Int -> Int -> Stream IO Int
105+sourceFoldMapWith f value n =
106+ Async.concatMapWith f Stream.fromPure $ Stream.fromList [n..n+value]
107+
108+{-# INLINE sourceFoldMapWithStream #-}
109+sourceFoldMapWithStream :: (Config -> Config) -> Int -> Int -> Stream IO Int
110+sourceFoldMapWithStream f value n =
111+ Async.concatMapWith f Stream.fromPure
112+ $ Stream.enumerateFromTo n (n + value)
113+
114+{-# INLINE concatFoldableWith #-}
115+concatFoldableWith :: (Config -> Config) -> Int -> Int -> Stream IO Int
116+concatFoldableWith f value n =
117+ let step x =
118+ if x <= n + value
119+ then Just (Stream.fromPure x, x + 1)
120+ else Nothing
121+ list = List.unfoldr step n
122+ in Async.concatWith f (Stream.fromList list)
123+
124+o_1_space_concatFoldable :: Int -> (Config -> Config) -> [Benchmark]
125+o_1_space_concatFoldable value f =
126+ [ bgroup "concat-foldable"
127+ [ benchIOSrc "foldMapWith (<>) (List)"
128+ (sourceFoldMapWith f value)
129+ , benchIOSrc "foldMapWith (<>) (Stream)"
130+ (sourceFoldMapWithStream f value)
131+ , benchIOSrc "S.concatFoldableWith (<>) (List)"
132+ (concatFoldableWith f value)
133+ ]
134+ ]
135+
136+{-# INLINE concatMapStreamsWith #-}
137+concatMapStreamsWith
138+ :: (Config -> Config)
139+ -> Int
140+ -> Int
141+ -> Int
142+ -> IO ()
143+concatMapStreamsWith f outer inner n =
144+ Stream.fold Fold.drain
145+ $ Async.concatMapWith f (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
146+
147+{-# INLINE concatFmapStreamsWith #-}
148+concatFmapStreamsWith
149+ :: (Config -> Config)
150+ -> Int
151+ -> Int
152+ -> Int
153+ -> IO ()
154+concatFmapStreamsWith f outer inner n =
155+ Stream.fold Fold.drain
156+ $ Async.concatWith f
157+ $ fmap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
158+
159+{-# INLINE concatMapInterleaveStreamsWith #-}
160+concatMapInterleaveStreamsWith
161+ :: (Config -> Config)
162+ -> Int
163+ -> Int
164+ -> Int
165+ -> IO ()
166+concatMapInterleaveStreamsWith f outer inner n =
167+ Stream.fold Fold.drain
168+ $ Async.concatMapInterleaveWith f
169+ (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
170+
171+o_1_space_concatMap :: Int -> (Config -> Config) -> [Benchmark]
172+o_1_space_concatMap value f =
173+ value2 `seq`
174+ [ bgroup "concat"
175+ [ benchIO "concatMapWith (n of 1)"
176+ (concatMapStreamsWith f value 1)
177+ , benchIO "concatMapWith (sqrt x of sqrt x)"
178+ (concatMapStreamsWith f value2 value2)
179+ , benchIO "concatMapWith (1 of n)"
180+ (concatMapStreamsWith f 1 value)
181+ , benchIO "concat . fmap (n of 1)"
182+ (concatFmapStreamsWith f value 1)
183+ ]
184+ ]
185+
186+ where
187+
188+ value2 = round $ sqrt (fromIntegral value :: Double)
189+
190+-- XXX These do not work with the eager option
191+o_1_space_concatMapInterleave :: Int -> (Config -> Config) -> [Benchmark]
192+o_1_space_concatMapInterleave value f =
193+ value2 `seq`
194+ [ bgroup "concat"
195+ [ benchIO "concatMapInterleaveWith (n of 1)"
196+ (concatMapInterleaveStreamsWith f value 1)
197+ , benchIO "concatMapInterleaveWith (sqrt x of sqrt x)"
198+ (concatMapInterleaveStreamsWith f value2 value2)
199+ , benchIO "concatMapInterleaveWith (1 of n)"
200+ (concatMapInterleaveStreamsWith f 1 value)
201+ ]
202+ ]
203+
204+ where
205+
206+ value2 = round $ sqrt (fromIntegral value :: Double)
207+
208+-------------------------------------------------------------------------------
209+-- Monadic outer product
210+-------------------------------------------------------------------------------
211+
212+{-# INLINE toNullAp #-}
213+toNullAp :: (Config -> Config) -> Int -> Int -> IO ()
214+toNullAp f linearCount start =
215+ Stream.fold Fold.drain
216+ $ Async.applyWith f
217+ (fmap (+) (sourceUnfoldrM nestedCount2 start))
218+ (sourceUnfoldrM nestedCount2 start)
219+
220+ where
221+
222+ nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
223+
224+o_1_space_outerProduct :: Int -> (Config -> Config) -> [Benchmark]
225+o_1_space_outerProduct value f =
226+ [ bgroup "monad-outer-product"
227+ [ benchIO "toNullAp" $ toNullAp f value
228+ ]
229+ ]
230+
231+-------------------------------------------------------------------------------
232+-- Benchmark sets
233+-------------------------------------------------------------------------------
234+
235+allBenchmarks :: String -> (Config -> Config) -> Int -> [Benchmark]
236+allBenchmarks moduleName modifier value =
237+ [ bgroup (o_1_space_prefix moduleName) $ concat
238+ [ o_1_space_mapping value modifier
239+ , o_1_space_concatFoldable value modifier
240+ , o_1_space_concatMap value modifier
241+ , o_1_space_outerProduct value modifier
242+ , o_1_space_joining value modifier
243+ ]
244+ , bgroup (o_n_heap_prefix moduleName)
245+ (o_n_heap_buffering value modifier)
246+ ]
247+
248+interleaveBenchmarks :: String -> (Config -> Config) -> Int -> [Benchmark]
249+interleaveBenchmarks moduleName modifier value =
250+ [ bgroup
251+ (o_1_space_prefix moduleName)
252+ (o_1_space_concatMapInterleave value modifier)
253+ ]
benchmark/Streamly/Benchmark/Data/Stream/AsyncEager.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+-- |
3+-- Module : Main
4+-- Copyright : (c) 2018 Composewell Technologies
5+--
6+-- License : BSD3
7+-- Maintainer : streamly@composewell.com
8+
9+import Stream.AsyncCommon (allBenchmarks)
10+import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
11+
12+import qualified Streamly.Internal.Data.Stream.Async as Async
13+
14+moduleName :: String
15+moduleName = "Data.Stream.AsyncEager"
16+
17+-------------------------------------------------------------------------------
18+-- Main
19+-------------------------------------------------------------------------------
20+
21+main :: IO ()
22+main =
23+ runWithCLIOpts defaultStreamSize (allBenchmarks moduleName Async.eagerEval)
benchmark/bench-runner/Main.hs+2
@@ -51,6 +51,8 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
51 "-K8M -M64M"
51 "-K8M -M64M"
52 | "Data.Stream/o-n-space.grouping." `isPrefixOf` benchName = ""
52 | "Data.Stream/o-n-space.grouping." `isPrefixOf` benchName = ""
53 | "Data.Stream/o-n-space." `isPrefixOf` benchName = "-K4M"
53 | "Data.Stream/o-n-space." `isPrefixOf` benchName = "-K4M"
54+ | "Data.Stream.AsyncEager/o-1-space.monad-outer-product.toNullAp" `isPrefixOf` benchName = "-M1024M -K4M"
55+ | "Data.Stream.AsyncEager/o-1-space." `isPrefixOf` benchName = "-M512M -K4M"
54 | "Prelude.WSerial/o-n-space." `isPrefixOf` benchName = "-K4M"
56 | "Prelude.WSerial/o-n-space." `isPrefixOf` benchName = "-K4M"
55 | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName =
57 | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName =
56 "-K4M"
58 "-K4M"
benchmark/streamly-benchmarks.cabal+14
@@ -250,6 +250,20 @@ benchmark Data.Stream.Async
250 hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
250 hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
251 main-is: Async.hs
251 main-is: Async.hs
252 other-modules:
252 other-modules:
253+ Stream.AsyncCommon
254+ Stream.Common
255+ if flag(use-streamly-core) || impl(ghcjs)
256+ buildable: False
257+ else
258+ buildable: True
259+
260+benchmark Data.Stream.AsyncEager
261+ import: bench-options-threaded
262+ type: exitcode-stdio-1.0
263+ hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
264+ main-is: AsyncEager.hs
265+ other-modules:
266+ Stream.AsyncCommon
253 Stream.Common
267 Stream.Common
254 if flag(use-streamly-core) || impl(ghcjs)
268 if flag(use-streamly-core) || impl(ghcjs)
255 buildable: False
269 buildable: False
hie.yaml+4
@@ -42,6 +42,10 @@ cradle:
42 component: "bench:Data.Stream"
42 component: "bench:Data.Stream"
43 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Async.hs"
43 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Async.hs"
44 component: "bench:Data.Stream.Async"
44 component: "bench:Data.Stream.Async"
45+ - path: "./benchmark/Streamly/Benchmark/Data/Stream/AsyncCommon.hs"
46+ component: "bench:Data.Stream.Async"
47+ - path: "./benchmark/Streamly/Benchmark/Data/Stream/AsyncEager.hs"
48+ component: "bench:Data.Stream.AsyncEager"
45 - path: "./benchmark/Streamly/Benchmark/Data/Unfold.hs"
49 - path: "./benchmark/Streamly/Benchmark/Data/Unfold.hs"
46 component: "bench:Data.Unfold"
50 component: "bench:Data.Unfold"
47 - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs"
51 - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs"
targets/Targets.hs+6
@@ -34,6 +34,12 @@ targets =
34 , "serial_async_cmp"
34 , "serial_async_cmp"
35 ]
35 ]
36 )
36 )
37+ , ("Data.Stream.AsyncEager",
38+ [ "prelude_concurrent_grp"
39+ , "infinite_grp"
40+ , "concurrent_cmp"
41+ ]
42+ )
37 , ("Prelude.WSerial", ["serial_wserial_cmp"])
43 , ("Prelude.WSerial", ["serial_wserial_cmp"])
38 , ("Prelude.WSerial",
44 , ("Prelude.WSerial",
39 [ "prelude_serial_grp"
45 [ "prelude_serial_grp"