on master help sign in
Add a benchmark for Data.Stream.Async
5e089b4Harendra Kumar
benchmark/Streamly/Benchmark/Data/Stream/Async.hsnew file+193
@@ -0,0 +1,193 @@
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.Common
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
22+
23+moduleName :: String
24+moduleName = "Data.Stream.Async"
25+
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+o_1_space_joining :: Int -> [Benchmark]
69+o_1_space_joining value =
70+ [ bgroup "joining"
71+ [ benchIOSrc1 "async (2 of n/2)" (async2 (value `div` 2))
72+ ]
73+ ]
74+
75+-------------------------------------------------------------------------------
76+-- Concat
77+-------------------------------------------------------------------------------
78+
79+{-# INLINE sourceFoldMapWith #-}
80+sourceFoldMapWith :: Int -> Int -> Stream IO Int
81+sourceFoldMapWith value n =
82+ Async.concatMap Stream.fromPure $ Stream.fromList [n..n+value]
83+
84+{-# INLINE sourceFoldMapWithStream #-}
85+sourceFoldMapWithStream :: Int -> Int -> Stream IO Int
86+sourceFoldMapWithStream value n =
87+ Async.concatMap Stream.fromPure $ Stream.enumerateFromTo n (n + value)
88+
89+{-# INLINE concatFoldableWith #-}
90+concatFoldableWith :: Int -> Int -> Stream IO Int
91+concatFoldableWith value n =
92+ let step x =
93+ if x <= n + value
94+ then Just (Stream.fromPure x, x + 1)
95+ else Nothing
96+ list = List.unfoldr step n
97+ in Async.concatList list
98+
99+o_1_space_concatFoldable :: Int -> [Benchmark]
100+o_1_space_concatFoldable value =
101+ [ bgroup "concat-foldable"
102+ [ benchIOSrc "foldMapWith (<>) (List)"
103+ (sourceFoldMapWith value)
104+ , benchIOSrc "foldMapWith (<>) (Stream)"
105+ (sourceFoldMapWithStream value)
106+ , benchIOSrc "S.concatFoldableWith (<>) (List)"
107+ (concatFoldableWith value)
108+ ]
109+ ]
110+
111+{-# INLINE concatMapStreamsWith #-}
112+concatMapStreamsWith
113+ :: Int
114+ -> Int
115+ -> Int
116+ -> IO ()
117+concatMapStreamsWith outer inner n =
118+ Stream.fold Fold.drain
119+ $ Async.concatMap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
120+
121+{-# INLINE concatFmapStreamsWith #-}
122+concatFmapStreamsWith
123+ :: Int
124+ -> Int
125+ -> Int
126+ -> IO ()
127+concatFmapStreamsWith outer inner n =
128+ Stream.fold Fold.drain
129+ $ Async.concat
130+ $ fmap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
131+
132+o_1_space_concatMap :: Int -> [Benchmark]
133+o_1_space_concatMap value =
134+ value2 `seq`
135+ [ bgroup "concat"
136+ [ benchIO "concatMapWith (n of 1)"
137+ (concatMapStreamsWith value 1)
138+ , benchIO "concatMapWith (sqrt x of sqrt x)"
139+ (concatMapStreamsWith value2 value2)
140+ , benchIO "concatMapWith (1 of n)"
141+ (concatMapStreamsWith 1 value)
142+ , benchIO "concat . fmap (n of 1)"
143+ (concatFmapStreamsWith value 1)
144+ ]
145+ ]
146+
147+ where
148+
149+ value2 = round $ sqrt (fromIntegral value :: Double)
150+
151+-------------------------------------------------------------------------------
152+-- Monadic outer product
153+-------------------------------------------------------------------------------
154+
155+{-# INLINE toNullAp #-}
156+toNullAp :: Int -> Int -> IO ()
157+toNullAp linearCount start =
158+ Stream.fold Fold.drain
159+ $ Async.apply
160+ (fmap (+) (sourceUnfoldrM nestedCount2 start))
161+ (sourceUnfoldrM nestedCount2 start)
162+
163+ where
164+
165+ nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
166+
167+o_1_space_outerProduct :: Int -> [Benchmark]
168+o_1_space_outerProduct value =
169+ [ bgroup "monad-outer-product"
170+ [ benchIO "toNullAp" $ toNullAp value
171+ ]
172+ ]
173+
174+-------------------------------------------------------------------------------
175+-- Main
176+-------------------------------------------------------------------------------
177+
178+main :: IO ()
179+main = runWithCLIOpts defaultStreamSize allBenchmarks
180+
181+
182+ where
183+
184+ allBenchmarks value =
185+ [ bgroup (o_1_space_prefix moduleName) $ concat
186+ [ o_1_space_mapping value
187+ , o_1_space_concatFoldable value
188+ , o_1_space_concatMap value
189+ , o_1_space_outerProduct value
190+ , o_1_space_joining value
191+ ]
192+ , bgroup (o_n_heap_prefix moduleName) (o_n_heap_buffering value)
193+ ]
benchmark/streamly-benchmarks.cabal+12
@@ -244,6 +244,18 @@ benchmark Data.Stream
244 else
244 else
245 ghc-options: +RTS -M2500M -RTS
245 ghc-options: +RTS -M2500M -RTS
246
246
247+benchmark Data.Stream.Async
248+ import: bench-options-threaded
249+ type: exitcode-stdio-1.0
250+ hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
251+ main-is: Async.hs
252+ other-modules:
253+ Stream.Common
254+ if flag(use-streamly-core) || impl(ghcjs)
255+ buildable: False
256+ else
257+ buildable: True
258+
247benchmark Prelude.WSerial
259benchmark Prelude.WSerial
248 import: bench-options
260 import: bench-options
249 type: exitcode-stdio-1.0
261 type: exitcode-stdio-1.0
hie.yaml+2
@@ -40,6 +40,8 @@ cradle:
40 component: "bench:Data.Stream"
40 component: "bench:Data.Stream"
41 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Transform.hs"
41 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Transform.hs"
42 component: "bench:Data.Stream"
42 component: "bench:Data.Stream"
43+ - path: "./benchmark/Streamly/Benchmark/Data/Stream/Async.hs"
44+ component: "bench:Data.Stream.Async"
43 - path: "./benchmark/Streamly/Benchmark/Data/Unfold.hs"
45 - path: "./benchmark/Streamly/Benchmark/Data/Unfold.hs"
44 component: "bench:Data.Unfold"
46 component: "bench:Data.Unfold"
45 - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs"
47 - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs"
targets/Targets.hs+8−2
@@ -20,8 +20,6 @@ targets =
20 )
20 )
21
21
22 -- Streams
22 -- Streams
23− , ("Data.Stream", ["serial_wserial_cmp"])
24− , ("Prelude.WSerial", ["serial_wserial_cmp"])
25 , ("Data.Stream",
23 , ("Data.Stream",
26 [ "prelude_serial_grp"
24 [ "prelude_serial_grp"
27 , "infinite_grp"
25 , "infinite_grp"
@@ -29,6 +27,14 @@ targets =
29 , "serial_async_cmp"
27 , "serial_async_cmp"
30 ]
28 ]
31 )
29 )
30+ , ("Data.Stream.Async",
31+ [ "prelude_concurrent_grp"
32+ , "infinite_grp"
33+ , "concurrent_cmp"
34+ , "serial_async_cmp"
35+ ]
36+ )
37+ , ("Prelude.WSerial", ["serial_wserial_cmp"])
32 , ("Prelude.WSerial",
38 , ("Prelude.WSerial",
33 [ "prelude_serial_grp"
39 [ "prelude_serial_grp"
34 , "infinite_grp"
40 , "infinite_grp"