@@ -17,23 +17,102 @@
17{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
17{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
20−module Main (main) where
22import Control.DeepSeq (NFData(..))
20import Control.DeepSeq (NFData(..))
21+import Control.Monad.IO.Class (MonadIO)
22+import Data.Functor ((<&>))
23import Streamly.Prelude (MonadAsync, SerialT, IsStream)
23import Streamly.Prelude (MonadAsync, SerialT, IsStream)
24+import Streamly.Internal.Data.Stream.Serial (SerialT(..))
24import System.Random (randomRIO)
25import System.Random (randomRIO)
26−import qualified Streamly.Prelude as Stream
27import qualified Streamly.Internal.Data.Array.Foreign as Array
44import qualified Streamly.Internal.Data.Array.Foreign as Array
28import qualified Streamly.Internal.Data.Array.Foreign.Mut as MArray
45import qualified Streamly.Internal.Data.Array.Foreign.Mut as MArray
46+import qualified Streamly.Internal.Data.Stream.StreamD as StreamD
47+import qualified Streamly.Prelude as Stream
50+import Streamly.Benchmark.Common hiding (benchPureSrc)
52+type Stream = MArray.Array
54+-------------------------------------------------------------------------------
56+-------------------------------------------------------------------------------
58+{-# INLINE benchIO #-}
59+benchIO :: NFData b => String -> (Int -> IO a) -> (a -> b) -> Benchmark
60+benchIO name src f = bench name $ nfIO $
61+ (randomRIO (1,1) >>= src) <&> f
63+{-# INLINE benchPureSink #-}
64+benchPureSink :: NFData b => Int -> String -> (Stream Int -> b) -> Benchmark
65+benchPureSink value name = benchIO name (sourceIntFromTo value)
30−import Gauge hiding (env)
67+{-# INLINE benchIO' #-}
31−import Streamly.Benchmark.Common
68+benchIO' :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
69+benchIO' name src f = bench name $ nfIO $
70+ randomRIO (1,1) >>= src >>= f
72+{-# INLINE benchIOSink #-}
73+benchIOSink :: NFData b => Int -> String -> (Stream Int -> IO b) -> Benchmark
74+benchIOSink value name = benchIO' name (sourceIntFromTo value)
76+-- Drain a source that generates an array in the IO monad
77+{-# INLINE benchIOSrc #-}
78+benchIOSrc :: String -> (Int -> IO (Stream a)) -> Benchmark
79+benchIOSrc name src = benchIO name src id
33-------------------------------------------------------------------------------
81-------------------------------------------------------------------------------
34−-- Utilities
82+-- Bench Ops
35-------------------------------------------------------------------------------
83-------------------------------------------------------------------------------
85+{-# INLINE sourceUnfoldr #-}
86+sourceUnfoldr :: MonadIO m => Int -> Int -> m (Stream Int)
87+sourceUnfoldr value n =
88+ Stream.fold (MArray.writeN value) $ Stream.unfoldr step n
95+ else Just (cnt, cnt + 1)
97+{-# INLINE sourceIntFromTo #-}
98+sourceIntFromTo :: MonadIO m => Int -> Int -> m (Stream Int)
99+sourceIntFromTo value n =
100+ Stream.fold (MArray.writeN value) $ Stream.enumerateFromTo n (n + value)
102+{-# INLINE sourceFromList #-}
103+sourceFromList :: MonadIO m => Int -> Int -> m (Stream Int)
104+sourceFromList value n =
105+ Stream.fold (MArray.writeN value) $ Stream.fromList [n .. n + value]
107+{-# INLINE sourceIntFromToFromList #-}
108+sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
109+sourceIntFromToFromList value n = MArray.fromListN value [n..n + value]
111+{-# INLINE sourceIntFromToFromStream #-}
112+sourceIntFromToFromStream :: MonadIO m => Int -> Int -> m (Stream Int)
113+sourceIntFromToFromStream value n =
114+ Stream.fold MArray.write $ Stream.enumerateFromTo n (n + value)
37{-# INLINE sourceUnfoldrM #-}
116{-# INLINE sourceUnfoldrM #-}
38sourceUnfoldrM :: (IsStream t, MonadAsync m) => Int -> Int -> t m Int
117sourceUnfoldrM :: (IsStream t, MonadAsync m) => Int -> Int -> t m Int
39sourceUnfoldrM value n = Stream.unfoldrM step n
118sourceUnfoldrM value n = Stream.unfoldrM step n
@@ -43,29 +122,140 @@ sourceUnfoldrM value n = Stream.unfoldrM step n
43 then return Nothing
122 then return Nothing
44 else return (Just (cnt, cnt + 1))
123 else return (Just (cnt, cnt + 1))
125+-------------------------------------------------------------------------------
127+-------------------------------------------------------------------------------
46−{-# INLINE benchIO #-}
129+{-# INLINE composeN #-}
47−benchIO
130+composeN :: Monad m
48− :: NFData b
131+ => Int -> (Stream Int -> m (Stream Int)) -> Stream Int -> m (Stream Int)
49− => String -> (Int -> a) -> (a -> IO b) -> Benchmark
132+composeN n f x =
50−benchIO name src sink =
133+ case n of
51− bench name $ nfIO $ randomRIO (1,1) >>= sink . src
134+ 1 -> f x
136+ 3 -> f x >>= f >>= f
137+ 4 -> f x >>= f >>= f >>= f
140+{-# INLINE scanl' #-}
141+scanl' :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
142+scanl' value n = composeN n $ onArray value $ Stream.scanl' (+) 0
144+{-# INLINE scanl1' #-}
145+scanl1' :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
146+scanl1' value n = composeN n $ onArray value $ Stream.scanl1' (+)
149+map :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
150+map value n = composeN n $ onArray value $ Stream.map (+ 1)
152+{-# INLINE onArray #-}
154+ :: MonadIO m => Int -> (Stream.SerialT m Int -> Stream.SerialT m Int)
157+onArray value f arr =
158+ Stream.fold (MArray.writeN value) $ f $ Stream.unfold MArray.read arr
160+-------------------------------------------------------------------------------
162+-------------------------------------------------------------------------------
164+{-# INLINE unfoldReadDrain #-}
165+unfoldReadDrain :: MonadIO m => Stream Int -> m ()
166+unfoldReadDrain = Stream.drain . Stream.unfold MArray.read
168+{-# INLINE unfoldReadRevDrain #-}
169+unfoldReadRevDrain :: MonadIO m => Stream Int -> m ()
170+unfoldReadRevDrain = Stream.drain . Stream.unfold MArray.readRev
172+{-# INLINE toStreamDRevDrain #-}
173+toStreamDRevDrain :: MonadIO m => Stream Int -> m ()
175+ Stream.drain . SerialT . StreamD.toStreamK . MArray.toStreamDRev
177+{-# INLINE toStreamDDrain #-}
178+toStreamDDrain :: MonadIO m => Stream Int -> m ()
179+toStreamDDrain = Stream.drain . SerialT . StreamD.toStreamK . MArray.toStreamD
181+{-# INLINE unfoldFold #-}
182+unfoldFold :: MonadIO m => Stream Int -> m Int
183+unfoldFold = Stream.foldl' (+) 0 . Stream.unfold MArray.read
185+-------------------------------------------------------------------------------
187+-------------------------------------------------------------------------------
189+o_1_space_generation :: Int -> [Benchmark]
190+o_1_space_generation value =
193+ [ benchIOSrc "writeN . intFromTo" (sourceIntFromTo value)
195+ "fromList . intFromTo"
196+ (sourceIntFromToFromList value)
197+ , benchIOSrc "writeN . unfoldr" (sourceUnfoldr value)
198+ , benchIOSrc "writeN . fromList" (sourceFromList value)
199+ , benchIOSrc "write . intFromTo" (sourceIntFromToFromStream value)
203+o_1_space_elimination :: Int -> [Benchmark]
204+o_1_space_elimination value =
205+ [ bgroup "elimination"
206+ [ benchPureSink value "id" id
207+ , benchIOSink value "foldl'" unfoldFold
208+ , benchIOSink value "read" unfoldReadDrain
209+ , benchIOSink value "readRev" unfoldReadRevDrain
210+ , benchIOSink value "toStream" toStreamDDrain
211+ , benchIOSink value "toStreamRev" toStreamDRevDrain
215+o_n_heap_serial :: Int -> [Benchmark]
216+o_n_heap_serial value =
217+ [ bgroup "elimination"
219+ -- Converting the stream to an array
220+ benchFold "writeN" (Stream.fold (MArray.writeN value))
221+ (sourceUnfoldrM value)
225+o_1_space_transformation :: Int -> [Benchmark]
226+o_1_space_transformation value =
227+ [ bgroup "transformation"
228+ [ benchIOSink value "scanl'" (scanl' value 1)
229+ , benchIOSink value "scanl1'" (scanl1' value 1)
230+ , benchIOSink value "map" (map value 1)
234+o_1_space_transformationX4 :: Int -> [Benchmark]
235+o_1_space_transformationX4 value =
236+ [ bgroup "transformationX4"
237+ [ benchIOSink value "scanl'" (scanl' value 4)
238+ , benchIOSink value "scanl1'" (scanl1' value 4)
239+ , benchIOSink value "map" (map value 4)
53o_1_space_serial_marray ::
243o_1_space_serial_marray ::
54 Int -> (MArray.Array Int, Array.Array Int) -> [Benchmark]
244 Int -> (MArray.Array Int, Array.Array Int) -> [Benchmark]
55o_1_space_serial_marray value ~(array, indices) =
245o_1_space_serial_marray value ~(array, indices) =
56− [ benchIO "partitionBy (< 0)" (const array)
246+ [ benchIO' "partitionBy (< 0)" (const (return array))
57 $ MArray.partitionBy (< 0)
247 $ MArray.partitionBy (< 0)
58− , benchIO "partitionBy (> 0)" (const array)
248+ , benchIO' "partitionBy (> 0)" (const (return array))
59 $ MArray.partitionBy (> 0)
249 $ MArray.partitionBy (> 0)
60− , benchIO "partitionBy (< value/2)" (const array)
250+ , benchIO' "partitionBy (< value/2)" (const (return array))
61 $ MArray.partitionBy (< (value `div` 2))
251 $ MArray.partitionBy (< (value `div` 2))
62− , benchIO "partitionBy (> value/2)" (const array)
252+ , benchIO' "partitionBy (> value/2)" (const (return array))
63 $ MArray.partitionBy (> (value `div` 2))
253 $ MArray.partitionBy (> (value `div` 2))
64− , benchIO "strip (< value/2 || > value/2)" (const array)
254+ , benchIO' "strip (< value/2 || > value/2)" (const (return array))
65 $ MArray.strip (\x -> x < value `div` 2 || x > value `div` 2)
255 $ MArray.strip (\x -> x < value `div` 2 || x > value `div` 2)
66− , benchIO "strip (> 0)" (const array)
256+ , benchIO' "strip (> 0)" (const (return array))
67 $ MArray.strip (> 0)
257 $ MArray.strip (> 0)
68− , benchIO "modifyIndices (+ 1)" (const indices)
258+ , benchIO' "modifyIndices (+ 1)" (const (return indices))
69 $ Stream.fold (MArray.modifyIndices (\_idx val -> val + 1) array)
259 $ Stream.fold (MArray.modifyIndices (\_idx val -> val + 1) array)
70 . Stream.unfold Array.read
260 . Stream.unfold Array.read
@@ -89,6 +279,13 @@ main = do
89 return (marr, indices)
279 return (marr, indices)
91 allBenchmarks array value =
281 allBenchmarks array value =
92− [ bgroup (o_1_space_prefix moduleName) $
282+ [ bgroup (o_1_space_prefix moduleName)
93− o_1_space_serial_marray value array
284+ [ o_1_space_serial_marray value array
285+ , o_1_space_generation value
286+ , o_1_space_elimination value
287+ , o_1_space_transformation value
288+ , o_1_space_transformationX4 value
290+ , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)