@@ -0,0 +1,253 @@
1+{-# LANGUAGE FlexibleContexts #-}
4+-- Copyright : (c) 2018 Composewell Technologies
7+-- Maintainer : streamly@composewell.com
9+module Stream.AsyncCommon
11+ , interleaveBenchmarks
16+ (composeN, benchIO, benchIOSink, benchIOSrc, sourceUnfoldrM)
17+import Streamly.Data.Stream (Stream)
18+import Streamly.Internal.Data.Stream.Async (MonadAsync, Config)
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
26+import Prelude hiding (mapM)
27+import Streamly.Benchmark.Common
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.
32+-------------------------------------------------------------------------------
34+-------------------------------------------------------------------------------
39+ => (Config -> Config)
43+mapM f n = composeN n $ Async.mapMWith f return
45+o_1_space_mapping :: Int -> (Config -> Config) -> [Benchmark]
46+o_1_space_mapping value f =
48+ [ benchIOSink value "mapM" $ mapM f 1
52+-------------------------------------------------------------------------------
53+-- Size conserving transformations (reordering, buffering, etc.)
54+-------------------------------------------------------------------------------
56+o_n_heap_buffering :: Int -> (Config -> Config) -> [Benchmark]
57+o_n_heap_buffering value f =
59+ [ benchIOSink value "mkAsync"
60+ (Stream.fold Fold.drain . Async.evalWith f)
64+-------------------------------------------------------------------------------
66+-------------------------------------------------------------------------------
69+async2 :: (Config -> Config) -> Int -> Int -> IO ()
71+ Stream.fold Fold.drain
73+ (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1))
75+{-# INLINE concatAsync2 #-}
76+concatAsync2 :: (Config -> Config) -> Int -> Int -> IO ()
77+concatAsync2 f count n =
78+ Stream.fold Fold.drain
81+ [sourceUnfoldrM count n, sourceUnfoldrM count (n + 1)]
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))
90+o_1_space_joining :: Int -> (Config -> Config) -> [Benchmark]
91+o_1_space_joining value f =
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))
99+-------------------------------------------------------------------------------
101+-------------------------------------------------------------------------------
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]
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)
114+{-# INLINE concatFoldableWith #-}
115+concatFoldableWith :: (Config -> Config) -> Int -> Int -> Stream IO Int
116+concatFoldableWith f value n =
119+ then Just (Stream.fromPure x, x + 1)
121+ list = List.unfoldr step n
122+ in Async.concatWith f (Stream.fromList list)
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)
136+{-# INLINE concatMapStreamsWith #-}
138+ :: (Config -> Config)
143+concatMapStreamsWith f outer inner n =
144+ Stream.fold Fold.drain
145+ $ Async.concatMapWith f (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
147+{-# INLINE concatFmapStreamsWith #-}
148+concatFmapStreamsWith
149+ :: (Config -> Config)
154+concatFmapStreamsWith f outer inner n =
155+ Stream.fold Fold.drain
156+ $ Async.concatWith f
157+ $ fmap (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
159+{-# INLINE concatMapInterleaveStreamsWith #-}
160+concatMapInterleaveStreamsWith
161+ :: (Config -> Config)
166+concatMapInterleaveStreamsWith f outer inner n =
167+ Stream.fold Fold.drain
168+ $ Async.concatMapInterleaveWith f
169+ (sourceUnfoldrM inner) (sourceUnfoldrM outer n)
171+o_1_space_concatMap :: Int -> (Config -> Config) -> [Benchmark]
172+o_1_space_concatMap value f =
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)
188+ value2 = round $ sqrt (fromIntegral value :: Double)
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 =
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)
206+ value2 = round $ sqrt (fromIntegral value :: Double)
208+-------------------------------------------------------------------------------
209+-- Monadic outer product
210+-------------------------------------------------------------------------------
212+{-# INLINE toNullAp #-}
213+toNullAp :: (Config -> Config) -> Int -> Int -> IO ()
214+toNullAp f linearCount start =
215+ Stream.fold Fold.drain
217+ (fmap (+) (sourceUnfoldrM nestedCount2 start))
218+ (sourceUnfoldrM nestedCount2 start)
222+ nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
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
231+-------------------------------------------------------------------------------
233+-------------------------------------------------------------------------------
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
244+ , bgroup (o_n_heap_prefix moduleName)
245+ (o_n_heap_buffering value modifier)
248+interleaveBenchmarks :: String -> (Config -> Config) -> Int -> [Benchmark]
249+interleaveBenchmarks moduleName modifier value =
251+ (o_1_space_prefix moduleName)
252+ (o_1_space_concatMapInterleave value modifier)