on master help sign in
Split lib/b/Prelude into Generation, Elimination and Transformation
commitae7a0250cd5fddc4caee1faef6f8158b6ca13da1 authoradithyaov <adi.obilisetty@gmail.com> dateThu 30 Apr 2020, 19:21 (6 years ago) parentcf8ec5c
7 files changed+3068−2707
benchmark/Streamly/Benchmark/Prelude/Serial.hs+1−1 benchmark/lib/Streamly/Benchmark/Prelude.hs+6−2706 benchmark/lib/Streamly/Benchmark/Prelude/Elimination.hs+795 benchmark/lib/Streamly/Benchmark/Prelude/Generation.hs+1248 benchmark/lib/Streamly/Benchmark/Prelude/Transformation.hs+1013 benchmark/streamly-benchmarks.cabal+4 streamly.cabal+1
benchmark/Streamly/Benchmark/Prelude/Serial.hs+1−1
@@ -30,7 +30,7 @@ main = do
3030 [ o_n_space_serial_toList size -- < 2MB
3131 , o_n_space_serial_outerProductStreams size
3232 , o_n_space_wSerial_outerProductStreams size
33− , o_n_space_serial_traversable size -- < 2MB
33+ , o_n_space_serial size -- < 2MB
3434 , o_n_space_serial_foldr size
3535 ]
3636 ]
benchmark/lib/Streamly/Benchmark/Prelude.hs+6−2706
@@ -5,2712 +5,12 @@
55-- License : MIT
66-- Maintainer : streamly@composewell.com
77
8−{-# LANGUAGE CPP #-}
9−{-# LANGUAGE FlexibleContexts #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE DeriveAnyClass #-}
12−{-# LANGUAGE DeriveGeneric #-}
13−{-# LANGUAGE RankNTypes #-}
14−{-# LANGUAGE TupleSections #-}
15−
16−#ifdef __HADDOCK_VERSION__
17−#undef INSPECTION
18−#endif
19−
20−#ifdef INSPECTION
21−{-# LANGUAGE TemplateHaskell #-}
22−{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
23−#endif
24−
258module Streamly.Benchmark.Prelude
26− -- TODO: export a single bench group for o_1_space_serial
27− ( o_1_space_serial_pure
28− , o_1_space_serial_foldable
29− , o_1_space_serial_generation
30− , o_1_space_serial_elimination
31− , o_1_space_serial_foldMultiStream
32− , o_1_space_serial_pipes
33− , o_1_space_serial_pipesX4
34− , o_1_space_serial_transformer
35− , o_1_space_serial_transformation
36− , o_1_space_serial_transformationX4
37− , o_1_space_serial_filtering
38− , o_1_space_serial_filteringX4
39− , o_1_space_serial_joining
40− , o_1_space_serial_concatFoldable
41− , o_1_space_serial_concatSerial
42− , o_1_space_serial_outerProductStreams
43− , o_1_space_serial_mixed
44− , o_1_space_serial_mixedX4
45−
46− , o_1_space_wSerial_transformation
47− , o_1_space_wSerial_concatMap
48− , o_1_space_wSerial_outerProduct
49−
50− , o_1_space_zipSerial_transformation
51−
52− , o_n_space_serial_toContainers
53− , o_n_space_serial_outerProductStreams
54−
55− , o_n_space_wSerial_outerProductStreams
56−
57− , o_n_space_serial_traversable
58− , o_n_space_serial_foldr
59−
60− , o_n_heap_serial_foldl
61− , o_n_heap_serial_buffering
62−
63− , o_n_stack_serial_iterated
64−
65− , o_1_space_async_generation
66− , o_1_space_async_concatFoldable
67− , o_1_space_async_concatMap
68− , o_1_space_async_transformation
69−
70− , o_1_space_wAsync_generation
71− , o_1_space_wAsync_concatFoldable
72− , o_1_space_wAsync_concatMap
73− , o_1_space_wAsync_transformation
74−
75− , o_1_space_ahead_generation
76− , o_1_space_ahead_concatFoldable
77− , o_1_space_ahead_concatMap
78− , o_1_space_ahead_transformation
79−
80− , o_1_space_async_zip
81−
82− , o_n_space_parallel_generation
83− , o_n_space_parallel_concatFoldable
84− , o_n_space_parallel_concatMap
85− , o_n_space_parallel_transformation
86− , o_n_space_parallel_outerProductStreams
87− , o_n_space_parallel_outerProductStreams2
88−
89− , o_1_space_async_avgRate
90−
91− , o_1_space_ahead_avgRate
9+ ( module Streamly.Benchmark.Prelude.Generation
10+ , module Streamly.Benchmark.Prelude.Elimination
11+ , module Streamly.Benchmark.Prelude.Transformation
9212 ) where
9313
94−import Control.DeepSeq (NFData(..))
95−import Control.Monad (when)
96−import Control.Monad.IO.Class (MonadIO(..))
97−import Control.Monad.State.Strict (StateT, get, put)
98−import Data.Functor.Identity (Identity, runIdentity)
99−import Data.IORef (newIORef, modifyIORef')
100−import GHC.Generics (Generic)
101−import System.Random (randomRIO)
102−import Prelude
103− (Monad, String, Int, (+), ($), (.), return, even, (>), (<=), (==), (>=),
104− subtract, undefined, Maybe(..), Bool(..), not, (>>=), curry,
105− maxBound, div, IO, compare, Double, fromIntegral, Integer, (<$>),
106− (<*>), flip, sqrt, round, (*), seq, const, Either(..))
107−import qualified Prelude as P
108−import qualified Data.Foldable as F
109−import qualified GHC.Exts as GHC
110−
111−#ifdef INSPECTION
112−import GHC.Types (SPEC(..))
113−import Test.Inspection
114−
115−import qualified Streamly.Internal.Data.Stream.StreamD as D
116−#endif
117−
118−import qualified Streamly as S hiding (runStream)
119−import qualified Streamly.Prelude as S
120−import qualified Streamly.Internal.Prelude as Internal
121−import qualified Streamly.Internal.Data.Fold as FL
122−import qualified Streamly.Internal.Data.Unfold as UF
123−import qualified Streamly.Internal.Data.Pipe as Pipe
124−import qualified Streamly.Internal.Data.Stream.Parallel as Par
125−import Streamly.Internal.Data.Time.Units
126−
127−import qualified Streamly.Internal.Prelude as IP
128−
129−import qualified Streamly.Benchmark.Prelude.NestedOps as Nested
130−
131−import Gauge
132−import Streamly hiding (runStream)
133−import Streamly.Benchmark.Common
134−
135−type Stream m a = S.SerialT m a
136−
137−-------------------------------------------------------------------------------
138−-- Stream generation
139−-------------------------------------------------------------------------------
140−
141−-- enumerate
142−
143−{-# INLINE sourceIntFromTo #-}
144−sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
145−sourceIntFromTo value n = S.enumerateFromTo n (n + value)
146−
147−{-# INLINE sourceIntFromThenTo #-}
148−sourceIntFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
149−sourceIntFromThenTo value n = S.enumerateFromThenTo n (n + 1) (n + value)
150−
151−{-# INLINE sourceFracFromTo #-}
152−sourceFracFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double
153−sourceFracFromTo value n =
154− S.enumerateFromTo (fromIntegral n) (fromIntegral (n + value))
155−
156−{-# INLINE sourceFracFromThenTo #-}
157−sourceFracFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double
158−sourceFracFromThenTo value n = S.enumerateFromThenTo (fromIntegral n)
159− (fromIntegral n + 1.0001) (fromIntegral (n + value))
160−
161−{-# INLINE sourceIntegerFromStep #-}
162−sourceIntegerFromStep :: (Monad m, S.IsStream t) => Int -> Int -> t m Integer
163−sourceIntegerFromStep value n =
164− S.take value $ S.enumerateFromThen (fromIntegral n) (fromIntegral n + 1)
165−
166−-- unfoldr
167−
168−{-# INLINE sourceUnfoldr #-}
169−sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
170−sourceUnfoldr value n = S.unfoldr step n
171− where
172− step cnt =
173− if cnt > n + value
174− then Nothing
175− else Just (cnt, cnt + 1)
176−
177−{-# INLINE sourceUnfoldrN #-}
178−sourceUnfoldrN :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
179−sourceUnfoldrN upto start = S.unfoldr step start
180− where
181− step cnt =
182− if cnt > start + upto
183− then Nothing
184− else Just (cnt, cnt + 1)
185−
186−{-# INLINE sourceUnfoldrM #-}
187−sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
188−sourceUnfoldrM value n = S.unfoldrM step n
189− where
190− step cnt =
191− if cnt > n + value
192− then return Nothing
193− else return (Just (cnt, cnt + 1))
194−
195−{-# INLINE source #-}
196−source :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
197−source = sourceUnfoldrM
198−
199−{-# INLINE sourceUnfoldrMN #-}
200−sourceUnfoldrMN :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
201−sourceUnfoldrMN upto start = S.unfoldrM step start
202− where
203− step cnt =
204− if cnt > start + upto
205− then return Nothing
206− else return (Just (cnt, cnt + 1))
207−
208−{-# INLINE sourceUnfoldrMAction #-}
209−sourceUnfoldrMAction :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (m Int)
210−sourceUnfoldrMAction value n = S.serially $ S.unfoldrM step n
211− where
212− step cnt =
213− if cnt > n + value
214− then return Nothing
215− else return (Just (return cnt, cnt + 1))
216−
217−{-# INLINE sourceUnfoldrAction #-}
218−sourceUnfoldrAction :: (S.IsStream t, Monad m, Monad m1)
219− => Int -> Int -> t m (m1 Int)
220−sourceUnfoldrAction value n = S.serially $ S.unfoldr step n
221− where
222− step cnt =
223− if cnt > n + value
224− then Nothing
225− else (Just (return cnt, cnt + 1))
226−
227−-- fromIndices
228−
229−{-# INLINE _sourceFromIndices #-}
230−_sourceFromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
231−_sourceFromIndices value n = S.take value $ S.fromIndices (+ n)
232−
233−{-# INLINE _sourceFromIndicesM #-}
234−_sourceFromIndicesM :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
235−_sourceFromIndicesM value n = S.take value $ S.fromIndicesM (P.fmap return (+ n))
236−
237−-- fromList
238−
239−{-# INLINE sourceFromList #-}
240−sourceFromList :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
241−sourceFromList value n = S.fromList [n..n+value]
242−
243−{-# INLINE sourceFromListM #-}
244−sourceFromListM :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
245−sourceFromListM value n = S.fromListM (P.fmap return [n..n+value])
246−
247−{-# INLINE sourceIsList #-}
248−sourceIsList :: Int -> Int -> S.SerialT Identity Int
249−sourceIsList value n = GHC.fromList [n..n+value]
250−
251−{-# INLINE sourceIsString #-}
252−sourceIsString :: Int -> Int -> S.SerialT Identity P.Char
253−sourceIsString value n = GHC.fromString (P.replicate (n + value) 'a')
254−
255−-- fromFoldable
256−
257−{-# INLINE sourceFromFoldable #-}
258−sourceFromFoldable :: S.IsStream t => Int -> Int -> t m Int
259−sourceFromFoldable value n = S.fromFoldable [n..n+value]
260−
261−{-# INLINE sourceFromFoldableM #-}
262−sourceFromFoldableM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
263−sourceFromFoldableM value n = S.fromFoldableM (P.fmap return [n..n+value])
264−
265−{-# INLINE absTimes #-}
266−absTimes :: (S.IsStream t, S.MonadAsync m, P.Functor (t m))
267− => Int -> Int -> t m AbsTime
268−absTimes value _ = S.take value $ Internal.absTimes
269−
270−-------------------------------------------------------------------------------
271−-- Elimination
272−-------------------------------------------------------------------------------
273−
274−{-# INLINE runStream #-}
275−runStream :: Monad m => Stream m a -> m ()
276−runStream = S.drain
277−
278−{-# INLINE toNull #-}
279−toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m ()
280−toNull t = runStream . t
281−
282−{-# INLINE uncons #-}
283−uncons :: Monad m => Stream m Int -> m ()
284−uncons s = do
285− r <- S.uncons s
286− case r of
287− Nothing -> return ()
288− Just (_, t) -> uncons t
289−
290−{-# INLINE init #-}
291−init :: Monad m => Stream m a -> m ()
292−init s = S.init s >>= P.mapM_ S.drain
293−
294−{-# INLINE tail #-}
295−tail :: Monad m => Stream m a -> m ()
296−tail s = S.tail s >>= P.mapM_ tail
297−
298−{-# INLINE nullHeadTail #-}
299−nullHeadTail :: Monad m => Stream m Int -> m ()
300−nullHeadTail s = do
301− r <- S.null s
302− when (not r) $ do
303− _ <- S.head s
304− S.tail s >>= P.mapM_ nullHeadTail
305−
306−{-# INLINE mapM_ #-}
307−mapM_ :: Monad m => Stream m Int -> m ()
308−mapM_ = S.mapM_ (\_ -> return ())
309−
310−{-# INLINE toList #-}
311−toList :: Monad m => Stream m Int -> m [Int]
312−toList = S.toList
313−
314−{-# INLINE toListRev #-}
315−toListRev :: Monad m => Stream m Int -> m [Int]
316−toListRev = Internal.toListRev
317−
318−{-# INLINE foldrMElem #-}
319−foldrMElem :: Monad m => Int -> Stream m Int -> m Bool
320−foldrMElem e m =
321− S.foldrM
322− (\x xs ->
323− if x == e
324− then return P.True
325− else xs)
326− (return P.False)
327− m
328−
329−{-# INLINE foldrMToStream #-}
330−foldrMToStream :: Monad m => Stream m Int -> m (Stream Identity Int)
331−foldrMToStream = S.foldr S.cons S.nil
332−
333−{-# INLINE foldrMBuild #-}
334−foldrMBuild :: Monad m => Stream m Int -> m [Int]
335−foldrMBuild = S.foldrM (\x xs -> xs >>= return . (x :)) (return [])
336−
337−{-# INLINE foldl'Build #-}
338−foldl'Build :: Monad m => Stream m Int -> m [Int]
339−foldl'Build = S.foldl' (flip (:)) []
340−
341−{-# INLINE foldlM'Build #-}
342−foldlM'Build :: Monad m => Stream m Int -> m [Int]
343−foldlM'Build = S.foldlM' (\xs x -> return $ x : xs) []
344−
345−{-# INLINE foldrMReduce #-}
346−foldrMReduce :: Monad m => Stream m Int -> m Int
347−foldrMReduce = S.foldrM (\x xs -> xs >>= return . (x +)) (return 0)
348−
349−{-# INLINE foldl'Reduce #-}
350−foldl'Reduce :: Monad m => Stream m Int -> m Int
351−foldl'Reduce = S.foldl' (+) 0
352−
353−{-# INLINE foldl'ReduceMap #-}
354−foldl'ReduceMap :: Monad m => Stream m Int -> m Int
355−foldl'ReduceMap = P.fmap (+ 1) . S.foldl' (+) 0
356−
357−{-# INLINE foldl1'Reduce #-}
358−foldl1'Reduce :: Monad m => Stream m Int -> m (Maybe Int)
359−foldl1'Reduce = S.foldl1' (+)
360−
361−{-# INLINE foldlM'Reduce #-}
362−foldlM'Reduce :: Monad m => Stream m Int -> m Int
363−foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
364−
365−{-# INLINE last #-}
366−last :: Monad m => Stream m Int -> m (Maybe Int)
367−last = S.last
368−
369−{-# INLINE _null #-}
370−_null :: Monad m => Stream m Int -> m Bool
371−_null = S.null
372−
373−{-# INLINE _head #-}
374−_head :: Monad m => Stream m Int -> m (Maybe Int)
375−_head = S.head
376−
377−{-# INLINE elem #-}
378−elem :: Monad m => Int -> Stream m Int -> m Bool
379−elem value = S.elem (value + 1)
380−
381−{-# INLINE notElem #-}
382−notElem :: Monad m => Int -> Stream m Int -> m Bool
383−notElem value = S.notElem (value + 1)
384−
385−{-# INLINE length #-}
386−length :: Monad m => Stream m Int -> m Int
387−length = S.length
388−
389−{-# INLINE all #-}
390−all :: Monad m => Int -> Stream m Int -> m Bool
391−all value = S.all (<= (value + 1))
392−
393−{-# INLINE any #-}
394−any :: Monad m => Int -> Stream m Int -> m Bool
395−any value = S.any (> (value + 1))
396−
397−{-# INLINE and #-}
398−and :: Monad m => Int -> Stream m Int -> m Bool
399−and value = S.and . S.map (<= (value + 1))
400−
401−{-# INLINE or #-}
402−or :: Monad m => Int -> Stream m Int -> m Bool
403−or value = S.or . S.map (> (value + 1))
404−
405−{-# INLINE find #-}
406−find :: Monad m => Int -> Stream m Int -> m (Maybe Int)
407−find value = S.find (== (value + 1))
408−
409−{-# INLINE findIndex #-}
410−findIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int)
411−findIndex value = S.findIndex (== (value + 1))
412−
413−{-# INLINE elemIndex #-}
414−elemIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int)
415−elemIndex value = S.elemIndex (value + 1)
416−
417−{-# INLINE maximum #-}
418−maximum :: Monad m => Stream m Int -> m (Maybe Int)
419−maximum = S.maximum
420−
421−{-# INLINE minimum #-}
422−minimum :: Monad m => Stream m Int -> m (Maybe Int)
423−minimum = S.minimum
424−
425−{-# INLINE sum #-}
426−sum :: Monad m => Stream m Int -> m Int
427−sum = S.sum
428−
429−{-# INLINE product #-}
430−product :: Monad m => Stream m Int -> m Int
431−product = S.product
432−
433−{-# INLINE minimumBy #-}
434−minimumBy :: Monad m => Stream m Int -> m (Maybe Int)
435−minimumBy = S.minimumBy compare
436−
437−{-# INLINE maximumBy #-}
438−maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
439−maximumBy = S.maximumBy compare
440−
441−-------------------------------------------------------------------------------
442−-- Transformation
443−-------------------------------------------------------------------------------
444−
445−{-# INLINE transform #-}
446−transform :: Monad m => Stream m a -> m ()
447−transform = runStream
448−
449−{-# INLINE composeN #-}
450−composeN ::
451− MonadIO m
452− => Int
453− -> (Stream m Int -> Stream m Int)
454− -> Stream m Int
455− -> m ()
456−composeN n f =
457− case n of
458− 1 -> transform . f
459− 2 -> transform . f . f
460− 3 -> transform . f . f . f
461− 4 -> transform . f . f . f . f
462− _ -> undefined
463−
464−-- polymorphic stream version of composeN
465−{-# INLINE composeN' #-}
466−composeN' ::
467− (S.IsStream t, Monad m)
468− => Int
469− -> (t m Int -> Stream m Int)
470− -> t m Int
471− -> m ()
472−composeN' n f =
473− case n of
474− 1 -> transform . f
475− 2 -> transform . f . S.adapt . f
476− 3 -> transform . f . S.adapt . f . S.adapt . f
477− 4 -> transform . f . S.adapt . f . S.adapt . f . S.adapt . f
478− _ -> undefined
479−
480−{-# INLINE scan #-}
481−scan :: MonadIO m => Int -> Stream m Int -> m ()
482−scan n = composeN n $ S.scanl' (+) 0
483−
484−{-# INLINE scanl1' #-}
485−scanl1' :: MonadIO m => Int -> Stream m Int -> m ()
486−scanl1' n = composeN n $ S.scanl1' (+)
487−
488−{-# INLINE fmap #-}
489−fmap :: MonadIO m => Int -> Stream m Int -> m ()
490−fmap n = composeN n $ P.fmap (+ 1)
491−
492−{-# INLINE fmap' #-}
493−fmap' ::
494− (S.IsStream t, S.MonadAsync m, P.Functor (t m))
495− => (t m Int -> S.SerialT m Int)
496− -> Int
497− -> t m Int
498− -> m ()
499−fmap' t n = composeN' n $ t . P.fmap (+ 1)
500−
501−{-# INLINE map #-}
502−map :: MonadIO m => Int -> Stream m Int -> m ()
503−map n = composeN n $ S.map (+ 1)
504−
505−{-# INLINE map' #-}
506−map' ::
507− (S.IsStream t, S.MonadAsync m)
508− => (t m Int -> S.SerialT m Int)
509− -> Int
510− -> t m Int
511− -> m ()
512−map' t n = composeN' n $ t . S.map (+ 1)
513−
514−{-# INLINE mapM #-}
515−mapM ::
516− (S.IsStream t, S.MonadAsync m)
517− => (t m Int -> S.SerialT m Int)
518− -> Int
519− -> t m Int
520− -> m ()
521−mapM t n = composeN' n $ t . S.mapM return
522−
523−{-# INLINE tap #-}
524−tap :: MonadIO m => Int -> Stream m Int -> m ()
525−tap n = composeN n $ S.tap FL.sum
526−
527−{-# INLINE tapRate #-}
528−tapRate :: Int -> Stream IO Int -> IO ()
529−tapRate n str = do
530− cref <- newIORef 0
531− composeN n (Internal.tapRate 1 (\c -> modifyIORef' cref (c +))) str
532−
533−{-# INLINE pollCounts #-}
534−pollCounts :: Int -> Stream IO Int -> IO ()
535−pollCounts n str = do
536− composeN n (Internal.pollCounts (P.const P.True) f FL.drain) str
537− where
538− f = Internal.rollingMap (P.-) . Internal.delayPost 1
539−
540−{-# INLINE tapAsyncS #-}
541−tapAsyncS :: S.MonadAsync m => Int -> Stream m Int -> m ()
542−tapAsyncS n = composeN n $ Par.tapAsync S.sum
543−
544−{-# INLINE tapAsync #-}
545−tapAsync :: S.MonadAsync m => Int -> Stream m Int -> m ()
546−tapAsync n = composeN n $ Internal.tapAsync FL.sum
547−
548−{-# INLINE timestamped #-}
549−timestamped :: (S.MonadAsync m) => Stream m Int -> m ()
550−timestamped = transform . Internal.timestamped
551−
552−{-# INLINE classifySessionsOf #-}
553−classifySessionsOf :: (S.MonadAsync m) => Stream m Int -> m ()
554−classifySessionsOf =
555− transform
556− . IP.classifySessionsOf 3 (const (return False)) (P.fmap Right FL.drain)
557− . S.map (\(ts,(k,a)) -> (k, a, ts))
558− . IP.timestamped
559− . S.concatMap (\x -> S.map (x,) (S.enumerateFromTo 1 (10 :: Int)))
560−
561−{-# INLINE mapMaybe #-}
562−mapMaybe :: MonadIO m => Int -> Stream m Int -> m ()
563−mapMaybe n =
564− composeN n $
565− S.mapMaybe
566− (\x ->
567− if P.odd x
568− then Nothing
569− else Just x)
570−
571−{-# INLINE mapMaybeM #-}
572−mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
573−mapMaybeM n =
574− composeN n $
575− S.mapMaybeM
576− (\x ->
577− if P.odd x
578− then return Nothing
579− else return $ Just x)
580−
581−{-# INLINE sequence #-}
582−sequence ::
583− (S.IsStream t, S.MonadAsync m)
584− => (t m Int -> S.SerialT m Int)
585− -> t m (m Int)
586− -> m ()
587−sequence t = transform . t . S.sequence
588−
589−{-# INLINE filterEven #-}
590−filterEven :: MonadIO m => Int -> Stream m Int -> m ()
591−filterEven n = composeN n $ S.filter even
592−
593−{-# INLINE filterAllOut #-}
594−filterAllOut :: MonadIO m => Int -> Int -> Stream m Int -> m ()
595−filterAllOut value n = composeN n $ S.filter (> (value + 1))
596−
597−{-# INLINE filterAllIn #-}
598−filterAllIn :: MonadIO m => Int -> Int -> Stream m Int -> m ()
599−filterAllIn value n = composeN n $ S.filter (<= (value + 1))
600−
601−{-# INLINE _takeOne #-}
602−_takeOne :: MonadIO m => Int -> Stream m Int -> m ()
603−_takeOne n = composeN n $ S.take 1
604−
605−{-# INLINE takeAll #-}
606−takeAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
607−takeAll value n = composeN n $ S.take (value + 1)
608−
609−{-# INLINE takeWhileTrue #-}
610−takeWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
611−takeWhileTrue value n = composeN n $ S.takeWhile (<= (value + 1))
612−
613−{-# INLINE _takeWhileMTrue #-}
614−_takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
615−_takeWhileMTrue value n = composeN n $ S.takeWhileM (return . (<= (value + 1)))
616−
617−{-# INLINE dropOne #-}
618−dropOne :: MonadIO m => Int -> Stream m Int -> m ()
619−dropOne n = composeN n $ S.drop 1
620−
621−{-# INLINE dropAll #-}
622−dropAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
623−dropAll value n = composeN n $ S.drop (value + 1)
624−
625−{-# INLINE dropWhileTrue #-}
626−dropWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
627−dropWhileTrue value n = composeN n $ S.dropWhile (<= (value + 1))
628−
629−{-# INLINE _dropWhileMTrue #-}
630−_dropWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
631−_dropWhileMTrue value n = composeN n $ S.dropWhileM (return . (<= (value + 1)))
632−
633−{-# INLINE dropWhileFalse #-}
634−dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m ()
635−dropWhileFalse value n = composeN n $ S.dropWhile (> (value + 1))
636−
637−{-# INLINE findIndices #-}
638−findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
639−findIndices value n = composeN n $ S.findIndices (== (value + 1))
640−
641−{-# INLINE elemIndices #-}
642−elemIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
643−elemIndices value n = composeN n $ S.elemIndices (value + 1)
644−
645−{-# INLINE intersperse #-}
646−intersperse :: S.MonadAsync m => Int -> Int -> Stream m Int -> m ()
647−intersperse value n = composeN n $ S.intersperse (value + 1)
648−
649−{-# INLINE insertBy #-}
650−insertBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
651−insertBy value n = composeN n $ S.insertBy compare (value + 1)
652−
653−{-# INLINE deleteBy #-}
654−deleteBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
655−deleteBy value n = composeN n $ S.deleteBy (>=) (value + 1)
656−
657−{-# INLINE reverse #-}
658−reverse :: MonadIO m => Int -> Stream m Int -> m ()
659−reverse n = composeN n $ S.reverse
660−
661−{-# INLINE reverse' #-}
662−reverse' :: MonadIO m => Int -> Stream m Int -> m ()
663−reverse' n = composeN n $ Internal.reverse'
664−
665−{-# INLINE foldrS #-}
666−foldrS :: MonadIO m => Int -> Stream m Int -> m ()
667−foldrS n = composeN n $ Internal.foldrS S.cons S.nil
668−
669−{-# INLINE foldrSMap #-}
670−foldrSMap :: MonadIO m => Int -> Stream m Int -> m ()
671−foldrSMap n = composeN n $ Internal.foldrS (\x xs -> x + 1 `S.cons` xs) S.nil
672−
673−{-# INLINE foldrT #-}
674−foldrT :: MonadIO m => Int -> Stream m Int -> m ()
675−foldrT n = composeN n $ Internal.foldrT S.cons S.nil
676−
677−{-# INLINE foldrTMap #-}
678−foldrTMap :: MonadIO m => Int -> Stream m Int -> m ()
679−foldrTMap n = composeN n $ Internal.foldrT (\x xs -> x + 1 `S.cons` xs) S.nil
680−
681−{-# INLINE takeByTime #-}
682−takeByTime :: NanoSecond64 -> Int -> Stream IO Int -> IO ()
683−takeByTime i n = composeN n (Internal.takeByTime i)
684−
685−#ifdef INSPECTION
686−-- inspect $ hasNoType 'takeByTime ''SPEC
687−inspect $ hasNoTypeClasses 'takeByTime
688−-- inspect $ 'takeByTime `hasNoType` ''D.Step
689−#endif
690−
691−{-# INLINE dropByTime #-}
692−dropByTime :: NanoSecond64 -> Int -> Stream IO Int -> IO ()
693−dropByTime i n = composeN n (Internal.dropByTime i)
694−
695−#ifdef INSPECTION
696−inspect $ hasNoTypeClasses 'dropByTime
697−-- inspect $ 'dropByTime `hasNoType` ''D.Step
698−#endif
699−
700−-------------------------------------------------------------------------------
701−-- Pipes
702−-------------------------------------------------------------------------------
703−
704−{-# INLINE transformMapM #-}
705−transformMapM ::
706− (S.IsStream t, S.MonadAsync m)
707− => (t m Int -> S.SerialT m Int)
708− -> Int
709− -> t m Int
710− -> m ()
711−transformMapM t n = composeN' n $ t . Internal.transform (Pipe.mapM return)
712−
713−{-# INLINE transformComposeMapM #-}
714−transformComposeMapM ::
715− (S.IsStream t, S.MonadAsync m)
716− => (t m Int -> S.SerialT m Int)
717− -> Int
718− -> t m Int
719− -> m ()
720−transformComposeMapM t n =
721− composeN' n $
722− t .
723− Internal.transform
724− (Pipe.mapM (\x -> return (x + 1)) `Pipe.compose`
725− Pipe.mapM (\x -> return (x + 2)))
726−
727−{-# INLINE transformTeeMapM #-}
728−transformTeeMapM ::
729− (S.IsStream t, S.MonadAsync m)
730− => (t m Int -> S.SerialT m Int)
731− -> Int
732− -> t m Int
733− -> m ()
734−transformTeeMapM t n =
735− composeN' n $
736− t .
737− Internal.transform
738− (Pipe.mapM (\x -> return (x + 1)) `Pipe.tee`
739− Pipe.mapM (\x -> return (x + 2)))
740−
741−{-# INLINE transformZipMapM #-}
742−transformZipMapM ::
743− (S.IsStream t, S.MonadAsync m)
744− => (t m Int -> S.SerialT m Int)
745− -> Int
746− -> t m Int
747− -> m ()
748−transformZipMapM t n =
749− composeN' n $
750− t .
751− Internal.transform
752− (Pipe.zipWith
753− (+)
754− (Pipe.mapM (\x -> return (x + 1)))
755− (Pipe.mapM (\x -> return (x + 2))))
756−
757−-------------------------------------------------------------------------------
758−-- Mixed Transformation
759−-------------------------------------------------------------------------------
760−
761−{-# INLINE scanMap #-}
762−scanMap :: MonadIO m => Int -> Stream m Int -> m ()
763−scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
764−
765−{-# INLINE dropMap #-}
766−dropMap :: MonadIO m => Int -> Stream m Int -> m ()
767−dropMap n = composeN n $ S.map (subtract 1) . S.drop 1
768−
769−{-# INLINE dropScan #-}
770−dropScan :: MonadIO m => Int -> Stream m Int -> m ()
771−dropScan n = composeN n $ S.scanl' (+) 0 . S.drop 1
772−
773−{-# INLINE takeDrop #-}
774−takeDrop :: MonadIO m => Int -> Int -> Stream m Int -> m ()
775−takeDrop value n = composeN n $ S.drop 1 . S.take (value + 1)
776−
777−{-# INLINE takeScan #-}
778−takeScan :: MonadIO m => Int -> Int -> Stream m Int -> m ()
779−takeScan value n = composeN n $ S.scanl' (+) 0 . S.take (value + 1)
780−
781−{-# INLINE takeMap #-}
782−takeMap :: MonadIO m => Int -> Int -> Stream m Int -> m ()
783−takeMap value n = composeN n $ S.map (subtract 1) . S.take (value + 1)
784−
785−{-# INLINE filterDrop #-}
786−filterDrop :: MonadIO m => Int -> Int -> Stream m Int -> m ()
787−filterDrop value n = composeN n $ S.drop 1 . S.filter (<= (value + 1))
788−
789−{-# INLINE filterTake #-}
790−filterTake :: MonadIO m => Int -> Int -> Stream m Int -> m ()
791−filterTake value n = composeN n $ S.take (value + 1) . S.filter (<= (value + 1))
792−
793−{-# INLINE filterScan #-}
794−filterScan :: MonadIO m => Int -> Stream m Int -> m ()
795−filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
796−
797−{-# INLINE filterScanl1 #-}
798−filterScanl1 :: MonadIO m => Int -> Stream m Int -> m ()
799−filterScanl1 n = composeN n $ S.scanl1' (+) . S.filter (<= maxBound)
800−
801−{-# INLINE filterMap #-}
802−filterMap :: MonadIO m => Int -> Int -> Stream m Int -> m ()
803−filterMap value n = composeN n $ S.map (subtract 1) . S.filter (<= (value + 1))
804−
805−-------------------------------------------------------------------------------
806−-- Scan and fold
807−-------------------------------------------------------------------------------
808−
809−data Pair a b =
810− Pair !a !b
811− deriving (Generic, NFData)
812−
813−{-# INLINE sumProductFold #-}
814−sumProductFold :: Monad m => Stream m Int -> m (Int, Int)
815−sumProductFold = S.foldl' (\(s, p) x -> (s + x, p P.* x)) (0, 1)
816−
817−{-# INLINE sumProductScan #-}
818−sumProductScan :: Monad m => Stream m Int -> m (Pair Int Int)
819−sumProductScan =
820− S.foldl' (\(Pair _ p) (s0, x) -> Pair s0 (p P.* x)) (Pair 0 1) .
821− S.scanl' (\(s, _) x -> (s + x, x)) (0, 0)
822−
823−-------------------------------------------------------------------------------
824−-- Iteration
825−-------------------------------------------------------------------------------
826−
827−{-# INLINE iterStreamLen #-}
828−iterStreamLen :: Int
829−iterStreamLen = 10
830−
831−{-# INLINE maxIters #-}
832−maxIters :: Int
833−maxIters = 10000
834−
835−{-# INLINE iterateSource #-}
836−iterateSource ::
837− S.MonadAsync m
838− => (Stream m Int -> Stream m Int)
839− -> Int
840− -> Int
841− -> Stream m Int
842−iterateSource g i n = f i (sourceUnfoldrMN iterStreamLen n)
843− where
844− f (0 :: Int) m = g m
845− f x m = g (f (x P.- 1) m)
846−
847−-- this is quadratic
848−{-# INLINE iterateScan #-}
849−iterateScan :: S.MonadAsync m => Int -> Stream m Int
850−iterateScan = iterateSource (S.scanl' (+) 0) (maxIters `div` 10)
851−
852−-- this is quadratic
853−{-# INLINE iterateScanl1 #-}
854−iterateScanl1 :: S.MonadAsync m => Int -> Stream m Int
855−iterateScanl1 = iterateSource (S.scanl1' (+)) (maxIters `div` 10)
856−
857−{-# INLINE iterateMapM #-}
858−iterateMapM :: S.MonadAsync m => Int -> Stream m Int
859−iterateMapM = iterateSource (S.mapM return) maxIters
860−
861−{-# INLINE iterateFilterEven #-}
862−iterateFilterEven :: S.MonadAsync m => Int -> Stream m Int
863−iterateFilterEven = iterateSource (S.filter even) maxIters
864−
865−{-# INLINE iterateTakeAll #-}
866−iterateTakeAll :: S.MonadAsync m => Int -> Int -> Stream m Int
867−iterateTakeAll value = iterateSource (S.take (value + 1)) maxIters
868−
869−{-# INLINE iterateDropOne #-}
870−iterateDropOne :: S.MonadAsync m => Int -> Stream m Int
871−iterateDropOne = iterateSource (S.drop 1) maxIters
872−
873−{-# INLINE iterateDropWhileFalse #-}
874−iterateDropWhileFalse :: S.MonadAsync m => Int -> Int -> Stream m Int
875−iterateDropWhileFalse value =
876− iterateSource (S.dropWhile (> (value + 1))) maxIters
877−
878−{-# INLINE iterateDropWhileTrue #-}
879−iterateDropWhileTrue :: S.MonadAsync m => Int -> Int -> Stream m Int
880−iterateDropWhileTrue value =
881− iterateSource (S.dropWhile (<= (value + 1))) maxIters
882−
883−-------------------------------------------------------------------------------
884−-- Combining streams
885−-------------------------------------------------------------------------------
886−
887−-------------------------------------------------------------------------------
888−-- Appending
889−-------------------------------------------------------------------------------
890−
891−{-# INLINE serial2 #-}
892−serial2 :: Int -> Int -> IO ()
893−serial2 count n =
894− S.drain $ S.serial (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
895−
896−{-# INLINE serial4 #-}
897−serial4 :: Int -> Int -> IO ()
898−serial4 count n =
899− S.drain $
900− S.serial
901− ((S.serial (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))))
902− ((S.serial
903− (sourceUnfoldrMN count (n + 2))
904− (sourceUnfoldrMN count (n + 3))))
905−
906−{-# INLINE append2 #-}
907−append2 :: Int -> Int -> IO ()
908−append2 count n =
909− S.drain $
910− Internal.append (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
911−
912−{-# INLINE append4 #-}
913−append4 :: Int -> Int -> IO ()
914−append4 count n =
915− S.drain $
916− Internal.append
917− ((Internal.append
918− (sourceUnfoldrMN count n)
919− (sourceUnfoldrMN count (n + 1))))
920− ((Internal.append
921− (sourceUnfoldrMN count (n + 2))
922− (sourceUnfoldrMN count (n + 3))))
923−
924−#ifdef INSPECTION
925−inspect $ hasNoTypeClasses 'append2
926−inspect $ 'append2 `hasNoType` ''SPEC
927−inspect $ 'append2 `hasNoType` ''D.AppendState
928−#endif
929−
930−-------------------------------------------------------------------------------
931−-- Interleaving
932−-------------------------------------------------------------------------------
933−
934−{-# INLINE wSerial2 #-}
935−wSerial2 :: Int -> Int -> IO ()
936−wSerial2 value n =
937− S.drain $
938− S.wSerial
939− (sourceUnfoldrMN (value `div` 2) n)
940− (sourceUnfoldrMN (value `div` 2) (n + 1))
941−
942−{-# INLINE interleave2 #-}
943−interleave2 :: Int -> Int -> IO ()
944−interleave2 value n =
945− S.drain $
946− Internal.interleave
947− (sourceUnfoldrMN (value `div` 2) n)
948− (sourceUnfoldrMN (value `div` 2) (n + 1))
949−
950−#ifdef INSPECTION
951−inspect $ hasNoTypeClasses 'interleave2
952−inspect $ 'interleave2 `hasNoType` ''SPEC
953−inspect $ 'interleave2 `hasNoType` ''D.InterleaveState
954−#endif
955−
956−{-# INLINE roundRobin2 #-}
957−roundRobin2 :: Int -> Int -> IO ()
958−roundRobin2 value n =
959− S.drain $
960− Internal.roundrobin
961− (sourceUnfoldrMN (value `div` 2) n)
962− (sourceUnfoldrMN (value `div` 2) (n + 1))
963−
964−#ifdef INSPECTION
965−inspect $ hasNoTypeClasses 'roundRobin2
966−inspect $ 'roundRobin2 `hasNoType` ''SPEC
967−inspect $ 'roundRobin2 `hasNoType` ''D.InterleaveState
968−#endif
969−
970−-------------------------------------------------------------------------------
971−-- Merging
972−-------------------------------------------------------------------------------
973−
974−{-# INLINE mergeBy #-}
975−mergeBy :: Int -> Int -> IO ()
976−mergeBy count n =
977− S.drain $
978− S.mergeBy
979− P.compare
980− (sourceUnfoldrMN count n)
981− (sourceUnfoldrMN count (n + 1))
982−
983−#ifdef INSPECTION
984−inspect $ hasNoTypeClasses 'mergeBy
985−inspect $ 'mergeBy `hasNoType` ''SPEC
986−inspect $ 'mergeBy `hasNoType` ''D.Step
987−#endif
988−
989−-------------------------------------------------------------------------------
990−-- Zipping
991−-------------------------------------------------------------------------------
992−
993−{-# INLINE zip #-}
994−zip :: Int -> Int -> IO ()
995−zip count n =
996− S.drain $
997− S.zipWith (,) (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
998−
999−#ifdef INSPECTION
1000−inspect $ hasNoTypeClasses 'zip
1001−inspect $ 'zip `hasNoType` ''SPEC
1002−inspect $ 'zip `hasNoType` ''D.Step
1003−#endif
1004−
1005−{-# INLINE zipM #-}
1006−zipM :: Int -> Int -> IO ()
1007−zipM count n =
1008− S.drain $
1009− S.zipWithM
1010− (curry return)
1011− (sourceUnfoldrMN count n)
1012− (sourceUnfoldrMN count (n + 1))
1013−
1014−#ifdef INSPECTION
1015−inspect $ hasNoTypeClasses 'zipM
1016−inspect $ 'zipM `hasNoType` ''SPEC
1017−inspect $ 'zipM `hasNoType` ''D.Step
1018−#endif
1019−
1020−{-# INLINE zipAsync #-}
1021−zipAsync :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
1022−zipAsync count n = do
1023− S.zipAsyncWith (,) (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
1024−
1025−{-# INLINE zipAsyncM #-}
1026−zipAsyncM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
1027−zipAsyncM count n = do
1028− S.zipAsyncWithM
1029− (curry return)
1030− (sourceUnfoldrMN count n)
1031− (sourceUnfoldrMN count (n + 1))
1032−
1033−{-# INLINE zipAsyncAp #-}
1034−zipAsyncAp :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
1035−zipAsyncAp count n = do
1036− S.zipAsyncly $
1037− (,) <$> (sourceUnfoldrMN count n) <*> (sourceUnfoldrMN count (n + 1))
1038−
1039−{-# INLINE mergeAsyncByM #-}
1040−mergeAsyncByM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
1041−mergeAsyncByM count n = do
1042− S.mergeAsyncByM
1043− (\a b -> return (a `compare` b))
1044− (sourceUnfoldrMN count n)
1045− (sourceUnfoldrMN count (n + 1))
1046−
1047−{-# INLINE mergeAsyncBy #-}
1048−mergeAsyncBy :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
1049−mergeAsyncBy count n = do
1050− S.mergeAsyncBy
1051− compare
1052− (sourceUnfoldrMN count n)
1053− (sourceUnfoldrMN count (n + 1))
1054−
1055−-------------------------------------------------------------------------------
1056−-- Multi-stream folds
1057−-------------------------------------------------------------------------------
1058−
1059−{-# INLINE isPrefixOf #-}
1060−isPrefixOf :: Monad m => Stream m Int -> m Bool
1061−isPrefixOf src = S.isPrefixOf src src
1062−
1063−{-# INLINE isSubsequenceOf #-}
1064−isSubsequenceOf :: Monad m => Stream m Int -> m Bool
1065−isSubsequenceOf src = S.isSubsequenceOf src src
1066−
1067−{-# INLINE stripPrefix #-}
1068−stripPrefix :: Monad m => Stream m Int -> m ()
1069−stripPrefix src = do
1070− _ <- S.stripPrefix src src
1071− return ()
1072−
1073−{-# INLINE eqBy' #-}
1074−eqBy' :: (Monad m, P.Eq a) => Stream m a -> m P.Bool
1075−eqBy' src = S.eqBy (==) src src
1076−
1077−{-# INLINE eqBy #-}
1078−eqBy :: Int -> Int -> IO Bool
1079−eqBy value n = eqBy' (source value n)
1080−
1081−#ifdef INSPECTION
1082−inspect $ hasNoTypeClasses 'eqBy
1083−inspect $ 'eqBy `hasNoType` ''SPEC
1084−inspect $ 'eqBy `hasNoType` ''D.Step
1085−#endif
1086−
1087−
1088−{-# INLINE eqByPure #-}
1089−eqByPure :: Int -> Int -> Identity Bool
1090−eqByPure value n = eqBy' (sourceUnfoldr value n)
1091−
1092−#ifdef INSPECTION
1093−inspect $ hasNoTypeClasses 'eqByPure
1094−inspect $ 'eqByPure `hasNoType` ''SPEC
1095−inspect $ 'eqByPure `hasNoType` ''D.Step
1096−#endif
1097−
1098−{-# INLINE cmpBy' #-}
1099−cmpBy' :: (Monad m, P.Ord a) => Stream m a -> m P.Ordering
1100−cmpBy' src = S.cmpBy P.compare src src
1101−
1102−{-# INLINE cmpBy #-}
1103−cmpBy :: Int -> Int -> IO P.Ordering
1104−cmpBy value n = cmpBy' (source value n)
1105−
1106−#ifdef INSPECTION
1107−inspect $ hasNoTypeClasses 'cmpBy
1108−inspect $ 'cmpBy `hasNoType` ''SPEC
1109−inspect $ 'cmpBy `hasNoType` ''D.Step
1110−#endif
1111−
1112−{-# INLINE cmpByPure #-}
1113−cmpByPure :: Int -> Int -> Identity P.Ordering
1114−cmpByPure value n = cmpBy' (sourceUnfoldr value n)
1115−
1116−#ifdef INSPECTION
1117−inspect $ hasNoTypeClasses 'cmpByPure
1118−inspect $ 'cmpByPure `hasNoType` ''SPEC
1119−inspect $ 'cmpByPure `hasNoType` ''D.Step
1120−#endif
1121−
1122−-------------------------------------------------------------------------------
1123−-- Streams of streams
1124−-------------------------------------------------------------------------------
1125−
1126−-- Special cases of concatMap
1127−
1128−{-# INLINE sourceFoldMapWith #-}
1129−sourceFoldMapWith :: (S.IsStream t, S.Semigroup (t m Int))
1130− => Int -> Int -> t m Int
1131−sourceFoldMapWith value n = S.foldMapWith (S.<>) S.yield [n..n+value]
1132−
1133−{-# INLINE sourceFoldMapWithM #-}
1134−sourceFoldMapWithM :: (S.IsStream t, Monad m, S.Semigroup (t m Int))
1135− => Int -> Int -> t m Int
1136−sourceFoldMapWithM value n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
1137−
1138−{-# INLINE sourceFoldMapM #-}
1139−sourceFoldMapM :: (S.IsStream t, Monad m, P.Monoid (t m Int))
1140− => Int -> Int -> t m Int
1141−sourceFoldMapM value n = F.foldMap (S.yieldM . return) [n..n+value]
1142−
1143−{-# INLINE sourceConcatMapId #-}
1144−sourceConcatMapId :: (S.IsStream t, Monad m)
1145− => Int -> Int -> t m Int
1146−sourceConcatMapId value n =
1147− S.concatMap P.id $ S.fromFoldable $ P.map (S.yieldM . return) [n..n+value]
1148−
1149−-- concatMap unfoldrM/unfoldrM
1150−
1151−{-# INLINE concatMap #-}
1152−concatMap :: Int -> Int -> Int -> IO ()
1153−concatMap outer inner n =
1154− S.drain $ S.concatMap
1155− (\_ -> sourceUnfoldrMN inner n)
1156− (sourceUnfoldrMN outer n)
1157−
1158−#ifdef INSPECTION
1159−inspect $ hasNoTypeClasses 'concatMap
1160−inspect $ 'concatMap `hasNoType` ''SPEC
1161−#endif
1162−
1163−-- concatMap unfoldr/unfoldr
1164−
1165−{-# INLINE concatMapPure #-}
1166−concatMapPure :: Int -> Int -> Int -> IO ()
1167−concatMapPure outer inner n =
1168− S.drain $ S.concatMap
1169− (\_ -> sourceUnfoldrN inner n)
1170− (sourceUnfoldrN outer n)
1171−
1172−#ifdef INSPECTION
1173−inspect $ hasNoTypeClasses 'concatMapPure
1174−inspect $ 'concatMapPure `hasNoType` ''SPEC
1175−#endif
1176−
1177−-- concatMap replicate/unfoldrM
1178−
1179−{-# INLINE concatMapRepl4xN #-}
1180−concatMapRepl4xN :: Int -> Int -> IO ()
1181−concatMapRepl4xN value n = S.drain $ S.concatMap (S.replicate 4)
1182− (sourceUnfoldrMN (value `div` 4) n)
1183−
1184−#ifdef INSPECTION
1185−inspect $ hasNoTypeClasses 'concatMapRepl4xN
1186−inspect $ 'concatMapRepl4xN `hasNoType` ''SPEC
1187−#endif
1188−
1189−-- concatMapWith
1190−
1191−{-# INLINE concatStreamsWith #-}
1192−concatStreamsWith
1193− :: (forall c. S.SerialT IO c -> S.SerialT IO c -> S.SerialT IO c)
1194− -> Int
1195− -> Int
1196− -> Int
1197− -> IO ()
1198−concatStreamsWith op outer inner n =
1199− S.drain $ S.concatMapWith op
1200− (\i -> sourceUnfoldrMN inner i)
1201− (sourceUnfoldrMN outer n)
1202−
1203−{-# INLINE concatMapWithSerial #-}
1204−concatMapWithSerial :: Int -> Int -> Int -> IO ()
1205−concatMapWithSerial = concatStreamsWith S.serial
1206−
1207−#ifdef INSPECTION
1208−inspect $ hasNoTypeClasses 'concatMapWithSerial
1209−inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
1210−#endif
1211−
1212−{-# INLINE concatMapWithAppend #-}
1213−concatMapWithAppend :: Int -> Int -> Int -> IO ()
1214−concatMapWithAppend = concatStreamsWith Internal.append
1215−
1216−#ifdef INSPECTION
1217−inspect $ hasNoTypeClasses 'concatMapWithAppend
1218−inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
1219−#endif
1220−
1221−{-# INLINE concatMapWithWSerial #-}
1222−concatMapWithWSerial :: Int -> Int -> Int -> IO ()
1223−concatMapWithWSerial = concatStreamsWith S.wSerial
1224−
1225−#ifdef INSPECTION
1226−inspect $ hasNoTypeClasses 'concatMapWithWSerial
1227−inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
1228−#endif
1229−
1230−-- concatUnfold
1231−
1232−-- concatUnfold replicate/unfoldrM
1233−
1234−{-# INLINE concatUnfoldRepl4xN #-}
1235−concatUnfoldRepl4xN :: Int -> Int -> IO ()
1236−concatUnfoldRepl4xN value n =
1237− S.drain $ S.concatUnfold
1238− (UF.replicateM 4)
1239− (sourceUnfoldrMN (value `div` 4) n)
1240−
1241−#ifdef INSPECTION
1242−inspect $ hasNoTypeClasses 'concatUnfoldRepl4xN
1243−inspect $ 'concatUnfoldRepl4xN `hasNoType` ''D.ConcatMapUState
1244−inspect $ 'concatUnfoldRepl4xN `hasNoType` ''SPEC
1245−#endif
1246−
1247−{-# INLINE concatUnfoldInterleaveRepl4xN #-}
1248−concatUnfoldInterleaveRepl4xN :: Int -> Int -> IO ()
1249−concatUnfoldInterleaveRepl4xN value n =
1250− S.drain $ Internal.concatUnfoldInterleave
1251− (UF.replicateM 4)
1252− (sourceUnfoldrMN (value `div` 4) n)
1253−
1254−#ifdef INSPECTION
1255−inspect $ hasNoTypeClasses 'concatUnfoldInterleaveRepl4xN
1256−-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType` ''SPEC
1257−-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType` ''D.ConcatUnfoldInterleaveState
1258−#endif
1259−
1260−{-# INLINE concatUnfoldRoundrobinRepl4xN #-}
1261−concatUnfoldRoundrobinRepl4xN :: Int -> Int -> IO ()
1262−concatUnfoldRoundrobinRepl4xN value n =
1263− S.drain $ Internal.concatUnfoldRoundrobin
1264− (UF.replicateM 4)
1265− (sourceUnfoldrMN (value `div` 4) n)
1266−
1267−#ifdef INSPECTION
1268−inspect $ hasNoTypeClasses 'concatUnfoldRoundrobinRepl4xN
1269−-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType` ''SPEC
1270−-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType` ''D.ConcatUnfoldInterleaveState
1271−#endif
1272−
1273−-------------------------------------------------------------------------------
1274−-- Monad transformation (hoisting etc.)
1275−-------------------------------------------------------------------------------
1276−
1277−{-# INLINE sourceUnfoldrState #-}
1278−sourceUnfoldrState :: (S.IsStream t, S.MonadAsync m)
1279− => Int -> Int -> t (StateT Int m) Int
1280−sourceUnfoldrState value n = S.unfoldrM step n
1281− where
1282− step cnt =
1283− if cnt > n + value
1284− then return Nothing
1285− else do
1286− s <- get
1287− put (s + 1)
1288− return (Just (s, cnt + 1))
1289−
1290−{-# INLINE evalStateT #-}
1291−evalStateT :: S.MonadAsync m => Int -> Int -> Stream m Int
1292−evalStateT value n = Internal.evalStateT 0 (sourceUnfoldrState value n)
1293−
1294−{-# INLINE withState #-}
1295−withState :: S.MonadAsync m => Int -> Int -> Stream m Int
1296−withState value n =
1297− Internal.evalStateT (0 :: Int) (Internal.liftInner (sourceUnfoldrM value n))
1298−
1299−-------------------------------------------------------------------------------
1300−-- Concurrent application/fold
1301−-------------------------------------------------------------------------------
1302−
1303−{-# INLINE parAppMap #-}
1304−parAppMap :: S.MonadAsync m => Stream m Int -> m ()
1305−parAppMap src = S.drain $ S.map (+1) S.|$ src
1306−
1307−{-# INLINE parAppSum #-}
1308−parAppSum :: S.MonadAsync m => Stream m Int -> m ()
1309−parAppSum src = (S.sum S.|$. src) >>= \x -> P.seq x (return ())
1310−
1311−-------------------------------------------------------------------------------
1312−-- Type class instances
1313−-------------------------------------------------------------------------------
1314−
1315−{-# INLINE eqInstance #-}
1316−eqInstance :: Stream Identity Int -> Bool
1317−eqInstance src = src == src
1318−
1319−{-# INLINE eqInstanceNotEq #-}
1320−eqInstanceNotEq :: Stream Identity Int -> Bool
1321−eqInstanceNotEq src = src P./= src
1322−
1323−{-# INLINE ordInstance #-}
1324−ordInstance :: Stream Identity Int -> Bool
1325−ordInstance src = src P.< src
1326−
1327−{-# INLINE ordInstanceMin #-}
1328−ordInstanceMin :: Stream Identity Int -> Stream Identity Int
1329−ordInstanceMin src = P.min src src
1330−
1331−{-# INLINE showInstance #-}
1332−showInstance :: Stream Identity Int -> P.String
1333−showInstance src = P.show src
1334−
1335−{-# INLINE showInstanceList #-}
1336−showInstanceList :: [Int] -> P.String
1337−showInstanceList src = P.show src
1338−
1339−{-# INLINE readInstance #-}
1340−readInstance :: P.String -> Stream Identity Int
1341−readInstance str =
1342− let r = P.reads str
1343− in case r of
1344− [(x,"")] -> x
1345− _ -> P.error "readInstance: no parse"
1346−
1347−{-# INLINE readInstanceList #-}
1348−readInstanceList :: P.String -> [Int]
1349−readInstanceList str =
1350− let r = P.reads str
1351− in case r of
1352− [(x,"")] -> x
1353− _ -> P.error "readInstance: no parse"
1354−
1355−-------------------------------------------------------------------------------
1356−-- Pure (Identity) streams
1357−-------------------------------------------------------------------------------
1358−
1359−{-# INLINE pureFoldl' #-}
1360−pureFoldl' :: Stream Identity Int -> Int
1361−pureFoldl' = runIdentity . S.foldl' (+) 0
1362−
1363−-------------------------------------------------------------------------------
1364−-- Foldable Instance
1365−-------------------------------------------------------------------------------
1366−
1367−{-# INLINE foldableFoldl' #-}
1368−foldableFoldl' :: Int -> Int -> Int
1369−foldableFoldl' value n =
1370− F.foldl' (+) 0 (sourceUnfoldr value n :: S.SerialT Identity Int)
1371−
1372−{-# INLINE foldableFoldrElem #-}
1373−foldableFoldrElem :: Int -> Int -> Bool
1374−foldableFoldrElem value n =
1375− F.foldr (\x xs -> if x == value then P.True else xs)
1376− (P.False)
1377− (sourceUnfoldr value n :: S.SerialT Identity Int)
1378−
1379−{-# INLINE foldableSum #-}
1380−foldableSum :: Int -> Int -> Int
1381−foldableSum value n =
1382− P.sum (sourceUnfoldr value n :: S.SerialT Identity Int)
1383−
1384−{-# INLINE foldableProduct #-}
1385−foldableProduct :: Int -> Int -> Int
1386−foldableProduct value n =
1387− P.product (sourceUnfoldr value n :: S.SerialT Identity Int)
1388−
1389−{-# INLINE _foldableNull #-}
1390−_foldableNull :: Int -> Int -> Bool
1391−_foldableNull value n =
1392− P.null (sourceUnfoldr value n :: S.SerialT Identity Int)
1393−
1394−{-# INLINE foldableElem #-}
1395−foldableElem :: Int -> Int -> Bool
1396−foldableElem value n =
1397− P.elem value (sourceUnfoldr value n :: S.SerialT Identity Int)
1398−
1399−{-# INLINE foldableNotElem #-}
1400−foldableNotElem :: Int -> Int -> Bool
1401−foldableNotElem value n =
1402− P.notElem value (sourceUnfoldr value n :: S.SerialT Identity Int)
1403−
1404−{-# INLINE foldableFind #-}
1405−foldableFind :: Int -> Int -> Maybe Int
1406−foldableFind value n =
1407− F.find (== (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
1408−
1409−{-# INLINE foldableAll #-}
1410−foldableAll :: Int -> Int -> Bool
1411−foldableAll value n =
1412− P.all (<= (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
1413−
1414−{-# INLINE foldableAny #-}
1415−foldableAny :: Int -> Int -> Bool
1416−foldableAny value n =
1417− P.any (> (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
1418−
1419−{-# INLINE foldableAnd #-}
1420−foldableAnd :: Int -> Int -> Bool
1421−foldableAnd value n =
1422− P.and $ S.map (<= (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
1423−
1424−{-# INLINE foldableOr #-}
1425−foldableOr :: Int -> Int -> Bool
1426−foldableOr value n =
1427− P.or $ S.map (> (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
1428−
1429−{-# INLINE foldableLength #-}
1430−foldableLength :: Int -> Int -> Int
1431−foldableLength value n =
1432− P.length (sourceUnfoldr value n :: S.SerialT Identity Int)
1433−
1434−{-# INLINE foldableMin #-}
1435−foldableMin :: Int -> Int -> Int
1436−foldableMin value n =
1437− P.minimum (sourceUnfoldr value n :: S.SerialT Identity Int)
1438−
1439−{-# INLINE foldableMax #-}
1440−foldableMax :: Int -> Int -> Int
1441−foldableMax value n =
1442− P.maximum (sourceUnfoldr value n :: S.SerialT Identity Int)
1443−
1444−{-# INLINE foldableMinBy #-}
1445−foldableMinBy :: Int -> Int -> Int
1446−foldableMinBy value n =
1447− F.minimumBy compare (sourceUnfoldr value n :: S.SerialT Identity Int)
1448−
1449−{-# INLINE foldableListMinBy #-}
1450−foldableListMinBy :: Int -> Int -> Int
1451−foldableListMinBy value n = F.minimumBy compare [1..value+n]
1452−
1453−{-# INLINE foldableMaxBy #-}
1454−foldableMaxBy :: Int -> Int -> Int
1455−foldableMaxBy value n =
1456− F.maximumBy compare (sourceUnfoldr value n :: S.SerialT Identity Int)
1457−
1458−{-# INLINE foldableToList #-}
1459−foldableToList :: Int -> Int -> [Int]
1460−foldableToList value n =
1461− F.toList (sourceUnfoldr value n :: S.SerialT Identity Int)
1462−
1463−{-# INLINE foldableMapM_ #-}
1464−foldableMapM_ :: Monad m => Int -> Int -> m ()
1465−foldableMapM_ value n =
1466− F.mapM_ (\_ -> return ()) (sourceUnfoldr value n :: S.SerialT Identity Int)
1467−
1468−{-# INLINE foldableSequence_ #-}
1469−foldableSequence_ :: Int -> Int -> IO ()
1470−foldableSequence_ value n =
1471− F.sequence_ (sourceUnfoldrAction value n :: S.SerialT Identity (IO Int))
1472−
1473−{-# INLINE _foldableMsum #-}
1474−_foldableMsum :: Int -> Int -> IO Int
1475−_foldableMsum value n =
1476− F.msum (sourceUnfoldrAction value n :: S.SerialT Identity (IO Int))
1477−
1478−-------------------------------------------------------------------------------
1479−-- Traversable Instance
1480−-------------------------------------------------------------------------------
1481−
1482−{-# INLINE traversableTraverse #-}
1483−traversableTraverse :: Stream Identity Int -> IO (Stream Identity Int)
1484−traversableTraverse = P.traverse return
1485−
1486−{-# INLINE traversableSequenceA #-}
1487−traversableSequenceA :: Stream Identity Int -> IO (Stream Identity Int)
1488−traversableSequenceA = P.sequenceA . P.fmap return
1489−
1490−{-# INLINE traversableMapM #-}
1491−traversableMapM :: Stream Identity Int -> IO (Stream Identity Int)
1492−traversableMapM = P.mapM return
1493−
1494−{-# INLINE traversableSequence #-}
1495−traversableSequence :: Stream Identity Int -> IO (Stream Identity Int)
1496−traversableSequence = P.sequence . P.fmap return
1497−
1498−-------------------------------------------------------------------------------
1499−-- Benchmark groups
1500−-------------------------------------------------------------------------------
1501−
1502−-- We need a monadic bind here to make sure that the function f does not get
1503−-- completely optimized out by the compiler in some cases.
1504−
1505−-- | Takes a fold method, and uses it with a default source.
1506−{-# INLINE benchIOSink #-}
1507−benchIOSink
1508− :: (IsStream t, NFData b)
1509− => Int -> String -> (t IO Int -> IO b) -> Benchmark
1510−benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . source value
1511−
1512−{-# INLINE benchHoistSink #-}
1513−benchHoistSink
1514− :: (IsStream t, NFData b)
1515− => Int -> String -> (t Identity Int -> IO b) -> Benchmark
1516−benchHoistSink value name f =
1517− bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldr value
1518−
1519−-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
1520−-- we can't use it as it requires MonadAsync constraint.
1521−{-# INLINE benchIdentitySink #-}
1522−benchIdentitySink
1523− :: (IsStream t, NFData b)
1524− => Int -> String -> (t Identity Int -> Identity b) -> Benchmark
1525−benchIdentitySink value name f = bench name $ nf (f . sourceUnfoldr value) 1
1526−
1527−-- | Takes a source, and uses it with a default drain/fold method.
1528−{-# INLINE benchIOSrc #-}
1529−benchIOSrc
1530− :: (t IO a -> SerialT IO a)
1531− -> String
1532− -> (Int -> t IO a)
1533− -> Benchmark
1534−benchIOSrc t name f =
1535− bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f
1536−
1537−{-# INLINE benchPureSink #-}
1538−benchPureSink :: NFData b => Int -> String -> (SerialT Identity Int -> b) -> Benchmark
1539−benchPureSink value name f = benchPure name (sourceUnfoldr value) f
1540−
1541−{-# INLINE benchPureSinkIO #-}
1542−benchPureSinkIO
1543− :: NFData b
1544− => Int -> String -> (SerialT Identity Int -> IO b) -> Benchmark
1545−benchPureSinkIO value name f =
1546− bench name $ nfIO $ randomRIO (1, 1) >>= f . sourceUnfoldr value
1547−
1548−{-# INLINE benchIO #-}
1549−benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
1550−benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
1551−
1552−-- | Takes a source, and uses it with a default drain/fold method.
1553−{-# INLINE benchSrcIO #-}
1554−benchSrcIO
1555− :: (t IO a -> SerialT IO a)
1556− -> String
1557− -> (Int -> t IO a)
1558− -> Benchmark
1559−benchSrcIO t name f
1560− = bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f
1561−
1562−{-# INLINE benchMonadicSrcIO #-}
1563−benchMonadicSrcIO :: String -> (Int -> IO ()) -> Benchmark
1564−benchMonadicSrcIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
1565−
1566−
1567−-------------------------------------------------------------------------------
1568−-- Serial : O(1) Space
1569−-------------------------------------------------------------------------------
1570−
1571−o_1_space_serial_pure :: Int -> [Benchmark]
1572−o_1_space_serial_pure value =
1573− [ bgroup
1574− "serially"
1575− [ bgroup
1576− "pure"
1577− [ benchPureSink value "id" P.id
1578− , benchPureSink1 "eqBy" (eqByPure value)
1579− , benchPureSink value "==" eqInstance
1580− , benchPureSink value "/=" eqInstanceNotEq
1581− , benchPureSink1 "cmpBy" (cmpByPure value)
1582− , benchPureSink value "<" ordInstance
1583− , benchPureSink value "min" ordInstanceMin
1584− , benchPureSrc "IsList.fromList" (sourceIsList value)
1585− -- length is used to check for foldr/build fusion
1586− , benchPureSink
1587− value
1588− "length . IsList.toList"
1589− (P.length . GHC.toList)
1590− , benchPureSrc "IsString.fromString" (sourceIsString value)
1591− , benchPureSink value "showsPrec pure streams" showInstance
1592− , benchPureSink value "foldl'" pureFoldl'
1593− ]
1594− ]
1595− ]
1596−
1597−o_1_space_serial_foldable :: Int -> [Benchmark]
1598−o_1_space_serial_foldable value =
1599− [ bgroup
1600− "serially"
1601− [ bgroup
1602− "foldable"
1603− -- Foldable instance
1604− -- type class operations
1605− [ bench "foldl'" $ nf (foldableFoldl' value) 1
1606− , bench "foldrElem" $ nf (foldableFoldrElem value) 1
1607− -- , bench "null" $ nf (_foldableNull value) 1
1608− , bench "elem" $ nf (foldableElem value) 1
1609− , bench "length" $ nf (foldableLength value) 1
1610− , bench "sum" $ nf (foldableSum value) 1
1611− , bench "product" $ nf (foldableProduct value) 1
1612− , bench "minimum" $ nf (foldableMin value) 1
1613− , bench "maximum" $ nf (foldableMax value) 1
1614− , bench "length . toList" $
1615− nf (P.length . foldableToList value) 1
1616− -- folds
1617− , bench "notElem" $ nf (foldableNotElem value) 1
1618− , bench "find" $ nf (foldableFind value) 1
1619− , bench "all" $ nf (foldableAll value) 1
1620− , bench "any" $ nf (foldableAny value) 1
1621− , bench "and" $ nf (foldableAnd value) 1
1622− , bench "or" $ nf (foldableOr value) 1
1623− -- Note: minimumBy/maximumBy do not work in constant memory they are in
1624− -- the O(n) group of benchmarks down below in this file.
1625− -- Applicative and Traversable operations
1626− -- TBD: traverse_
1627− , benchIOSink1 "mapM_" (foldableMapM_ value)
1628− -- TBD: for_
1629− -- TBD: forM_
1630− , benchIOSink1 "sequence_" (foldableSequence_ value)
1631− -- TBD: sequenceA_
1632− -- TBD: asum
1633− -- , benchIOSink1 "msum" (_foldableMsum value)
1634− ]
1635− ]
1636− ]
1637−
1638−o_1_space_serial_generation :: Int -> [Benchmark]
1639−o_1_space_serial_generation value =
1640− [ bgroup
1641− "serially"
1642− [ bgroup
1643− "generation"
1644− -- Most basic, barely stream continuations running
1645− [ benchIOSrc serially "unfoldr" (sourceUnfoldr value)
1646− , benchIOSrc serially "unfoldrM" (sourceUnfoldrM value)
1647− , benchIOSrc serially "intFromTo" (sourceIntFromTo value)
1648− , benchIOSrc
1649− serially
1650− "intFromThenTo"
1651− (sourceIntFromThenTo value)
1652− , benchIOSrc
1653− serially
1654− "integerFromStep"
1655− (sourceIntegerFromStep value)
1656− , benchIOSrc
1657− serially
1658− "fracFromThenTo"
1659− (sourceFracFromThenTo value)
1660− , benchIOSrc serially "fracFromTo" (sourceFracFromTo value)
1661− , benchIOSrc serially "fromList" (sourceFromList value)
1662− , benchIOSrc serially "fromListM" (sourceFromListM value)
1663− -- These are essentially cons and consM
1664− , benchIOSrc
1665− serially
1666− "fromFoldable"
1667− (sourceFromFoldable value)
1668− , benchIOSrc
1669− serially
1670− "fromFoldableM"
1671− (sourceFromFoldableM value)
1672− , benchIOSrc serially "absTimes" $
1673− absTimes value
1674− ]
1675− ]
1676− ]
1677−
1678−o_1_space_serial_elimination :: Int -> [Benchmark]
1679−o_1_space_serial_elimination value =
1680− [ bgroup
1681− "serially"
1682− [ bgroup
1683− "elimination"
1684− [ bgroup
1685− "reduce"
1686− [ bgroup
1687− "IO"
1688− [ benchIOSink value "foldl'" foldl'Reduce
1689− , benchIOSink value "foldl1'" foldl1'Reduce
1690− , benchIOSink value "foldlM'" foldlM'Reduce
1691− ]
1692− , bgroup
1693− "Identity"
1694− [ benchIdentitySink value "foldl'" foldl'Reduce
1695− , benchIdentitySink
1696− value
1697− "foldl1'"
1698− foldl1'Reduce
1699− , benchIdentitySink
1700− value
1701− "foldlM'"
1702− foldlM'Reduce
1703− ]
1704− ]
1705− , bgroup
1706− "build"
1707− [ bgroup
1708− "IO"
1709− [ benchIOSink
1710− value
1711− "foldrMElem"
1712− (foldrMElem value)
1713− ]
1714− , bgroup
1715− "Identity"
1716− [ benchIdentitySink
1717− value
1718− "foldrMElem"
1719− (foldrMElem value)
1720− , benchIdentitySink
1721− value
1722− "foldrMToStreamLength"
1723− (S.length . runIdentity . foldrMToStream)
1724− , benchPureSink
1725− value
1726− "foldrMToListLength"
1727− (P.length . runIdentity . foldrMBuild)
1728− ]
1729− ]
1730− , benchIOSink value "uncons" uncons
1731− , benchIOSink value "toNull" $ toNull serially
1732− , benchIOSink value "mapM_" mapM_
1733− , benchIOSink value "init" init
1734− -- this is too low and causes all benchmarks reported in ns
1735− -- , benchIOSink value "head" head
1736− , benchIOSink value "last" last
1737− -- , benchIOSink value "lookup" lookup
1738− , benchIOSink value "find" (find value)
1739− , benchIOSink value "findIndex" (findIndex value)
1740− , benchIOSink value "elemIndex" (elemIndex value)
1741− -- this is too low and causes all benchmarks reported in ns
1742− -- , benchIOSink value "null" null
1743− , benchIOSink value "elem" (elem value)
1744− , benchIOSink value "notElem" (notElem value)
1745− , benchIOSink value "all" (all value)
1746− , benchIOSink value "any" (any value)
1747− , benchIOSink value "and" (and value)
1748− , benchIOSink value "or" (or value)
1749− , benchIOSink value "length" length
1750− , benchHoistSink
1751− value
1752− "length . generally"
1753− (length . IP.generally)
1754− , benchIOSink value "sum" sum
1755− , benchIOSink value "product" product
1756− , benchIOSink value "maximumBy" maximumBy
1757− , benchIOSink value "maximum" maximum
1758− , benchIOSink value "minimumBy" minimumBy
1759− , benchIOSink value "minimum" minimum
1760− ]
1761− ]
1762− ]
1763−
1764−o_1_space_serial_foldMultiStream :: Int -> [Benchmark]
1765−o_1_space_serial_foldMultiStream value =
1766− [ bgroup
1767− "serially"
1768− [ bgroup
1769− "fold-multi-stream"
1770− [ benchIOSink1 "eqBy" (eqBy value)
1771− , benchIOSink1 "cmpBy" (cmpBy value)
1772− , benchIOSink value "isPrefixOf" isPrefixOf
1773− , benchIOSink value "isSubsequenceOf" isSubsequenceOf
1774− , benchIOSink value "stripPrefix" stripPrefix
1775− ]
1776− ]
1777− ]
1778−
1779−o_1_space_serial_pipes :: Int -> [Benchmark]
1780−o_1_space_serial_pipes value =
1781− [ bgroup
1782− "serially"
1783− [ bgroup
1784− "pipes"
1785− [ benchIOSink value "mapM" (transformMapM serially 1)
1786− , benchIOSink
1787− value
1788− "compose"
1789− (transformComposeMapM serially 1)
1790− , benchIOSink value "tee" (transformTeeMapM serially 1)
1791− , benchIOSink value "zip" (transformZipMapM serially 1)
1792− ]
1793− ]
1794− ]
1795−
1796−o_1_space_serial_pipesX4 :: Int -> [Benchmark]
1797−o_1_space_serial_pipesX4 value =
1798− [ bgroup
1799− "serially"
1800− [ bgroup
1801− "pipesX4"
1802− [ benchIOSink value "mapM" (transformMapM serially 4)
1803− , benchIOSink
1804− value
1805− "compose"
1806− (transformComposeMapM serially 4)
1807− , benchIOSink value "tee" (transformTeeMapM serially 4)
1808− , benchIOSink value "zip" (transformZipMapM serially 4)
1809− ]
1810− ]
1811− ]
1812−
1813−
1814−o_1_space_serial_transformer :: Int -> [Benchmark]
1815−o_1_space_serial_transformer value =
1816− [ bgroup
1817− "serially"
1818− [ bgroup
1819− "transformer"
1820− [ benchIOSrc serially "evalState" (evalStateT value)
1821− , benchIOSrc serially "withState" (withState value)
1822− ]
1823− ]
1824− ]
1825−
1826−o_1_space_serial_transformation :: Int -> [Benchmark]
1827−o_1_space_serial_transformation value =
1828− [ bgroup
1829− "serially"
1830− [ bgroup
1831− "transformation"
1832− [ benchIOSink value "scanl" (scan 1)
1833− , benchIOSink value "scanl1'" (scanl1' 1)
1834− , benchIOSink value "map" (map 1)
1835− , benchIOSink value "fmap" (fmap 1)
1836− , benchIOSink value "mapM" (mapM serially 1)
1837− , benchIOSink value "mapMaybe" (mapMaybe 1)
1838− , benchIOSink value "mapMaybeM" (mapMaybeM 1)
1839− , bench "sequence" $
1840− nfIO $
1841− randomRIO (1, 1000) >>= \n ->
1842− sequence serially (sourceUnfoldrMAction value n)
1843− , benchIOSink value "findIndices" (findIndices value 1)
1844− , benchIOSink value "elemIndices" (elemIndices value 1)
1845− , benchIOSink value "foldrS" (foldrS 1)
1846− , benchIOSink value "foldrSMap" (foldrSMap 1)
1847− , benchIOSink value "foldrT" (foldrT 1)
1848− , benchIOSink value "foldrTMap" (foldrTMap 1)
1849− , benchIOSink value "tap" (tap 1)
1850− , benchIOSink value "tapRate 1 second" (tapRate 1)
1851− , benchIOSink value "pollCounts 1 second" (pollCounts 1)
1852− , benchIOSink value "tapAsync" (tapAsync 1)
1853− , benchIOSink value "tapAsyncS" (tapAsyncS 1)
1854− , benchIOSink value "timestamped" timestamped
1855− ]
1856− ]
1857− ]
1858−
1859−o_1_space_serial_transformationX4 :: Int -> [Benchmark]
1860−o_1_space_serial_transformationX4 value =
1861− [ bgroup
1862− "serially"
1863− [ bgroup
1864− "transformationX4"
1865− [ benchIOSink value "scan" (scan 4)
1866− , benchIOSink value "scanl1'" (scanl1' 4)
1867− , benchIOSink value "map" (map 4)
1868− , benchIOSink value "fmap" (fmap 4)
1869− , benchIOSink value "mapM" (mapM serially 4)
1870− , benchIOSink value "mapMaybe" (mapMaybe 4)
1871− , benchIOSink value "mapMaybeM" (mapMaybeM 4)
1872− -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
1873− -- sequence serially (sourceUnfoldrMAction n)
1874− , benchIOSink value "findIndices" (findIndices value 4)
1875− , benchIOSink value "elemIndices" (elemIndices value 4)
1876− ]
1877− ]
1878− ]
1879−
1880−o_1_space_serial_filtering :: Int -> [Benchmark]
1881−o_1_space_serial_filtering value =
1882− [ bgroup
1883− "serially"
1884− [ bgroup
1885− "filtering"
1886− [ benchIOSink value "filter-even" (filterEven 1)
1887− , benchIOSink value "filter-all-out" (filterAllOut value 1)
1888− , benchIOSink value "filter-all-in" (filterAllIn value 1)
1889− , benchIOSink value "take-all" (takeAll value 1)
1890− , benchIOSink
1891− value
1892− "takeByTime-all"
1893− (takeByTime (NanoSecond64 maxBound) 1)
1894− , benchIOSink value "takeWhile-true" (takeWhileTrue value 1)
1895− --, benchIOSink value "takeWhileM-true" (_takeWhileMTrue 1)
1896− -- "drop-one" is dual to "last"
1897− , benchIOSink value "drop-one" (dropOne 1)
1898− , benchIOSink value "drop-all" (dropAll value 1)
1899− , benchIOSink
1900− value
1901− "dropByTime-all"
1902− (dropByTime (NanoSecond64 maxBound) 1)
1903− , benchIOSink value "dropWhile-true" (dropWhileTrue value 1)
1904− --, benchIOSink value "dropWhileM-true" (_dropWhileMTrue 1)
1905− , benchIOSink
1906− value
1907− "dropWhile-false"
1908− (dropWhileFalse value 1)
1909− , benchIOSink value "deleteBy" (deleteBy value 1)
1910− , benchIOSink value "intersperse" (intersperse value 1)
1911− , benchIOSink value "insertBy" (insertBy value 1)
1912− ]
1913− ]
1914− ]
1915−
1916−o_1_space_serial_filteringX4 :: Int -> [Benchmark]
1917−o_1_space_serial_filteringX4 value =
1918− [ bgroup
1919− "serially"
1920− [ bgroup
1921− "filteringX4"
1922− [ benchIOSink value "filter-even" (filterEven 4)
1923− , benchIOSink value "filter-all-out" (filterAllOut value 4)
1924− , benchIOSink value "filter-all-in" (filterAllIn value 4)
1925− , benchIOSink value "take-all" (takeAll value 4)
1926− , benchIOSink value "takeWhile-true" (takeWhileTrue value 4)
1927− --, benchIOSink value "takeWhileM-true" (_takeWhileMTrue 4)
1928− , benchIOSink value "drop-one" (dropOne 4)
1929− , benchIOSink value "drop-all" (dropAll value 4)
1930− , benchIOSink value "dropWhile-true" (dropWhileTrue value 4)
1931− --, benchIOSink value "dropWhileM-true" (_dropWhileMTrue 4)
1932− , benchIOSink
1933− value
1934− "dropWhile-false"
1935− (dropWhileFalse value 4)
1936− , benchIOSink value "deleteBy" (deleteBy value 4)
1937− , benchIOSink value "intersperse" (intersperse value 4)
1938− , benchIOSink value "insertBy" (insertBy value 4)
1939− ]
1940− ]
1941− ]
1942−
1943−o_1_space_serial_joining :: Int -> [Benchmark]
1944−o_1_space_serial_joining value =
1945− [ bgroup
1946− "serially"
1947− [ bgroup
1948− "joining"
1949− [ benchIOSrc1 "zip (2,x/2)" (zip (value `div` 2))
1950− , benchIOSrc1 "zipM (2,x/2)" (zipM (value `div` 2))
1951− , benchIOSrc1 "mergeBy (2,x/2)" (mergeBy (value `div` 2))
1952− , benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2))
1953− , benchIOSrc1 "append (2,x/2)" (append2 (value `div` 2))
1954− , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4))
1955− , benchIOSrc1 "append (2,2,x/4)" (append4 (value `div` 4))
1956− , benchIOSrc1 "wSerial (2,x/2)" (wSerial2 value) -- XXX Move this elsewhere?
1957− , benchIOSrc1 "interleave (2,x/2)" (interleave2 value)
1958− , benchIOSrc1 "roundRobin (2,x/2)" (roundRobin2 value)
1959− ]
1960− ]
1961− ]
1962−
1963−o_1_space_serial_concatFoldable :: Int -> [Benchmark]
1964−o_1_space_serial_concatFoldable value =
1965− [ bgroup
1966− "serially"
1967− [ bgroup
1968− "concat-foldable"
1969− [ benchIOSrc
1970− serially
1971− "foldMapWith"
1972− (sourceFoldMapWith value)
1973− , benchIOSrc
1974− serially
1975− "foldMapWithM"
1976− (sourceFoldMapWithM value)
1977− , benchIOSrc serially "foldMapM" (sourceFoldMapM value)
1978− , benchIOSrc
1979− serially
1980− "foldWithConcatMapId"
1981− (sourceConcatMapId value)
1982− ]
1983− ]
1984− ]
1985−
1986−o_1_space_serial_concatSerial :: Int -> [Benchmark]
1987−o_1_space_serial_concatSerial value =
1988− [ bgroup
1989− "serially"
1990− [ bgroup
1991− "concat-serial"
1992− [ benchIOSrc1
1993− "concatMapPure (2,x/2)"
1994− (concatMapPure 2 (value `div` 2))
1995− , benchIOSrc1
1996− "concatMap (2,x/2)"
1997− (concatMap 2 (value `div` 2))
1998− , benchIOSrc1
1999− "concatMap (x/2,2)"
2000− (concatMap (value `div` 2) 2)
2001− , benchIOSrc1
2002− "concatMapRepl (x/4,4)"
2003− (concatMapRepl4xN value)
2004− , benchIOSrc1
2005− "concatUnfoldRepl (x/4,4)"
2006− (concatUnfoldRepl4xN value)
2007− , benchIOSrc1
2008− "concatMapWithSerial (2,x/2)"
2009− (concatMapWithSerial 2 (value `div` 2))
2010− , benchIOSrc1
2011− "concatMapWithSerial (x/2,2)"
2012− (concatMapWithSerial (value `div` 2) 2)
2013− , benchIOSrc1
2014− "concatMapWithAppend (2,x/2)"
2015− (concatMapWithAppend 2 (value `div` 2))
2016− ]
2017− ]
2018− ]
2019−
2020−o_1_space_serial_outerProductStreams :: Int -> [Benchmark]
2021−o_1_space_serial_outerProductStreams value =
2022− [ bgroup
2023− "serially"
2024− [ bgroup
2025− "outer-product-streams"
2026− [ benchIO "toNullAp" $ Nested.toNullAp value serially
2027− , benchIO "toNull" $ Nested.toNull value serially
2028− , benchIO "toNull3" $ Nested.toNull3 value serially
2029− , benchIO "filterAllOut" $ Nested.filterAllOut value serially
2030− , benchIO "filterAllIn" $ Nested.filterAllIn value serially
2031− , benchIO "filterSome" $ Nested.filterSome value serially
2032− , benchIO "breakAfterSome" $
2033− Nested.breakAfterSome value serially
2034− ]
2035− ]
2036− ]
2037−
2038−o_1_space_serial_mixed :: Int -> [Benchmark]
2039−o_1_space_serial_mixed value =
2040− [ bgroup
2041− "serially"
2042− -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
2043− -- library. If scan/fold followed by a map is efficient enough we may not
2044− -- need monolithic implementations of these.
2045− [ bgroup
2046− "mixed"
2047− [ benchIOSink value "scanl-map" (scanMap 1)
2048− , benchIOSink value "foldl-map" foldl'ReduceMap
2049− , benchIOSink value "sum-product-fold" sumProductFold
2050− , benchIOSink value "sum-product-scan" sumProductScan
2051− ]
2052− ]
2053− ]
2054−
2055−o_1_space_serial_mixedX4 :: Int -> [Benchmark]
2056−o_1_space_serial_mixedX4 value =
2057− [ bgroup
2058− "serially"
2059− [ bgroup
2060− "mixedX4"
2061− [ benchIOSink value "scan-map" (scanMap 4)
2062− , benchIOSink value "drop-map" (dropMap 4)
2063− , benchIOSink value "drop-scan" (dropScan 4)
2064− , benchIOSink value "take-drop" (takeDrop value 4)
2065− , benchIOSink value "take-scan" (takeScan value 4)
2066− , benchIOSink value "take-map" (takeMap value 4)
2067− , benchIOSink value "filter-drop" (filterDrop value 4)
2068− , benchIOSink value "filter-take" (filterTake value 4)
2069− , benchIOSink value "filter-scan" (filterScan 4)
2070− , benchIOSink value "filter-scanl1" (filterScanl1 4)
2071− , benchIOSink value "filter-map" (filterMap value 4)
2072− ]
2073− ]
2074− ]
2075−
2076−o_1_space_wSerial_transformation :: Int -> [Benchmark]
2077−o_1_space_wSerial_transformation value =
2078− [ bgroup
2079− "wSerially"
2080− [ bgroup
2081− "transformation"
2082− [benchIOSink value "fmap" $ fmap' wSerially 1]
2083− ]
2084− ]
2085−
2086−o_1_space_wSerial_concatMap :: Int -> [Benchmark]
2087−o_1_space_wSerial_concatMap value =
2088− [ bgroup
2089− "wSerially"
2090− [ bgroup
2091− "concatMap"
2092− [ benchIOSrc1
2093− "concatMapWithWSerial (2,x/2)"
2094− (concatMapWithWSerial 2 (value `div` 2))
2095− , benchIOSrc1
2096− "concatMapWithWSerial (x/2,2)"
2097− (concatMapWithWSerial (value `div` 2) 2)
2098− ]
2099− ]
2100− ]
2101−
2102−o_1_space_wSerial_outerProduct :: Int -> [Benchmark]
2103−o_1_space_wSerial_outerProduct value =
2104− [ bgroup
2105− "wSerially"
2106− [ bgroup
2107− "outer-product"
2108− [ benchIO "toNullAp" $ Nested.toNullAp value wSerially
2109− , benchIO "toNull" $ Nested.toNull value wSerially
2110− , benchIO "toNull3" $ Nested.toNull3 value wSerially
2111− , benchIO "filterAllOut" $ Nested.filterAllOut value wSerially
2112− , benchIO "filterAllIn" $ Nested.filterAllIn value wSerially
2113− , benchIO "filterSome" $ Nested.filterSome value wSerially
2114− , benchIO "breakAfterSome" $
2115− Nested.breakAfterSome value wSerially
2116− ]
2117− ]
2118− ]
2119−
2120−o_1_space_zipSerial_transformation :: Int -> [Benchmark]
2121−o_1_space_zipSerial_transformation value =
2122− [ bgroup
2123− "zipSerially"
2124− [ bgroup
2125− "transformation"
2126− [benchIOSink value "fmap" $ fmap' zipSerially 1]
2127− -- XXX needs fixing
2128− {-
2129− , bgroup "outer-product"
2130− [ benchIO "toNullAp" $ Nested.toNullAp value zipSerially
2131− ]
2132− -}
2133− ]
2134− ]
2135−
2136−-------------------------------------------------------------------------------
2137−-- Serial : O(n) Space
2138−-------------------------------------------------------------------------------
2139−
2140−o_n_space_serial_toContainers :: Int -> [Benchmark]
2141−o_n_space_serial_toContainers value =
2142− [ bgroup
2143− "serially"
2144− [ bgroup
2145− "toList" -- < 2MB
2146− -- Converting the stream to a list or pure stream in a strict monad
2147− [ benchIOSink value "foldrMToList" foldrMBuild
2148− , benchIOSink value "toList" toList
2149− , benchIOSink value "toListRev" toListRev
2150− -- , benchIOSink value "toPure" toPure
2151− -- , benchIOSink value "toPureRev" toPureRev
2152− ]
2153− , benchIOSink (value `div` 10) "classifySessionsOf"
2154− classifySessionsOf
2155− ]
2156− ]
2157−
2158−o_n_space_serial_outerProductStreams :: Int -> [Benchmark]
2159−o_n_space_serial_outerProductStreams value =
2160− [ bgroup
2161− "serially"
2162− [ bgroup
2163− "outer-product-streams"
2164− [ benchIO "toList" $ Nested.toList value serially
2165− , benchIO "toListSome" $ Nested.toListSome value serially
2166− ]
2167− ]
2168− ]
2169−
2170−o_n_space_wSerial_outerProductStreams :: Int -> [Benchmark]
2171−o_n_space_wSerial_outerProductStreams value =
2172− [ bgroup
2173− "wSerially"
2174− [ bgroup
2175− "outer-product-streams"
2176− [ benchIO "toList" $ Nested.toList value wSerially
2177− , benchIO "toListSome" $ Nested.toListSome value wSerially
2178− ]
2179− ]
2180− ]
2181−
2182−o_n_space_serial_traversable :: Int -> [Benchmark]
2183−o_n_space_serial_traversable value =
2184− [ bgroup
2185− "serially"
2186− -- Buffering operations using heap proportional to number of elements.
2187− [ bgroup
2188− "traversable" -- < 2MB
2189− -- Traversable instance
2190− [ benchPureSinkIO value "traverse" traversableTraverse
2191− , benchPureSinkIO value "sequenceA" traversableSequenceA
2192− , benchPureSinkIO value "mapM" traversableMapM
2193− , benchPureSinkIO value "sequence" traversableSequence
2194− ]
2195− ]
2196− ]
2197−
2198−o_n_space_serial_foldr :: Int -> [Benchmark]
2199−o_n_space_serial_foldr value =
2200− [ bgroup
2201− "serially"
2202− -- Head recursive strict right folds.
2203− [ bgroup
2204− "foldr"
2205− -- < 2MB
2206− -- accumulation due to strictness of IO monad
2207− [ benchIOSink value "foldrM/build/IO" foldrMBuild
2208− -- Right folds for reducing are inherently non-streaming as the
2209− -- expression needs to be fully built before it can be reduced.
2210− , benchIdentitySink
2211− value
2212− "foldrM/reduce/Identity"
2213− foldrMReduce
2214− -- takes < 4MB
2215− , benchIOSink value "foldrM/reduce/IO" foldrMReduce
2216− -- XXX the definitions of minimumBy and maximumBy in Data.Foldable use
2217− -- foldl1 which does not work in constant memory for our implementation.
2218− -- It works in constant memory for lists but even for lists it takes 15x
2219− -- more time compared to our foldl' based implementation.
2220− -- XXX these take < 16M stack space
2221− , bench "minimumBy" $ nf (flip foldableMinBy 1) value
2222− , bench "maximumBy" $ nf (flip foldableMaxBy 1) value
2223− , bench "minimumByList" $ nf (flip foldableListMinBy 1) value
2224− ]
2225− ]
2226− ]
2227−
2228−
2229−o_n_heap_serial_foldl :: Int -> [Benchmark]
2230−o_n_heap_serial_foldl value =
2231− [ bgroup
2232− "serially"
2233− [ bgroup
2234− "foldl"
2235− -- Left folds for building a structure are inherently non-streaming
2236− -- as the structure cannot be lazily consumed until fully built.
2237− [ benchIOSink value "foldl'/build/IO" foldl'Build
2238− , benchIdentitySink value "foldl'/build/Identity" foldl'Build
2239− , benchIOSink value "foldlM'/build/IO" foldlM'Build
2240− , benchIdentitySink
2241− value
2242− "foldlM'/build/Identity"
2243− foldlM'Build
2244− -- Reversing/sorting a stream
2245− , benchIOSink value "reverse" (reverse 1)
2246− , benchIOSink value "reverse'" (reverse' 1)
2247− ]
2248− ]
2249− ]
2250−
2251−o_n_heap_serial_buffering :: Int -> [Benchmark]
2252−o_n_heap_serial_buffering value =
2253− [ bgroup
2254− "serially"
2255− [ bgroup
2256− "buffering"
2257− -- Buffers the output of show/read.
2258− -- XXX can the outputs be streaming? Can we have special read/show
2259− -- style type classes, readM/showM supporting streaming effects?
2260− [ bench "readsPrec pure streams" $
2261− nf readInstance (mkString value)
2262− , bench "readsPrec Haskell lists" $
2263− nf readInstanceList (mkListString value)
2264− , bench "showPrec Haskell lists" $
2265− nf showInstanceList (mkList value)
2266− -- interleave x/4 streams of 4 elements each. Needs to buffer
2267− -- proportional to x/4. This is different from WSerial because
2268− -- WSerial expands slowly because of binary interleave behavior and
2269− -- this expands immediately because of Nary interleave behavior.
2270− , benchIOSrc1
2271− "concatUnfoldInterleaveRepl (x/4,4)"
2272− (concatUnfoldInterleaveRepl4xN value)
2273− , benchIOSrc1
2274− "concatUnfoldRoundrobinRepl (x/4,4)"
2275− (concatUnfoldRoundrobinRepl4xN value)
2276− ]
2277− ]
2278− ]
2279−
2280−-- Head recursive operations.
2281−o_n_stack_serial_iterated :: Int -> [Benchmark]
2282−o_n_stack_serial_iterated value =
2283− [ bgroup
2284− "serially"
2285− [ bgroup
2286− "iterated"
2287− [ benchIOSrc serially "mapMx10K" iterateMapM
2288− , benchIOSrc serially "scanx100" iterateScan
2289− , benchIOSrc serially "scanl1x100" iterateScanl1
2290− , benchIOSrc serially "filterEvenx10K" iterateFilterEven
2291− , benchIOSrc serially "takeAllx10K" (iterateTakeAll value)
2292− , benchIOSrc serially "dropOnex10K" iterateDropOne
2293− , benchIOSrc
2294− serially
2295− "dropWhileFalsex10K"
2296− (iterateDropWhileFalse value)
2297− , benchIOSrc
2298− serially
2299− "dropWhileTruex10K"
2300− (iterateDropWhileTrue value)
2301− , benchIOSink value "tail" tail
2302− , benchIOSink value "nullHeadTail" nullHeadTail
2303− ]
2304− ]
2305− ]
2306−
2307−o_1_space_async_generation :: Int -> [Benchmark]
2308−o_1_space_async_generation value =
2309− [ bgroup
2310− "asyncly"
2311− [ bgroup
2312− "generation"
2313− [ benchSrcIO asyncly "unfoldr" (sourceUnfoldr value)
2314− , benchSrcIO asyncly "unfoldrM" (sourceUnfoldrM value)
2315− , benchSrcIO asyncly "fromFoldable" (sourceFromFoldable value)
2316− , benchSrcIO asyncly "fromFoldableM" (sourceFromFoldableM value)
2317− , benchSrcIO
2318− asyncly
2319− "unfoldrM maxThreads 1"
2320− (maxThreads 1 . sourceUnfoldrM value)
2321− , benchSrcIO
2322− asyncly
2323− "unfoldrM maxBuffer 1 (x/10 ops)"
2324− (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
2325− ]
2326− ]
2327− ]
2328−
2329−o_1_space_async_concatFoldable :: Int -> [Benchmark]
2330−o_1_space_async_concatFoldable value =
2331− [ bgroup
2332− "asyncly"
2333− [ bgroup
2334− "concat-foldable"
2335− [ benchSrcIO asyncly "foldMapWith" (sourceFoldMapWith value)
2336− , benchSrcIO
2337− asyncly
2338− "foldMapWithM"
2339− (sourceFoldMapWithM value)
2340− , benchSrcIO asyncly "foldMapM" (sourceFoldMapM value)
2341− ]
2342− ]
2343− ]
2344−
2345−o_1_space_async_concatMap :: Int -> [Benchmark]
2346−o_1_space_async_concatMap value =
2347− value2 `seq`
2348− [ bgroup
2349− "asyncly"
2350− [ bgroup
2351− "concatMap"
2352− [ benchMonadicSrcIO
2353− "concatMapWith (2,x/2)"
2354− (concatStreamsWith async 2 (value `div` 2))
2355− , benchMonadicSrcIO
2356− "concatMapWith (sqrt x,sqrt x)"
2357− (concatStreamsWith async value2 value2)
2358− , benchMonadicSrcIO
2359− "concatMapWith (sqrt x * 2,sqrt x / 2)"
2360− (concatStreamsWith async (value2 * 2) (value2 `div` 2))
2361− ]
2362− ]
2363− ]
2364− where
2365− value2 = round $ sqrt $ (fromIntegral value :: Double)
2366−
2367−o_1_space_async_transformation :: Int -> [Benchmark]
2368−o_1_space_async_transformation value =
2369− [ bgroup
2370− "asyncly"
2371− [ bgroup
2372− "transformation"
2373− [ benchIOSink value "map" $ map' asyncly 1
2374− , benchIOSink value "fmap" $ fmap' asyncly 1
2375− , benchIOSink value "mapM" $ mapM asyncly 1
2376− ]
2377− ]
2378− ]
2379−
2380−o_1_space_wAsync_generation :: Int -> [Benchmark]
2381−o_1_space_wAsync_generation value =
2382− [ bgroup
2383− "wAsyncly"
2384− [ bgroup
2385− "generation"
2386− [ benchSrcIO wAsyncly "unfoldr" (sourceUnfoldr value)
2387− , benchSrcIO wAsyncly "unfoldrM" (sourceUnfoldrM value)
2388− , benchSrcIO wAsyncly "fromFoldable" (sourceFromFoldable value)
2389− , benchSrcIO
2390− wAsyncly
2391− "fromFoldableM"
2392− (sourceFromFoldableM value)
2393− , benchSrcIO
2394− wAsyncly
2395− "unfoldrM maxThreads 1"
2396− (maxThreads 1 . sourceUnfoldrM value)
2397− , benchSrcIO
2398− wAsyncly
2399− "unfoldrM maxBuffer 1 (x/10 ops)"
2400− (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
2401− ]
2402− ]
2403− ]
2404−
2405−o_1_space_wAsync_concatFoldable :: Int -> [Benchmark]
2406−o_1_space_wAsync_concatFoldable value =
2407− [ bgroup
2408− "wAsyncly"
2409− [ bgroup
2410− "concat-foldable"
2411− [ benchSrcIO wAsyncly "foldMapWith" (sourceFoldMapWith value)
2412− , benchSrcIO wAsyncly "foldMapWithM" (sourceFoldMapWithM value)
2413− , benchSrcIO wAsyncly "foldMapM" (sourceFoldMapM value)
2414− ]
2415− ]
2416− ]
2417−
2418−-- When we merge streams using wAsync the size of the queue increases
2419−-- slowly because of the binary composition adding just one more item
2420−-- to the work queue only after every scheduling pass through the
2421−-- work queue.
2422−--
2423−-- We should see the memory consumption increasing slowly if these
2424−-- benchmarks are left to run on infinite number of streams of infinite
2425−-- sizes.
2426−o_1_space_wAsync_concatMap :: Int -> [Benchmark]
2427−o_1_space_wAsync_concatMap value =
2428− value2 `seq`
2429− [ bgroup
2430− "wAsyncly"
2431− [ benchMonadicSrcIO
2432− "concatMapWith (2,x/2)"
2433− (concatStreamsWith wAsync 2 (value `div` 2))
2434− , benchMonadicSrcIO
2435− "concatMapWith (sqrt x,sqrt x)"
2436− (concatStreamsWith wAsync value2 value2)
2437− , benchMonadicSrcIO
2438− "concatMapWith (sqrt x * 2,sqrt x / 2)"
2439− (concatStreamsWith wAsync (value2 * 2) (value2 `div` 2))
2440− ]
2441− ]
2442− where
2443− value2 = round $ sqrt $ (fromIntegral value :: Double)
2444−
2445−o_1_space_wAsync_transformation :: Int -> [Benchmark]
2446−o_1_space_wAsync_transformation value =
2447− [ bgroup
2448− "wAsyncly"
2449− [ bgroup
2450− "transformation"
2451− [ benchIOSink value "map" $ map' wAsyncly 1
2452− , benchIOSink value "fmap" $ fmap' wAsyncly 1
2453− , benchIOSink value "mapM" $ mapM wAsyncly 1
2454− ]
2455− ]
2456− ]
2457−
2458−-- unfoldr and fromFoldable are always serial and therefore the same for
2459−-- all stream types. They can be removed to reduce the number of benchmarks.
2460−o_1_space_ahead_generation :: Int -> [Benchmark]
2461−o_1_space_ahead_generation value =
2462− [ bgroup
2463− "aheadly"
2464− [ bgroup
2465− "generation"
2466− [ benchSrcIO aheadly "unfoldr" (sourceUnfoldr value)
2467− , benchSrcIO aheadly "unfoldrM" (sourceUnfoldrM value)
2468−-- , benchSrcIO aheadly "fromFoldable" (sourceFromFoldable value)
2469− , benchSrcIO
2470− aheadly
2471− "fromFoldableM"
2472− (sourceFromFoldableM value)
2473− , benchSrcIO
2474− aheadly
2475− "unfoldrM maxThreads 1"
2476− (maxThreads 1 . sourceUnfoldrM value)
2477− , benchSrcIO
2478− aheadly
2479− "unfoldrM maxBuffer 1 (x/10 ops)"
2480− (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
2481− ]
2482− ]
2483− ]
2484−
2485−o_1_space_ahead_concatFoldable :: Int -> [Benchmark]
2486−o_1_space_ahead_concatFoldable value =
2487− [ bgroup
2488− "aheadly"
2489− [ bgroup
2490− "concat-foldable"
2491− [ benchSrcIO aheadly "foldMapWith" (sourceFoldMapWith value)
2492− , benchSrcIO aheadly "foldMapWithM" (sourceFoldMapWithM value)
2493− , benchSrcIO aheadly "foldMapM" (sourceFoldMapM value)
2494− ]
2495− ]
2496− ]
2497−
2498−o_1_space_ahead_concatMap :: Int -> [Benchmark]
2499−o_1_space_ahead_concatMap value =
2500− value2 `seq`
2501− [ bgroup
2502− "aheadly"
2503− [ benchMonadicSrcIO
2504− "concatMapWith (2,x/2)"
2505− (concatStreamsWith ahead 2 (value `div` 2))
2506− , benchMonadicSrcIO
2507− "concatMapWith (sqrt x,sqrt x)"
2508− (concatStreamsWith ahead value2 value2)
2509− , benchMonadicSrcIO
2510− "concatMapWith (sqrt x * 2,sqrt x / 2)"
2511− (concatStreamsWith ahead (value2 * 2) (value2 `div` 2))
2512− ]
2513− ]
2514− where
2515− value2 = round $ sqrt $ (fromIntegral value :: Double)
2516−
2517−
2518−o_1_space_ahead_transformation :: Int -> [Benchmark]
2519−o_1_space_ahead_transformation value =
2520− [ bgroup
2521− "aheadly"
2522− [ bgroup
2523− "transformation"
2524− [ benchIOSink value "map" $ map' aheadly 1
2525− , benchIOSink value "fmap" $ fmap' aheadly 1
2526− , benchIOSink value "mapM" $ mapM aheadly 1
2527− ]
2528− ]
2529− ]
2530−
2531−o_1_space_async_zip :: Int -> [Benchmark]
2532−o_1_space_async_zip value =
2533− [ bgroup
2534− "asyncly"
2535− [ bgroup
2536− "zip"
2537− [ benchSrcIO
2538− serially
2539− "zipAsync (2,x/2)"
2540− (zipAsync (value `div` 2))
2541− , benchSrcIO
2542− serially
2543− "zipAsyncM (2,x/2)"
2544− (zipAsyncM (value `div` 2))
2545− , benchSrcIO
2546− serially
2547− "zipAsyncAp (2,x/2)"
2548− (zipAsyncAp (value `div` 2))
2549− , benchIOSink value "fmap zipAsyncly" $ fmap' S.zipAsyncly 1
2550− , benchSrcIO
2551− serially
2552− "mergeAsyncBy (2,x/2)"
2553− (mergeAsyncBy (value `div` 2))
2554− , benchSrcIO
2555− serially
2556− "mergeAsyncByM (2,x/2)"
2557− (mergeAsyncByM (value `div` 2))
2558− -- Parallel stages in a pipeline
2559− , benchIOSink value "parAppMap" parAppMap
2560− , benchIOSink value "parAppSum" parAppSum
2561− ]
2562− ]
2563− ]
2564−
2565−o_n_space_parallel_generation :: Int -> [Benchmark]
2566−o_n_space_parallel_generation value =
2567− [ bgroup
2568− "parallely"
2569− [ bgroup
2570− "generation"
2571− [ benchSrcIO parallely "unfoldr" (sourceUnfoldr value)
2572− , benchSrcIO parallely "unfoldrM" (sourceUnfoldrM value)
2573−-- , benchSrcIO parallely "fromFoldable" (sourceFromFoldable value)
2574− , benchSrcIO
2575− parallely
2576− "fromFoldableM"
2577− (sourceFromFoldableM value)
2578− , benchSrcIO
2579− parallely
2580− "unfoldrM maxThreads 1"
2581− (maxThreads 1 . sourceUnfoldrM value)
2582− , benchSrcIO
2583− parallely
2584− "unfoldrM maxBuffer 1 (x/10 ops)"
2585− (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
2586− ]
2587− ]
2588− ]
2589−
2590−o_n_space_parallel_concatFoldable :: Int -> [Benchmark]
2591−o_n_space_parallel_concatFoldable value =
2592− [ bgroup
2593− "parallely"
2594− [ bgroup
2595− "concat-foldable"
2596− [ benchSrcIO parallely "foldMapWith" (sourceFoldMapWith value)
2597− , benchSrcIO parallely "foldMapWithM" (sourceFoldMapWithM value)
2598− , benchSrcIO parallely "foldMapM" (sourceFoldMapM value)
2599− ]
2600− ]
2601− ]
2602−
2603−o_n_space_parallel_concatMap :: Int -> [Benchmark]
2604−o_n_space_parallel_concatMap value =
2605− value2 `seq`
2606− [ bgroup
2607− "parallely"
2608− [ benchMonadicSrcIO
2609− "concatMapWith (2,x/2)"
2610− (concatStreamsWith parallel 2 (value `div` 2))
2611− , benchMonadicSrcIO
2612− "concatMapWith (sqrt x,sqrt x)"
2613− (concatStreamsWith parallel value2 value2)
2614− , benchMonadicSrcIO
2615− "concatMapWith (sqrt x * 2,sqrt x / 2)"
2616− (concatStreamsWith parallel (value2 * 2) (value2 `div` 2))
2617− ]
2618− ]
2619− where
2620− value2 = round $ sqrt $ (fromIntegral value :: Double)
2621−
2622−
2623−o_n_space_parallel_transformation :: Int -> [Benchmark]
2624−o_n_space_parallel_transformation value =
2625− [ bgroup
2626− "parallely"
2627− [ bgroup
2628− "transformation"
2629− [ benchIOSink value "map" $ map' parallely 1
2630− , benchIOSink value "fmap" $ fmap' parallely 1
2631− , benchIOSink value "mapM" $ mapM parallely 1
2632− ]
2633− ]
2634− ]
2635−
2636−o_n_space_parallel_outerProductStreams :: Int -> [Benchmark]
2637−o_n_space_parallel_outerProductStreams value =
2638− [ bgroup
2639− "parallely"
2640− [ bgroup
2641− "outer-product-streams"
2642− [ benchIO "toNullAp" $ Nested.toNullAp value parallely
2643− , benchIO "toNull" $ Nested.toNull value parallely
2644− , benchIO "toNull3" $ Nested.toNull3 value parallely
2645− , benchIO "filterAllOut" $ Nested.filterAllOut value parallely
2646− , benchIO "filterAllIn" $ Nested.filterAllIn value parallely
2647− , benchIO "filterSome" $ Nested.filterSome value parallely
2648− , benchIO "breakAfterSome" $
2649− Nested.breakAfterSome value parallely
2650− ]
2651− ]
2652− ]
2653−
2654−o_n_space_parallel_outerProductStreams2 :: Int -> [Benchmark]
2655−o_n_space_parallel_outerProductStreams2 value =
2656− [ bgroup
2657− "parallely"
2658− [ bgroup
2659− "outer-product-streams"
2660− [ benchIO "toList" $ Nested.toList value parallely
2661− , benchIO "toListSome" $ Nested.toListSome value parallely
2662− ]
2663− ]
2664− ]
2665−
2666−-- XXX arbitrarily large rate should be the same as rate Nothing
2667−o_1_space_async_avgRate :: Int -> [Benchmark]
2668−o_1_space_async_avgRate value =
2669− [ bgroup
2670− "asyncly"
2671− [ bgroup
2672− "avgRate"
2673− -- benchIO "unfoldr" $ toNull asyncly
2674− -- benchSrcIO asyncly "unfoldrM" (sourceUnfoldrM value)
2675− [ benchSrcIO
2676− asyncly
2677− "unfoldrM/Nothing"
2678− (S.rate Nothing . sourceUnfoldrM value)
2679− , benchSrcIO
2680− asyncly
2681− "unfoldrM/1,000,000"
2682− (S.avgRate 1000000 . sourceUnfoldrM value)
2683− , benchSrcIO
2684− asyncly
2685− "unfoldrM/3,000,000"
2686− (S.avgRate 3000000 . sourceUnfoldrM value)
2687− , benchSrcIO
2688− asyncly
2689− "unfoldrM/10,000,000/maxThreads1"
2690− (maxThreads 1 .
2691− S.avgRate 10000000 . sourceUnfoldrM value)
2692− , benchSrcIO
2693− asyncly
2694− "unfoldrM/10,000,000"
2695− (S.avgRate 10000000 . sourceUnfoldrM value)
2696− , benchSrcIO
2697− asyncly
2698− "unfoldrM/20,000,000"
2699− (S.avgRate 20000000 . sourceUnfoldrM value)
2700− ]
2701− ]
2702− ]
2703−
2704−o_1_space_ahead_avgRate :: Int -> [Benchmark]
2705−o_1_space_ahead_avgRate value =
2706− [ bgroup
2707− "aheadly"
2708− [ bgroup
2709− "avgRate"
2710− [ benchSrcIO
2711− aheadly
2712− "unfoldrM/1,000,000"
2713− (S.avgRate 1000000 . sourceUnfoldrM value)
2714− ]
2715− ]
2716− ]
14+import Streamly.Benchmark.Prelude.Generation
15+import Streamly.Benchmark.Prelude.Elimination
16+import Streamly.Benchmark.Prelude.Transformation
benchmark/lib/Streamly/Benchmark/Prelude/Elimination.hsnew file+795
@@ -0,0 +1,795 @@
1+-- |
2+-- Module : Streamly.Benchmark.Prelude
3+-- Copyright : (c) 2018 Harendra Kumar
4+--
5+-- License : MIT
6+-- Maintainer : streamly@composewell.com
7+
8+{-# LANGUAGE CPP #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE DeriveAnyClass #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE RankNTypes #-}
14+
15+#ifdef __HADDOCK_VERSION__
16+#undef INSPECTION
17+#endif
18+
19+#ifdef INSPECTION
20+{-# LANGUAGE TemplateHaskell #-}
21+{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
22+#endif
23+
24+module Streamly.Benchmark.Prelude.Elimination
25+ ( o_1_space_serial_pure
26+ , o_1_space_serial_foldable
27+ , o_1_space_serial_elimination
28+ , o_1_space_serial_foldMultiStream
29+
30+ , o_n_space_serial_toList
31+
32+ , o_n_space_serial_foldr
33+ , o_n_heap_serial_foldl
34+ ) where
35+
36+import Control.DeepSeq (NFData(..))
37+import Control.Monad.IO.Class (MonadIO(..))
38+import Data.Functor.Identity (Identity, runIdentity)
39+
40+import System.Random (randomRIO)
41+import Prelude
42+ (Monad, String, Int, (+), ($), (.), return, (>), (<=), (==),
43+ undefined, Maybe(..), Bool, (>>=), IO, compare, flip)
44+import qualified Prelude as P
45+import qualified Data.Foldable as F
46+import qualified GHC.Exts as GHC
47+
48+#ifdef INSPECTION
49+import GHC.Types (SPEC(..))
50+import Test.Inspection
51+
52+import qualified Streamly.Internal.Data.Stream.StreamD as D
53+#endif
54+
55+import qualified Streamly as S hiding (runStream)
56+import qualified Streamly.Prelude as S
57+import qualified Streamly.Internal.Prelude as Internal
58+
59+import qualified Streamly.Internal.Prelude as IP
60+
61+
62+import Gauge
63+import Streamly hiding (runStream)
64+import Streamly.Benchmark.Common
65+
66+type Stream m a = S.SerialT m a
67+
68+
69+-------------------------------------------------------------------------------
70+-- Stream generation
71+-------------------------------------------------------------------------------
72+
73+-- unfoldr
74+
75+{-# INLINE sourceUnfoldr #-}
76+sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
77+sourceUnfoldr value n = S.unfoldr step n
78+ where
79+ step cnt =
80+ if cnt > n + value
81+ then Nothing
82+ else Just (cnt, cnt + 1)
83+
84+{-# INLINE sourceUnfoldrM #-}
85+sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
86+sourceUnfoldrM value n = S.unfoldrM step n
87+ where
88+ step cnt =
89+ if cnt > n + value
90+ then return Nothing
91+ else return (Just (cnt, cnt + 1))
92+
93+{-# INLINE source #-}
94+source :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
95+source = sourceUnfoldrM
96+
97+{-# INLINE sourceUnfoldrAction #-}
98+sourceUnfoldrAction :: (S.IsStream t, Monad m, Monad m1)
99+ => Int -> Int -> t m (m1 Int)
100+sourceUnfoldrAction value n = S.serially $ S.unfoldr step n
101+ where
102+ step cnt =
103+ if cnt > n + value
104+ then Nothing
105+ else (Just (return cnt, cnt + 1))
106+
107+-- fromIndices
108+
109+{-# INLINE sourceIsList #-}
110+sourceIsList :: Int -> Int -> S.SerialT Identity Int
111+sourceIsList value n = GHC.fromList [n..n+value]
112+
113+{-# INLINE sourceIsString #-}
114+sourceIsString :: Int -> Int -> S.SerialT Identity P.Char
115+sourceIsString value n = GHC.fromString (P.replicate (n + value) 'a')
116+
117+-------------------------------------------------------------------------------
118+-- Elimination
119+-------------------------------------------------------------------------------
120+
121+{-# INLINE runStream #-}
122+runStream :: Monad m => Stream m a -> m ()
123+runStream = S.drain
124+
125+{-# INLINE toNull #-}
126+toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m ()
127+toNull t = runStream . t
128+
129+{-# INLINE uncons #-}
130+uncons :: Monad m => Stream m Int -> m ()
131+uncons s = do
132+ r <- S.uncons s
133+ case r of
134+ Nothing -> return ()
135+ Just (_, t) -> uncons t
136+
137+{-# INLINE init #-}
138+init :: Monad m => Stream m a -> m ()
139+init s = S.init s >>= P.mapM_ S.drain
140+
141+{-# INLINE mapM_ #-}
142+mapM_ :: Monad m => Stream m Int -> m ()
143+mapM_ = S.mapM_ (\_ -> return ())
144+
145+{-# INLINE toList #-}
146+toList :: Monad m => Stream m Int -> m [Int]
147+toList = S.toList
148+
149+{-# INLINE toListRev #-}
150+toListRev :: Monad m => Stream m Int -> m [Int]
151+toListRev = Internal.toListRev
152+
153+{-# INLINE foldrMElem #-}
154+foldrMElem :: Monad m => Int -> Stream m Int -> m Bool
155+foldrMElem e m =
156+ S.foldrM
157+ (\x xs ->
158+ if x == e
159+ then return P.True
160+ else xs)
161+ (return P.False)
162+ m
163+
164+{-# INLINE foldrMToStream #-}
165+foldrMToStream :: Monad m => Stream m Int -> m (Stream Identity Int)
166+foldrMToStream = S.foldr S.cons S.nil
167+
168+{-# INLINE foldrMBuild #-}
169+foldrMBuild :: Monad m => Stream m Int -> m [Int]
170+foldrMBuild = S.foldrM (\x xs -> xs >>= return . (x :)) (return [])
171+
172+{-# INLINE foldl'Build #-}
173+foldl'Build :: Monad m => Stream m Int -> m [Int]
174+foldl'Build = S.foldl' (flip (:)) []
175+
176+{-# INLINE foldlM'Build #-}
177+foldlM'Build :: Monad m => Stream m Int -> m [Int]
178+foldlM'Build = S.foldlM' (\xs x -> return $ x : xs) []
179+
180+{-# INLINE foldrMReduce #-}
181+foldrMReduce :: Monad m => Stream m Int -> m Int
182+foldrMReduce = S.foldrM (\x xs -> xs >>= return . (x +)) (return 0)
183+
184+{-# INLINE foldl'Reduce #-}
185+foldl'Reduce :: Monad m => Stream m Int -> m Int
186+foldl'Reduce = S.foldl' (+) 0
187+
188+{-# INLINE foldl1'Reduce #-}
189+foldl1'Reduce :: Monad m => Stream m Int -> m (Maybe Int)
190+foldl1'Reduce = S.foldl1' (+)
191+
192+{-# INLINE foldlM'Reduce #-}
193+foldlM'Reduce :: Monad m => Stream m Int -> m Int
194+foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
195+
196+{-# INLINE last #-}
197+last :: Monad m => Stream m Int -> m (Maybe Int)
198+last = S.last
199+
200+{-# INLINE _null #-}
201+_null :: Monad m => Stream m Int -> m Bool
202+_null = S.null
203+
204+{-# INLINE _head #-}
205+_head :: Monad m => Stream m Int -> m (Maybe Int)
206+_head = S.head
207+
208+{-# INLINE elem #-}
209+elem :: Monad m => Int -> Stream m Int -> m Bool
210+elem value = S.elem (value + 1)
211+
212+{-# INLINE notElem #-}
213+notElem :: Monad m => Int -> Stream m Int -> m Bool
214+notElem value = S.notElem (value + 1)
215+
216+{-# INLINE length #-}
217+length :: Monad m => Stream m Int -> m Int
218+length = S.length
219+
220+{-# INLINE all #-}
221+all :: Monad m => Int -> Stream m Int -> m Bool
222+all value = S.all (<= (value + 1))
223+
224+{-# INLINE any #-}
225+any :: Monad m => Int -> Stream m Int -> m Bool
226+any value = S.any (> (value + 1))
227+
228+{-# INLINE and #-}
229+and :: Monad m => Int -> Stream m Int -> m Bool
230+and value = S.and . S.map (<= (value + 1))
231+
232+{-# INLINE or #-}
233+or :: Monad m => Int -> Stream m Int -> m Bool
234+or value = S.or . S.map (> (value + 1))
235+
236+{-# INLINE find #-}
237+find :: Monad m => Int -> Stream m Int -> m (Maybe Int)
238+find value = S.find (== (value + 1))
239+
240+{-# INLINE findIndex #-}
241+findIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int)
242+findIndex value = S.findIndex (== (value + 1))
243+
244+{-# INLINE elemIndex #-}
245+elemIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int)
246+elemIndex value = S.elemIndex (value + 1)
247+
248+{-# INLINE maximum #-}
249+maximum :: Monad m => Stream m Int -> m (Maybe Int)
250+maximum = S.maximum
251+
252+{-# INLINE minimum #-}
253+minimum :: Monad m => Stream m Int -> m (Maybe Int)
254+minimum = S.minimum
255+
256+{-# INLINE sum #-}
257+sum :: Monad m => Stream m Int -> m Int
258+sum = S.sum
259+
260+{-# INLINE product #-}
261+product :: Monad m => Stream m Int -> m Int
262+product = S.product
263+
264+{-# INLINE minimumBy #-}
265+minimumBy :: Monad m => Stream m Int -> m (Maybe Int)
266+minimumBy = S.minimumBy compare
267+
268+{-# INLINE maximumBy #-}
269+maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
270+maximumBy = S.maximumBy compare
271+
272+-------------------------------------------------------------------------------
273+-- Transformation
274+-------------------------------------------------------------------------------
275+
276+{-# INLINE transform #-}
277+transform :: Monad m => Stream m a -> m ()
278+transform = runStream
279+
280+{-# INLINE composeN #-}
281+composeN ::
282+ MonadIO m
283+ => Int
284+ -> (Stream m Int -> Stream m Int)
285+ -> Stream m Int
286+ -> m ()
287+composeN n f =
288+ case n of
289+ 1 -> transform . f
290+ 2 -> transform . f . f
291+ 3 -> transform . f . f . f
292+ 4 -> transform . f . f . f . f
293+ _ -> undefined
294+
295+{-# INLINE reverse #-}
296+reverse :: MonadIO m => Int -> Stream m Int -> m ()
297+reverse n = composeN n $ S.reverse
298+
299+{-# INLINE reverse' #-}
300+reverse' :: MonadIO m => Int -> Stream m Int -> m ()
301+reverse' n = composeN n $ Internal.reverse'
302+
303+-------------------------------------------------------------------------------
304+-- Multi-stream folds
305+-------------------------------------------------------------------------------
306+
307+{-# INLINE isPrefixOf #-}
308+isPrefixOf :: Monad m => Stream m Int -> m Bool
309+isPrefixOf src = S.isPrefixOf src src
310+
311+{-# INLINE isSubsequenceOf #-}
312+isSubsequenceOf :: Monad m => Stream m Int -> m Bool
313+isSubsequenceOf src = S.isSubsequenceOf src src
314+
315+{-# INLINE stripPrefix #-}
316+stripPrefix :: Monad m => Stream m Int -> m ()
317+stripPrefix src = do
318+ _ <- S.stripPrefix src src
319+ return ()
320+
321+{-# INLINE eqBy' #-}
322+eqBy' :: (Monad m, P.Eq a) => Stream m a -> m P.Bool
323+eqBy' src = S.eqBy (==) src src
324+
325+{-# INLINE eqBy #-}
326+eqBy :: Int -> Int -> IO Bool
327+eqBy value n = eqBy' (source value n)
328+
329+#ifdef INSPECTION
330+inspect $ hasNoTypeClasses 'eqBy
331+inspect $ 'eqBy `hasNoType` ''SPEC
332+inspect $ 'eqBy `hasNoType` ''D.Step
333+#endif
334+
335+
336+{-# INLINE eqByPure #-}
337+eqByPure :: Int -> Int -> Identity Bool
338+eqByPure value n = eqBy' (sourceUnfoldr value n)
339+
340+#ifdef INSPECTION
341+inspect $ hasNoTypeClasses 'eqByPure
342+inspect $ 'eqByPure `hasNoType` ''SPEC
343+inspect $ 'eqByPure `hasNoType` ''D.Step
344+#endif
345+
346+{-# INLINE cmpBy' #-}
347+cmpBy' :: (Monad m, P.Ord a) => Stream m a -> m P.Ordering
348+cmpBy' src = S.cmpBy P.compare src src
349+
350+{-# INLINE cmpBy #-}
351+cmpBy :: Int -> Int -> IO P.Ordering
352+cmpBy value n = cmpBy' (source value n)
353+
354+#ifdef INSPECTION
355+inspect $ hasNoTypeClasses 'cmpBy
356+inspect $ 'cmpBy `hasNoType` ''SPEC
357+inspect $ 'cmpBy `hasNoType` ''D.Step
358+#endif
359+
360+{-# INLINE cmpByPure #-}
361+cmpByPure :: Int -> Int -> Identity P.Ordering
362+cmpByPure value n = cmpBy' (sourceUnfoldr value n)
363+
364+#ifdef INSPECTION
365+inspect $ hasNoTypeClasses 'cmpByPure
366+inspect $ 'cmpByPure `hasNoType` ''SPEC
367+inspect $ 'cmpByPure `hasNoType` ''D.Step
368+#endif
369+
370+-------------------------------------------------------------------------------
371+-- Type class instances
372+-------------------------------------------------------------------------------
373+
374+{-# INLINE eqInstance #-}
375+eqInstance :: Stream Identity Int -> Bool
376+eqInstance src = src == src
377+
378+{-# INLINE eqInstanceNotEq #-}
379+eqInstanceNotEq :: Stream Identity Int -> Bool
380+eqInstanceNotEq src = src P./= src
381+
382+{-# INLINE ordInstance #-}
383+ordInstance :: Stream Identity Int -> Bool
384+ordInstance src = src P.< src
385+
386+{-# INLINE ordInstanceMin #-}
387+ordInstanceMin :: Stream Identity Int -> Stream Identity Int
388+ordInstanceMin src = P.min src src
389+
390+{-# INLINE showInstance #-}
391+showInstance :: Stream Identity Int -> P.String
392+showInstance src = P.show src
393+
394+-------------------------------------------------------------------------------
395+-- Pure (Identity) streams
396+-------------------------------------------------------------------------------
397+
398+{-# INLINE pureFoldl' #-}
399+pureFoldl' :: Stream Identity Int -> Int
400+pureFoldl' = runIdentity . S.foldl' (+) 0
401+
402+-------------------------------------------------------------------------------
403+-- Foldable Instance
404+-------------------------------------------------------------------------------
405+
406+{-# INLINE foldableFoldl' #-}
407+foldableFoldl' :: Int -> Int -> Int
408+foldableFoldl' value n =
409+ F.foldl' (+) 0 (sourceUnfoldr value n :: S.SerialT Identity Int)
410+
411+{-# INLINE foldableFoldrElem #-}
412+foldableFoldrElem :: Int -> Int -> Bool
413+foldableFoldrElem value n =
414+ F.foldr (\x xs -> if x == value then P.True else xs)
415+ (P.False)
416+ (sourceUnfoldr value n :: S.SerialT Identity Int)
417+
418+{-# INLINE foldableSum #-}
419+foldableSum :: Int -> Int -> Int
420+foldableSum value n =
421+ P.sum (sourceUnfoldr value n :: S.SerialT Identity Int)
422+
423+{-# INLINE foldableProduct #-}
424+foldableProduct :: Int -> Int -> Int
425+foldableProduct value n =
426+ P.product (sourceUnfoldr value n :: S.SerialT Identity Int)
427+
428+{-# INLINE _foldableNull #-}
429+_foldableNull :: Int -> Int -> Bool
430+_foldableNull value n =
431+ P.null (sourceUnfoldr value n :: S.SerialT Identity Int)
432+
433+{-# INLINE foldableElem #-}
434+foldableElem :: Int -> Int -> Bool
435+foldableElem value n =
436+ P.elem value (sourceUnfoldr value n :: S.SerialT Identity Int)
437+
438+{-# INLINE foldableNotElem #-}
439+foldableNotElem :: Int -> Int -> Bool
440+foldableNotElem value n =
441+ P.notElem value (sourceUnfoldr value n :: S.SerialT Identity Int)
442+
443+{-# INLINE foldableFind #-}
444+foldableFind :: Int -> Int -> Maybe Int
445+foldableFind value n =
446+ F.find (== (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
447+
448+{-# INLINE foldableAll #-}
449+foldableAll :: Int -> Int -> Bool
450+foldableAll value n =
451+ P.all (<= (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
452+
453+{-# INLINE foldableAny #-}
454+foldableAny :: Int -> Int -> Bool
455+foldableAny value n =
456+ P.any (> (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
457+
458+{-# INLINE foldableAnd #-}
459+foldableAnd :: Int -> Int -> Bool
460+foldableAnd value n =
461+ P.and $ S.map (<= (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
462+
463+{-# INLINE foldableOr #-}
464+foldableOr :: Int -> Int -> Bool
465+foldableOr value n =
466+ P.or $ S.map (> (value + 1)) (sourceUnfoldr value n :: S.SerialT Identity Int)
467+
468+{-# INLINE foldableLength #-}
469+foldableLength :: Int -> Int -> Int
470+foldableLength value n =
471+ P.length (sourceUnfoldr value n :: S.SerialT Identity Int)
472+
473+{-# INLINE foldableMin #-}
474+foldableMin :: Int -> Int -> Int
475+foldableMin value n =
476+ P.minimum (sourceUnfoldr value n :: S.SerialT Identity Int)
477+
478+{-# INLINE foldableMax #-}
479+foldableMax :: Int -> Int -> Int
480+foldableMax value n =
481+ P.maximum (sourceUnfoldr value n :: S.SerialT Identity Int)
482+
483+{-# INLINE foldableMinBy #-}
484+foldableMinBy :: Int -> Int -> Int
485+foldableMinBy value n =
486+ F.minimumBy compare (sourceUnfoldr value n :: S.SerialT Identity Int)
487+
488+{-# INLINE foldableListMinBy #-}
489+foldableListMinBy :: Int -> Int -> Int
490+foldableListMinBy value n = F.minimumBy compare [1..value+n]
491+
492+{-# INLINE foldableMaxBy #-}
493+foldableMaxBy :: Int -> Int -> Int
494+foldableMaxBy value n =
495+ F.maximumBy compare (sourceUnfoldr value n :: S.SerialT Identity Int)
496+
497+{-# INLINE foldableToList #-}
498+foldableToList :: Int -> Int -> [Int]
499+foldableToList value n =
500+ F.toList (sourceUnfoldr value n :: S.SerialT Identity Int)
501+
502+{-# INLINE foldableMapM_ #-}
503+foldableMapM_ :: Monad m => Int -> Int -> m ()
504+foldableMapM_ value n =
505+ F.mapM_ (\_ -> return ()) (sourceUnfoldr value n :: S.SerialT Identity Int)
506+
507+{-# INLINE foldableSequence_ #-}
508+foldableSequence_ :: Int -> Int -> IO ()
509+foldableSequence_ value n =
510+ F.sequence_ (sourceUnfoldrAction value n :: S.SerialT Identity (IO Int))
511+
512+{-# INLINE _foldableMsum #-}
513+_foldableMsum :: Int -> Int -> IO Int
514+_foldableMsum value n =
515+ F.msum (sourceUnfoldrAction value n :: S.SerialT Identity (IO Int))
516+
517+-------------------------------------------------------------------------------
518+-- Benchmark groups
519+-------------------------------------------------------------------------------
520+
521+-- We need a monadic bind here to make sure that the function f does not get
522+-- completely optimized out by the compiler in some cases.
523+
524+-- | Takes a fold method, and uses it with a default source.
525+{-# INLINE benchIOSink #-}
526+benchIOSink
527+ :: (IsStream t, NFData b)
528+ => Int -> String -> (t IO Int -> IO b) -> Benchmark
529+benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . source value
530+
531+{-# INLINE benchHoistSink #-}
532+benchHoistSink
533+ :: (IsStream t, NFData b)
534+ => Int -> String -> (t Identity Int -> IO b) -> Benchmark
535+benchHoistSink value name f =
536+ bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldr value
537+
538+-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
539+-- we can't use it as it requires MonadAsync constraint.
540+{-# INLINE benchIdentitySink #-}
541+benchIdentitySink
542+ :: (IsStream t, NFData b)
543+ => Int -> String -> (t Identity Int -> Identity b) -> Benchmark
544+benchIdentitySink value name f = bench name $ nf (f . sourceUnfoldr value) 1
545+
546+{-# INLINE benchPureSink #-}
547+benchPureSink :: NFData b => Int -> String -> (SerialT Identity Int -> b) -> Benchmark
548+benchPureSink value name f = benchPure name (sourceUnfoldr value) f
549+
550+-------------------------------------------------------------------------------
551+-- Benchmark groups
552+-------------------------------------------------------------------------------
553+
554+o_1_space_serial_pure :: Int -> [Benchmark]
555+o_1_space_serial_pure value =
556+ [ bgroup
557+ "serially"
558+ [ bgroup
559+ "pure"
560+ [ benchPureSink value "id" P.id
561+ , benchPureSink1 "eqBy" (eqByPure value)
562+ , benchPureSink value "==" eqInstance
563+ , benchPureSink value "/=" eqInstanceNotEq
564+ , benchPureSink1 "cmpBy" (cmpByPure value)
565+ , benchPureSink value "<" ordInstance
566+ , benchPureSink value "min" ordInstanceMin
567+ , benchPureSrc "IsList.fromList" (sourceIsList value)
568+ -- length is used to check for foldr/build fusion
569+ , benchPureSink
570+ value
571+ "length . IsList.toList"
572+ (P.length . GHC.toList)
573+ , benchPureSrc "IsString.fromString" (sourceIsString value)
574+ , benchPureSink value "showsPrec pure streams" showInstance
575+ , benchPureSink value "foldl'" pureFoldl'
576+ ]
577+ ]
578+ ]
579+
580+
581+o_1_space_serial_foldable :: Int -> [Benchmark]
582+o_1_space_serial_foldable value =
583+ [ bgroup
584+ "serially"
585+ [ bgroup
586+ "foldable"
587+ -- Foldable instance
588+ -- type class operations
589+ [ bench "foldl'" $ nf (foldableFoldl' value) 1
590+ , bench "foldrElem" $ nf (foldableFoldrElem value) 1
591+ -- , bench "null" $ nf (_foldableNull value) 1
592+ , bench "elem" $ nf (foldableElem value) 1
593+ , bench "length" $ nf (foldableLength value) 1
594+ , bench "sum" $ nf (foldableSum value) 1
595+ , bench "product" $ nf (foldableProduct value) 1
596+ , bench "minimum" $ nf (foldableMin value) 1
597+ , bench "maximum" $ nf (foldableMax value) 1
598+ , bench "length . toList" $
599+ nf (P.length . foldableToList value) 1
600+ -- folds
601+ , bench "notElem" $ nf (foldableNotElem value) 1
602+ , bench "find" $ nf (foldableFind value) 1
603+ , bench "all" $ nf (foldableAll value) 1
604+ , bench "any" $ nf (foldableAny value) 1
605+ , bench "and" $ nf (foldableAnd value) 1
606+ , bench "or" $ nf (foldableOr value) 1
607+ -- Note: minimumBy/maximumBy do not work in constant memory they are in
608+ -- the O(n) group of benchmarks down below in this file.
609+ -- Applicative and Traversable operations
610+ -- TBD: traverse_
611+ , benchIOSink1 "mapM_" (foldableMapM_ value)
612+ -- TBD: for_
613+ -- TBD: forM_
614+ , benchIOSink1 "sequence_" (foldableSequence_ value)
615+ -- TBD: sequenceA_
616+ -- TBD: asum
617+ -- , benchIOSink1 "msum" (_foldableMsum value)
618+ ]
619+ ]
620+ ]
621+
622+
623+o_1_space_serial_elimination :: Int -> [Benchmark]
624+o_1_space_serial_elimination value =
625+ [ bgroup
626+ "serially"
627+ [ bgroup
628+ "elimination"
629+ [ bgroup
630+ "reduce"
631+ [ bgroup
632+ "IO"
633+ [ benchIOSink value "foldl'" foldl'Reduce
634+ , benchIOSink value "foldl1'" foldl1'Reduce
635+ , benchIOSink value "foldlM'" foldlM'Reduce
636+ ]
637+ , bgroup
638+ "Identity"
639+ [ benchIdentitySink value "foldl'" foldl'Reduce
640+ , benchIdentitySink
641+ value
642+ "foldl1'"
643+ foldl1'Reduce
644+ , benchIdentitySink
645+ value
646+ "foldlM'"
647+ foldlM'Reduce
648+ ]
649+ ]
650+ , bgroup
651+ "build"
652+ [ bgroup
653+ "IO"
654+ [ benchIOSink
655+ value
656+ "foldrMElem"
657+ (foldrMElem value)
658+ ]
659+ , bgroup
660+ "Identity"
661+ [ benchIdentitySink
662+ value
663+ "foldrMElem"
664+ (foldrMElem value)
665+ , benchIdentitySink
666+ value
667+ "foldrMToStreamLength"
668+ (S.length . runIdentity . foldrMToStream)
669+ , benchPureSink
670+ value
671+ "foldrMToListLength"
672+ (P.length . runIdentity . foldrMBuild)
673+ ]
674+ ]
675+ , benchIOSink value "uncons" uncons
676+ , benchIOSink value "toNull" $ toNull serially
677+ , benchIOSink value "mapM_" mapM_
678+ , benchIOSink value "init" init
679+ -- this is too low and causes all benchmarks reported in ns
680+ -- , benchIOSink value "head" head
681+ , benchIOSink value "last" last
682+ -- , benchIOSink value "lookup" lookup
683+ , benchIOSink value "find" (find value)
684+ , benchIOSink value "findIndex" (findIndex value)
685+ , benchIOSink value "elemIndex" (elemIndex value)
686+ -- this is too low and causes all benchmarks reported in ns
687+ -- , benchIOSink value "null" null
688+ , benchIOSink value "elem" (elem value)
689+ , benchIOSink value "notElem" (notElem value)
690+ , benchIOSink value "all" (all value)
691+ , benchIOSink value "any" (any value)
692+ , benchIOSink value "and" (and value)
693+ , benchIOSink value "or" (or value)
694+ , benchIOSink value "length" length
695+ , benchHoistSink
696+ value
697+ "length . generally"
698+ (length . IP.generally)
699+ , benchIOSink value "sum" sum
700+ , benchIOSink value "product" product
701+ , benchIOSink value "maximumBy" maximumBy
702+ , benchIOSink value "maximum" maximum
703+ , benchIOSink value "minimumBy" minimumBy
704+ , benchIOSink value "minimum" minimum
705+ ]
706+ ]
707+ ]
708+
709+
710+
711+o_1_space_serial_foldMultiStream :: Int -> [Benchmark]
712+o_1_space_serial_foldMultiStream value =
713+ [ bgroup
714+ "serially"
715+ [ bgroup
716+ "fold-multi-stream"
717+ [ benchIOSink1 "eqBy" (eqBy value)
718+ , benchIOSink1 "cmpBy" (cmpBy value)
719+ , benchIOSink value "isPrefixOf" isPrefixOf
720+ , benchIOSink value "isSubsequenceOf" isSubsequenceOf
721+ , benchIOSink value "stripPrefix" stripPrefix
722+ ]
723+ ]
724+ ]
725+
726+
727+o_n_space_serial_toList :: Int -> [Benchmark]
728+o_n_space_serial_toList value =
729+ [ bgroup
730+ "serially"
731+ [ bgroup
732+ "toList" -- < 2MB
733+ -- Converting the stream to a list or pure stream in a strict monad
734+ [ benchIOSink value "foldrMToList" foldrMBuild
735+ , benchIOSink value "toList" toList
736+ , benchIOSink value "toListRev" toListRev
737+ -- , benchIOSink value "toPure" toPure
738+ -- , benchIOSink value "toPureRev" toPureRev
739+ ]
740+ ]
741+ ]
742+
743+
744+o_n_space_serial_foldr :: Int -> [Benchmark]
745+o_n_space_serial_foldr value =
746+ [ bgroup
747+ "serially"
748+ -- Head recursive strict right folds.
749+ [ bgroup
750+ "foldr"
751+ -- < 2MB
752+ -- accumulation due to strictness of IO monad
753+ [ benchIOSink value "foldrM/build/IO" foldrMBuild
754+ -- Right folds for reducing are inherently non-streaming as the
755+ -- expression needs to be fully built before it can be reduced.
756+ , benchIdentitySink
757+ value
758+ "foldrM/reduce/Identity"
759+ foldrMReduce
760+ -- takes < 4MB
761+ , benchIOSink value "foldrM/reduce/IO" foldrMReduce
762+ -- XXX the definitions of minimumBy and maximumBy in Data.Foldable use
763+ -- foldl1 which does not work in constant memory for our implementation.
764+ -- It works in constant memory for lists but even for lists it takes 15x
765+ -- more time compared to our foldl' based implementation.
766+ -- XXX these take < 16M stack space
767+ , bench "minimumBy" $ nf (flip foldableMinBy 1) value
768+ , bench "maximumBy" $ nf (flip foldableMaxBy 1) value
769+ , bench "minimumByList" $ nf (flip foldableListMinBy 1) value
770+ ]
771+ ]
772+ ]
773+
774+
775+o_n_heap_serial_foldl :: Int -> [Benchmark]
776+o_n_heap_serial_foldl value =
777+ [ bgroup
778+ "serially"
779+ [ bgroup
780+ "foldl"
781+ -- Left folds for building a structure are inherently non-streaming
782+ -- as the structure cannot be lazily consumed until fully built.
783+ [ benchIOSink value "foldl'/build/IO" foldl'Build
784+ , benchIdentitySink value "foldl'/build/Identity" foldl'Build
785+ , benchIOSink value "foldlM'/build/IO" foldlM'Build
786+ , benchIdentitySink
787+ value
788+ "foldlM'/build/Identity"
789+ foldlM'Build
790+ -- Reversing/sorting a stream
791+ , benchIOSink value "reverse" (reverse 1)
792+ , benchIOSink value "reverse'" (reverse' 1)
793+ ]
794+ ]
795+ ]
benchmark/lib/Streamly/Benchmark/Prelude/Generation.hsnew file+1248
@@ -0,0 +1,1248 @@
1+-- |
2+-- Module : Streamly.Benchmark.Prelude
3+-- Copyright : (c) 2018 Harendra Kumar
4+--
5+-- License : MIT
6+-- Maintainer : streamly@composewell.com
7+
8+{-# LANGUAGE CPP #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE DeriveAnyClass #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE RankNTypes #-}
14+{-# LANGUAGE TupleSections #-}
15+
16+#ifdef __HADDOCK_VERSION__
17+#undef INSPECTION
18+#endif
19+
20+#ifdef INSPECTION
21+{-# LANGUAGE TemplateHaskell #-}
22+{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
23+#endif
24+
25+module Streamly.Benchmark.Prelude.Generation
26+ ( o_1_space_serial_generation
27+ , o_1_space_serial_joining
28+ , o_1_space_serial_concatFoldable
29+ , o_1_space_serial_concatSerial
30+ , o_1_space_serial_outerProductStreams
31+
32+ , o_1_space_wSerial_concatMap
33+ , o_1_space_wSerial_outerProduct
34+
35+ , o_n_space_serial_outerProductStreams
36+
37+ , o_n_space_wSerial_outerProductStreams
38+
39+ , o_n_heap_serial_buffering
40+
41+ , o_1_space_async_generation
42+ , o_1_space_async_concatFoldable
43+ , o_1_space_async_concatMap
44+
45+ , o_1_space_wAsync_generation
46+ , o_1_space_wAsync_concatFoldable
47+ , o_1_space_wAsync_concatMap
48+
49+ , o_1_space_ahead_generation
50+ , o_1_space_ahead_concatFoldable
51+ , o_1_space_ahead_concatMap
52+
53+ , o_1_space_async_zip
54+
55+ , o_n_space_parallel_generation
56+ , o_n_space_parallel_concatFoldable
57+ , o_n_space_parallel_concatMap
58+ , o_n_space_parallel_outerProductStreams
59+ , o_n_space_parallel_outerProductStreams2
60+
61+ , o_1_space_async_avgRate
62+
63+ , o_1_space_ahead_avgRate
64+ ) where
65+
66+
67+import Control.DeepSeq (NFData(..))
68+import Data.Functor.Identity (Identity)
69+import System.Random (randomRIO)
70+import Prelude
71+ (Monad, String, Int, (+), ($), (.), return, (>),
72+ undefined, Maybe(..), (>>=), curry,
73+ div, IO, compare, Double, fromIntegral, Integer, (<$>),
74+ (<*>), sqrt, round, (*), seq)
75+import qualified Prelude as P
76+import qualified Data.Foldable as F
77+
78+#ifdef INSPECTION
79+import GHC.Types (SPEC(..))
80+import Test.Inspection
81+
82+import qualified Streamly.Internal.Data.Stream.StreamD as D
83+#endif
84+
85+import qualified Streamly as S hiding (runStream)
86+import qualified Streamly.Prelude as S
87+import qualified Streamly.Internal.Prelude as Internal
88+import qualified Streamly.Internal.Data.Unfold as UF
89+import Streamly.Internal.Data.Time.Units
90+
91+import qualified Streamly.Benchmark.Prelude.NestedOps as Nested
92+
93+import Gauge
94+import Streamly hiding (runStream)
95+import Streamly.Benchmark.Common
96+
97+type Stream m a = S.SerialT m a
98+
99+
100+-------------------------------------------------------------------------------
101+-- Stream generation
102+-------------------------------------------------------------------------------
103+
104+-- enumerate
105+
106+{-# INLINE sourceIntFromTo #-}
107+sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
108+sourceIntFromTo value n = S.enumerateFromTo n (n + value)
109+
110+{-# INLINE sourceIntFromThenTo #-}
111+sourceIntFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
112+sourceIntFromThenTo value n = S.enumerateFromThenTo n (n + 1) (n + value)
113+
114+{-# INLINE sourceFracFromTo #-}
115+sourceFracFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double
116+sourceFracFromTo value n =
117+ S.enumerateFromTo (fromIntegral n) (fromIntegral (n + value))
118+
119+{-# INLINE sourceFracFromThenTo #-}
120+sourceFracFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double
121+sourceFracFromThenTo value n = S.enumerateFromThenTo (fromIntegral n)
122+ (fromIntegral n + 1.0001) (fromIntegral (n + value))
123+
124+{-# INLINE sourceIntegerFromStep #-}
125+sourceIntegerFromStep :: (Monad m, S.IsStream t) => Int -> Int -> t m Integer
126+sourceIntegerFromStep value n =
127+ S.take value $ S.enumerateFromThen (fromIntegral n) (fromIntegral n + 1)
128+
129+-- unfoldr
130+
131+{-# INLINE sourceUnfoldr #-}
132+sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
133+sourceUnfoldr value n = S.unfoldr step n
134+ where
135+ step cnt =
136+ if cnt > n + value
137+ then Nothing
138+ else Just (cnt, cnt + 1)
139+
140+{-# INLINE sourceUnfoldrN #-}
141+sourceUnfoldrN :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
142+sourceUnfoldrN upto start = S.unfoldr step start
143+ where
144+ step cnt =
145+ if cnt > start + upto
146+ then Nothing
147+ else Just (cnt, cnt + 1)
148+
149+{-# INLINE sourceUnfoldrM #-}
150+sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
151+sourceUnfoldrM value n = S.unfoldrM step n
152+ where
153+ step cnt =
154+ if cnt > n + value
155+ then return Nothing
156+ else return (Just (cnt, cnt + 1))
157+
158+{-# INLINE source #-}
159+source :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
160+source = sourceUnfoldrM
161+
162+{-# INLINE sourceUnfoldrMN #-}
163+sourceUnfoldrMN :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
164+sourceUnfoldrMN upto start = S.unfoldrM step start
165+ where
166+ step cnt =
167+ if cnt > start + upto
168+ then return Nothing
169+ else return (Just (cnt, cnt + 1))
170+
171+-- fromIndices
172+
173+{-# INLINE _sourceFromIndices #-}
174+_sourceFromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
175+_sourceFromIndices value n = S.take value $ S.fromIndices (+ n)
176+
177+{-# INLINE _sourceFromIndicesM #-}
178+_sourceFromIndicesM :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
179+_sourceFromIndicesM value n = S.take value $ S.fromIndicesM (P.fmap return (+ n))
180+
181+-- fromList
182+
183+{-# INLINE sourceFromList #-}
184+sourceFromList :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
185+sourceFromList value n = S.fromList [n..n+value]
186+
187+{-# INLINE sourceFromListM #-}
188+sourceFromListM :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
189+sourceFromListM value n = S.fromListM (P.fmap return [n..n+value])
190+
191+-- fromFoldable
192+
193+{-# INLINE sourceFromFoldable #-}
194+sourceFromFoldable :: S.IsStream t => Int -> Int -> t m Int
195+sourceFromFoldable value n = S.fromFoldable [n..n+value]
196+
197+{-# INLINE sourceFromFoldableM #-}
198+sourceFromFoldableM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
199+sourceFromFoldableM value n = S.fromFoldableM (P.fmap return [n..n+value])
200+
201+{-# INLINE absTimes #-}
202+absTimes :: (S.IsStream t, S.MonadAsync m, P.Functor (t m))
203+ => Int -> Int -> t m AbsTime
204+absTimes value _ = S.take value $ Internal.absTimes
205+
206+-------------------------------------------------------------------------------
207+-- Elimination
208+-------------------------------------------------------------------------------
209+
210+{-# INLINE runStream #-}
211+runStream :: Monad m => Stream m a -> m ()
212+runStream = S.drain
213+
214+{-# INLINE toNull #-}
215+toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m ()
216+toNull t = runStream . t
217+
218+-------------------------------------------------------------------------------
219+-- Transformation
220+-------------------------------------------------------------------------------
221+
222+{-# INLINE transform #-}
223+transform :: Monad m => Stream m a -> m ()
224+transform = runStream
225+
226+-- polymorphic stream version of composeN
227+{-# INLINE composeN' #-}
228+composeN' ::
229+ (S.IsStream t, Monad m)
230+ => Int
231+ -> (t m Int -> Stream m Int)
232+ -> t m Int
233+ -> m ()
234+composeN' n f =
235+ case n of
236+ 1 -> transform . f
237+ 2 -> transform . f . S.adapt . f
238+ 3 -> transform . f . S.adapt . f . S.adapt . f
239+ 4 -> transform . f . S.adapt . f . S.adapt . f . S.adapt . f
240+ _ -> undefined
241+
242+{-# INLINE fmap' #-}
243+fmap' ::
244+ (S.IsStream t, S.MonadAsync m, P.Functor (t m))
245+ => (t m Int -> S.SerialT m Int)
246+ -> Int
247+ -> t m Int
248+ -> m ()
249+fmap' t n = composeN' n $ t . P.fmap (+ 1)
250+
251+-------------------------------------------------------------------------------
252+-- Combining streams
253+-------------------------------------------------------------------------------
254+
255+-------------------------------------------------------------------------------
256+-- Appending
257+-------------------------------------------------------------------------------
258+
259+{-# INLINE serial2 #-}
260+serial2 :: Int -> Int -> IO ()
261+serial2 count n =
262+ S.drain $ S.serial (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
263+
264+{-# INLINE serial4 #-}
265+serial4 :: Int -> Int -> IO ()
266+serial4 count n =
267+ S.drain $
268+ S.serial
269+ ((S.serial (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))))
270+ ((S.serial
271+ (sourceUnfoldrMN count (n + 2))
272+ (sourceUnfoldrMN count (n + 3))))
273+
274+{-# INLINE append2 #-}
275+append2 :: Int -> Int -> IO ()
276+append2 count n =
277+ S.drain $
278+ Internal.append (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
279+
280+{-# INLINE append4 #-}
281+append4 :: Int -> Int -> IO ()
282+append4 count n =
283+ S.drain $
284+ Internal.append
285+ ((Internal.append
286+ (sourceUnfoldrMN count n)
287+ (sourceUnfoldrMN count (n + 1))))
288+ ((Internal.append
289+ (sourceUnfoldrMN count (n + 2))
290+ (sourceUnfoldrMN count (n + 3))))
291+
292+#ifdef INSPECTION
293+inspect $ hasNoTypeClasses 'append2
294+inspect $ 'append2 `hasNoType` ''SPEC
295+inspect $ 'append2 `hasNoType` ''D.AppendState
296+#endif
297+
298+-------------------------------------------------------------------------------
299+-- Interleaving
300+-------------------------------------------------------------------------------
301+
302+{-# INLINE wSerial2 #-}
303+wSerial2 :: Int -> Int -> IO ()
304+wSerial2 value n =
305+ S.drain $
306+ S.wSerial
307+ (sourceUnfoldrMN (value `div` 2) n)
308+ (sourceUnfoldrMN (value `div` 2) (n + 1))
309+
310+{-# INLINE interleave2 #-}
311+interleave2 :: Int -> Int -> IO ()
312+interleave2 value n =
313+ S.drain $
314+ Internal.interleave
315+ (sourceUnfoldrMN (value `div` 2) n)
316+ (sourceUnfoldrMN (value `div` 2) (n + 1))
317+
318+#ifdef INSPECTION
319+inspect $ hasNoTypeClasses 'interleave2
320+inspect $ 'interleave2 `hasNoType` ''SPEC
321+inspect $ 'interleave2 `hasNoType` ''D.InterleaveState
322+#endif
323+
324+{-# INLINE roundRobin2 #-}
325+roundRobin2 :: Int -> Int -> IO ()
326+roundRobin2 value n =
327+ S.drain $
328+ Internal.roundrobin
329+ (sourceUnfoldrMN (value `div` 2) n)
330+ (sourceUnfoldrMN (value `div` 2) (n + 1))
331+
332+#ifdef INSPECTION
333+inspect $ hasNoTypeClasses 'roundRobin2
334+inspect $ 'roundRobin2 `hasNoType` ''SPEC
335+inspect $ 'roundRobin2 `hasNoType` ''D.InterleaveState
336+#endif
337+
338+-------------------------------------------------------------------------------
339+-- Merging
340+-------------------------------------------------------------------------------
341+
342+{-# INLINE mergeBy #-}
343+mergeBy :: Int -> Int -> IO ()
344+mergeBy count n =
345+ S.drain $
346+ S.mergeBy
347+ P.compare
348+ (sourceUnfoldrMN count n)
349+ (sourceUnfoldrMN count (n + 1))
350+
351+#ifdef INSPECTION
352+inspect $ hasNoTypeClasses 'mergeBy
353+inspect $ 'mergeBy `hasNoType` ''SPEC
354+inspect $ 'mergeBy `hasNoType` ''D.Step
355+#endif
356+
357+-------------------------------------------------------------------------------
358+-- Zipping
359+-------------------------------------------------------------------------------
360+
361+{-# INLINE zip #-}
362+zip :: Int -> Int -> IO ()
363+zip count n =
364+ S.drain $
365+ S.zipWith (,) (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
366+
367+#ifdef INSPECTION
368+inspect $ hasNoTypeClasses 'zip
369+inspect $ 'zip `hasNoType` ''SPEC
370+inspect $ 'zip `hasNoType` ''D.Step
371+#endif
372+
373+{-# INLINE zipM #-}
374+zipM :: Int -> Int -> IO ()
375+zipM count n =
376+ S.drain $
377+ S.zipWithM
378+ (curry return)
379+ (sourceUnfoldrMN count n)
380+ (sourceUnfoldrMN count (n + 1))
381+
382+#ifdef INSPECTION
383+inspect $ hasNoTypeClasses 'zipM
384+inspect $ 'zipM `hasNoType` ''SPEC
385+inspect $ 'zipM `hasNoType` ''D.Step
386+#endif
387+
388+{-# INLINE zipAsync #-}
389+zipAsync :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
390+zipAsync count n = do
391+ S.zipAsyncWith (,) (sourceUnfoldrMN count n) (sourceUnfoldrMN count (n + 1))
392+
393+{-# INLINE zipAsyncM #-}
394+zipAsyncM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
395+zipAsyncM count n = do
396+ S.zipAsyncWithM
397+ (curry return)
398+ (sourceUnfoldrMN count n)
399+ (sourceUnfoldrMN count (n + 1))
400+
401+{-# INLINE zipAsyncAp #-}
402+zipAsyncAp :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int)
403+zipAsyncAp count n = do
404+ S.zipAsyncly $
405+ (,) <$> (sourceUnfoldrMN count n) <*> (sourceUnfoldrMN count (n + 1))
406+
407+{-# INLINE mergeAsyncByM #-}
408+mergeAsyncByM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
409+mergeAsyncByM count n = do
410+ S.mergeAsyncByM
411+ (\a b -> return (a `compare` b))
412+ (sourceUnfoldrMN count n)
413+ (sourceUnfoldrMN count (n + 1))
414+
415+{-# INLINE mergeAsyncBy #-}
416+mergeAsyncBy :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
417+mergeAsyncBy count n = do
418+ S.mergeAsyncBy
419+ compare
420+ (sourceUnfoldrMN count n)
421+ (sourceUnfoldrMN count (n + 1))
422+
423+-------------------------------------------------------------------------------
424+-- Streams of streams
425+-------------------------------------------------------------------------------
426+
427+-- Special cases of concatMap
428+
429+{-# INLINE sourceFoldMapWith #-}
430+sourceFoldMapWith :: (S.IsStream t, S.Semigroup (t m Int))
431+ => Int -> Int -> t m Int
432+sourceFoldMapWith value n = S.foldMapWith (S.<>) S.yield [n..n+value]
433+
434+{-# INLINE sourceFoldMapWithM #-}
435+sourceFoldMapWithM :: (S.IsStream t, Monad m, S.Semigroup (t m Int))
436+ => Int -> Int -> t m Int
437+sourceFoldMapWithM value n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
438+
439+{-# INLINE sourceFoldMapM #-}
440+sourceFoldMapM :: (S.IsStream t, Monad m, P.Monoid (t m Int))
441+ => Int -> Int -> t m Int
442+sourceFoldMapM value n = F.foldMap (S.yieldM . return) [n..n+value]
443+
444+{-# INLINE sourceConcatMapId #-}
445+sourceConcatMapId :: (S.IsStream t, Monad m)
446+ => Int -> Int -> t m Int
447+sourceConcatMapId value n =
448+ S.concatMap P.id $ S.fromFoldable $ P.map (S.yieldM . return) [n..n+value]
449+
450+-- concatMap unfoldrM/unfoldrM
451+
452+{-# INLINE concatMap #-}
453+concatMap :: Int -> Int -> Int -> IO ()
454+concatMap outer inner n =
455+ S.drain $ S.concatMap
456+ (\_ -> sourceUnfoldrMN inner n)
457+ (sourceUnfoldrMN outer n)
458+
459+#ifdef INSPECTION
460+inspect $ hasNoTypeClasses 'concatMap
461+inspect $ 'concatMap `hasNoType` ''SPEC
462+#endif
463+
464+-- concatMap unfoldr/unfoldr
465+
466+{-# INLINE concatMapPure #-}
467+concatMapPure :: Int -> Int -> Int -> IO ()
468+concatMapPure outer inner n =
469+ S.drain $ S.concatMap
470+ (\_ -> sourceUnfoldrN inner n)
471+ (sourceUnfoldrN outer n)
472+
473+#ifdef INSPECTION
474+inspect $ hasNoTypeClasses 'concatMapPure
475+inspect $ 'concatMapPure `hasNoType` ''SPEC
476+#endif
477+
478+-- concatMap replicate/unfoldrM
479+
480+{-# INLINE concatMapRepl4xN #-}
481+concatMapRepl4xN :: Int -> Int -> IO ()
482+concatMapRepl4xN value n = S.drain $ S.concatMap (S.replicate 4)
483+ (sourceUnfoldrMN (value `div` 4) n)
484+
485+#ifdef INSPECTION
486+inspect $ hasNoTypeClasses 'concatMapRepl4xN
487+inspect $ 'concatMapRepl4xN `hasNoType` ''SPEC
488+#endif
489+
490+-- concatMapWith
491+
492+{-# INLINE concatStreamsWith #-}
493+concatStreamsWith
494+ :: (forall c. S.SerialT IO c -> S.SerialT IO c -> S.SerialT IO c)
495+ -> Int
496+ -> Int
497+ -> Int
498+ -> IO ()
499+concatStreamsWith op outer inner n =
500+ S.drain $ S.concatMapWith op
501+ (\i -> sourceUnfoldrMN inner i)
502+ (sourceUnfoldrMN outer n)
503+
504+{-# INLINE concatMapWithSerial #-}
505+concatMapWithSerial :: Int -> Int -> Int -> IO ()
506+concatMapWithSerial = concatStreamsWith S.serial
507+
508+#ifdef INSPECTION
509+inspect $ hasNoTypeClasses 'concatMapWithSerial
510+inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
511+#endif
512+
513+{-# INLINE concatMapWithAppend #-}
514+concatMapWithAppend :: Int -> Int -> Int -> IO ()
515+concatMapWithAppend = concatStreamsWith Internal.append
516+
517+#ifdef INSPECTION
518+inspect $ hasNoTypeClasses 'concatMapWithAppend
519+inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
520+#endif
521+
522+{-# INLINE concatMapWithWSerial #-}
523+concatMapWithWSerial :: Int -> Int -> Int -> IO ()
524+concatMapWithWSerial = concatStreamsWith S.wSerial
525+
526+#ifdef INSPECTION
527+inspect $ hasNoTypeClasses 'concatMapWithWSerial
528+inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
529+#endif
530+
531+-- concatUnfold
532+
533+-- concatUnfold replicate/unfoldrM
534+
535+{-# INLINE concatUnfoldRepl4xN #-}
536+concatUnfoldRepl4xN :: Int -> Int -> IO ()
537+concatUnfoldRepl4xN value n =
538+ S.drain $ S.concatUnfold
539+ (UF.replicateM 4)
540+ (sourceUnfoldrMN (value `div` 4) n)
541+
542+#ifdef INSPECTION
543+inspect $ hasNoTypeClasses 'concatUnfoldRepl4xN
544+inspect $ 'concatUnfoldRepl4xN `hasNoType` ''D.ConcatMapUState
545+inspect $ 'concatUnfoldRepl4xN `hasNoType` ''SPEC
546+#endif
547+
548+{-# INLINE concatUnfoldInterleaveRepl4xN #-}
549+concatUnfoldInterleaveRepl4xN :: Int -> Int -> IO ()
550+concatUnfoldInterleaveRepl4xN value n =
551+ S.drain $ Internal.concatUnfoldInterleave
552+ (UF.replicateM 4)
553+ (sourceUnfoldrMN (value `div` 4) n)
554+
555+#ifdef INSPECTION
556+inspect $ hasNoTypeClasses 'concatUnfoldInterleaveRepl4xN
557+-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType` ''SPEC
558+-- inspect $ 'concatUnfoldInterleaveRepl4xN `hasNoType` ''D.ConcatUnfoldInterleaveState
559+#endif
560+
561+{-# INLINE concatUnfoldRoundrobinRepl4xN #-}
562+concatUnfoldRoundrobinRepl4xN :: Int -> Int -> IO ()
563+concatUnfoldRoundrobinRepl4xN value n =
564+ S.drain $ Internal.concatUnfoldRoundrobin
565+ (UF.replicateM 4)
566+ (sourceUnfoldrMN (value `div` 4) n)
567+
568+#ifdef INSPECTION
569+inspect $ hasNoTypeClasses 'concatUnfoldRoundrobinRepl4xN
570+-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType` ''SPEC
571+-- inspect $ 'concatUnfoldRoundrobinRepl4xN `hasNoType` ''D.ConcatUnfoldInterleaveState
572+#endif
573+
574+-------------------------------------------------------------------------------
575+-- Concurrent application/fold
576+-------------------------------------------------------------------------------
577+
578+{-# INLINE parAppMap #-}
579+parAppMap :: S.MonadAsync m => Stream m Int -> m ()
580+parAppMap src = S.drain $ S.map (+1) S.|$ src
581+
582+{-# INLINE parAppSum #-}
583+parAppSum :: S.MonadAsync m => Stream m Int -> m ()
584+parAppSum src = (S.sum S.|$. src) >>= \x -> P.seq x (return ())
585+
586+-------------------------------------------------------------------------------
587+-- Type class instances
588+-------------------------------------------------------------------------------
589+
590+{-# INLINE showInstanceList #-}
591+showInstanceList :: [Int] -> P.String
592+showInstanceList src = P.show src
593+
594+{-# INLINE readInstance #-}
595+readInstance :: P.String -> Stream Identity Int
596+readInstance str =
597+ let r = P.reads str
598+ in case r of
599+ [(x,"")] -> x
600+ _ -> P.error "readInstance: no parse"
601+
602+{-# INLINE readInstanceList #-}
603+readInstanceList :: P.String -> [Int]
604+readInstanceList str =
605+ let r = P.reads str
606+ in case r of
607+ [(x,"")] -> x
608+ _ -> P.error "readInstance: no parse"
609+
610+-------------------------------------------------------------------------------
611+-- Benchmark groups
612+-------------------------------------------------------------------------------
613+
614+-- We need a monadic bind here to make sure that the function f does not get
615+-- completely optimized out by the compiler in some cases.
616+
617+-- | Takes a fold method, and uses it with a default source.
618+{-# INLINE benchIOSink #-}
619+benchIOSink
620+ :: (IsStream t, NFData b)
621+ => Int -> String -> (t IO Int -> IO b) -> Benchmark
622+benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . source value
623+
624+-- | Takes a source, and uses it with a default drain/fold method.
625+{-# INLINE benchIOSrc #-}
626+benchIOSrc
627+ :: (t IO a -> SerialT IO a)
628+ -> String
629+ -> (Int -> t IO a)
630+ -> Benchmark
631+benchIOSrc t name f =
632+ bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f
633+
634+{-# INLINE benchIO #-}
635+benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
636+benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
637+
638+-- | Takes a source, and uses it with a default drain/fold method.
639+{-# INLINE benchSrcIO #-}
640+benchSrcIO
641+ :: (t IO a -> SerialT IO a)
642+ -> String
643+ -> (Int -> t IO a)
644+ -> Benchmark
645+benchSrcIO t name f
646+ = bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f
647+
648+{-# INLINE benchMonadicSrcIO #-}
649+benchMonadicSrcIO :: String -> (Int -> IO ()) -> Benchmark
650+benchMonadicSrcIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
651+
652+-------------------------------------------------------------------------------
653+-- Benchmark groups
654+-------------------------------------------------------------------------------
655+
656+o_1_space_serial_generation :: Int -> [Benchmark]
657+o_1_space_serial_generation value =
658+ [ bgroup
659+ "serially"
660+ [ bgroup
661+ "generation"
662+ -- Most basic, barely stream continuations running
663+ [ benchIOSrc serially "unfoldr" (sourceUnfoldr value)
664+ , benchIOSrc serially "unfoldrM" (sourceUnfoldrM value)
665+ , benchIOSrc serially "intFromTo" (sourceIntFromTo value)
666+ , benchIOSrc
667+ serially
668+ "intFromThenTo"
669+ (sourceIntFromThenTo value)
670+ , benchIOSrc
671+ serially
672+ "integerFromStep"
673+ (sourceIntegerFromStep value)
674+ , benchIOSrc
675+ serially
676+ "fracFromThenTo"
677+ (sourceFracFromThenTo value)
678+ , benchIOSrc serially "fracFromTo" (sourceFracFromTo value)
679+ , benchIOSrc serially "fromList" (sourceFromList value)
680+ , benchIOSrc serially "fromListM" (sourceFromListM value)
681+ -- These are essentially cons and consM
682+ , benchIOSrc
683+ serially
684+ "fromFoldable"
685+ (sourceFromFoldable value)
686+ , benchIOSrc
687+ serially
688+ "fromFoldableM"
689+ (sourceFromFoldableM value)
690+ , benchIOSrc serially "absTimes" $ absTimes value
691+ ]
692+ ]
693+ ]
694+
695+
696+
697+o_1_space_serial_joining :: Int -> [Benchmark]
698+o_1_space_serial_joining value =
699+ [ bgroup
700+ "serially"
701+ [ bgroup
702+ "joining"
703+ [ benchIOSrc1 "zip (2,x/2)" (zip (value `div` 2))
704+ , benchIOSrc1 "zipM (2,x/2)" (zipM (value `div` 2))
705+ , benchIOSrc1 "mergeBy (2,x/2)" (mergeBy (value `div` 2))
706+ , benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2))
707+ , benchIOSrc1 "append (2,x/2)" (append2 (value `div` 2))
708+ , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4))
709+ , benchIOSrc1 "append (2,2,x/4)" (append4 (value `div` 4))
710+ , benchIOSrc1 "wSerial (2,x/2)" (wSerial2 value) -- XXX Move this elsewhere?
711+ , benchIOSrc1 "interleave (2,x/2)" (interleave2 value)
712+ , benchIOSrc1 "roundRobin (2,x/2)" (roundRobin2 value)
713+ ]
714+ ]
715+ ]
716+
717+
718+o_1_space_serial_concatFoldable :: Int -> [Benchmark]
719+o_1_space_serial_concatFoldable value =
720+ [ bgroup
721+ "serially"
722+ [ bgroup
723+ "concat-foldable"
724+ [ benchIOSrc
725+ serially
726+ "foldMapWith"
727+ (sourceFoldMapWith value)
728+ , benchIOSrc
729+ serially
730+ "foldMapWithM"
731+ (sourceFoldMapWithM value)
732+ , benchIOSrc serially "foldMapM" (sourceFoldMapM value)
733+ , benchIOSrc
734+ serially
735+ "foldWithConcatMapId"
736+ (sourceConcatMapId value)
737+ ]
738+ ]
739+ ]
740+
741+o_1_space_serial_concatSerial :: Int -> [Benchmark]
742+o_1_space_serial_concatSerial value =
743+ [ bgroup
744+ "serially"
745+ [ bgroup
746+ "concat-serial"
747+ [ benchIOSrc1
748+ "concatMapPure (2,x/2)"
749+ (concatMapPure 2 (value `div` 2))
750+ , benchIOSrc1
751+ "concatMap (2,x/2)"
752+ (concatMap 2 (value `div` 2))
753+ , benchIOSrc1
754+ "concatMap (x/2,2)"
755+ (concatMap (value `div` 2) 2)
756+ , benchIOSrc1
757+ "concatMapRepl (x/4,4)"
758+ (concatMapRepl4xN value)
759+ , benchIOSrc1
760+ "concatUnfoldRepl (x/4,4)"
761+ (concatUnfoldRepl4xN value)
762+ , benchIOSrc1
763+ "concatMapWithSerial (2,x/2)"
764+ (concatMapWithSerial 2 (value `div` 2))
765+ , benchIOSrc1
766+ "concatMapWithSerial (x/2,2)"
767+ (concatMapWithSerial (value `div` 2) 2)
768+ , benchIOSrc1
769+ "concatMapWithAppend (2,x/2)"
770+ (concatMapWithAppend 2 (value `div` 2))
771+ ]
772+ ]
773+ ]
774+
775+o_1_space_serial_outerProductStreams :: Int -> [Benchmark]
776+o_1_space_serial_outerProductStreams value =
777+ [ bgroup
778+ "serially"
779+ [ bgroup
780+ "outer-product-streams"
781+ [ benchIO "toNullAp" $ Nested.toNullAp value serially
782+ , benchIO "toNull" $ Nested.toNull value serially
783+ , benchIO "toNull3" $ Nested.toNull3 value serially
784+ , benchIO "filterAllOut" $ Nested.filterAllOut value serially
785+ , benchIO "filterAllIn" $ Nested.filterAllIn value serially
786+ , benchIO "filterSome" $ Nested.filterSome value serially
787+ , benchIO "breakAfterSome" $
788+ Nested.breakAfterSome value serially
789+ ]
790+ ]
791+ ]
792+
793+
794+o_1_space_wSerial_concatMap :: Int -> [Benchmark]
795+o_1_space_wSerial_concatMap value =
796+ [ bgroup
797+ "wSerially"
798+ [ bgroup
799+ "concatMap"
800+ [ benchIOSrc1
801+ "concatMapWithWSerial (2,x/2)"
802+ (concatMapWithWSerial 2 (value `div` 2))
803+ , benchIOSrc1
804+ "concatMapWithWSerial (x/2,2)"
805+ (concatMapWithWSerial (value `div` 2) 2)
806+ ]
807+ ]
808+ ]
809+
810+o_1_space_wSerial_outerProduct :: Int -> [Benchmark]
811+o_1_space_wSerial_outerProduct value =
812+ [ bgroup
813+ "wSerially"
814+ [ bgroup
815+ "outer-product"
816+ [ benchIO "toNullAp" $ Nested.toNullAp value wSerially
817+ , benchIO "toNull" $ Nested.toNull value wSerially
818+ , benchIO "toNull3" $ Nested.toNull3 value wSerially
819+ , benchIO "filterAllOut" $ Nested.filterAllOut value wSerially
820+ , benchIO "filterAllIn" $ Nested.filterAllIn value wSerially
821+ , benchIO "filterSome" $ Nested.filterSome value wSerially
822+ , benchIO "breakAfterSome" $
823+ Nested.breakAfterSome value wSerially
824+ ]
825+ ]
826+ ]
827+
828+
829+o_n_space_serial_outerProductStreams :: Int -> [Benchmark]
830+o_n_space_serial_outerProductStreams value =
831+ [ bgroup
832+ "serially"
833+ [ bgroup
834+ "outer-product-streams"
835+ [ benchIO "toList" $ Nested.toList value serially
836+ , benchIO "toListSome" $ Nested.toListSome value serially
837+ ]
838+ ]
839+ ]
840+
841+o_n_space_wSerial_outerProductStreams :: Int -> [Benchmark]
842+o_n_space_wSerial_outerProductStreams value =
843+ [ bgroup
844+ "wSerially"
845+ [ bgroup
846+ "outer-product-streams"
847+ [ benchIO "toList" $ Nested.toList value wSerially
848+ , benchIO "toListSome" $ Nested.toListSome value wSerially
849+ ]
850+ ]
851+ ]
852+
853+
854+o_n_heap_serial_buffering :: Int -> [Benchmark]
855+o_n_heap_serial_buffering value =
856+ [ bgroup
857+ "serially"
858+ [ bgroup
859+ "buffering"
860+ -- Buffers the output of show/read.
861+ -- XXX can the outputs be streaming? Can we have special read/show
862+ -- style type classes, readM/showM supporting streaming effects?
863+ [ bench "readsPrec pure streams" $
864+ nf readInstance (mkString value)
865+ , bench "readsPrec Haskell lists" $
866+ nf readInstanceList (mkListString value)
867+ , bench "showPrec Haskell lists" $
868+ nf showInstanceList (mkList value)
869+ -- interleave x/4 streams of 4 elements each. Needs to buffer
870+ -- proportional to x/4. This is different from WSerial because
871+ -- WSerial expands slowly because of binary interleave behavior and
872+ -- this expands immediately because of Nary interleave behavior.
873+ , benchIOSrc1
874+ "concatUnfoldInterleaveRepl (x/4,4)"
875+ (concatUnfoldInterleaveRepl4xN value)
876+ , benchIOSrc1
877+ "concatUnfoldRoundrobinRepl (x/4,4)"
878+ (concatUnfoldRoundrobinRepl4xN value)
879+ ]
880+ ]
881+ ]
882+
883+
884+o_1_space_async_generation :: Int -> [Benchmark]
885+o_1_space_async_generation value =
886+ [ bgroup
887+ "asyncly"
888+ [ bgroup
889+ "generation"
890+ [ benchSrcIO asyncly "unfoldr" (sourceUnfoldr value)
891+ , benchSrcIO asyncly "unfoldrM" (sourceUnfoldrM value)
892+ , benchSrcIO asyncly "fromFoldable" (sourceFromFoldable value)
893+ , benchSrcIO asyncly "fromFoldableM" (sourceFromFoldableM value)
894+ , benchSrcIO
895+ asyncly
896+ "unfoldrM maxThreads 1"
897+ (maxThreads 1 . sourceUnfoldrM value)
898+ , benchSrcIO
899+ asyncly
900+ "unfoldrM maxBuffer 1 (x/10 ops)"
901+ (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
902+ ]
903+ ]
904+ ]
905+
906+
907+o_1_space_async_concatFoldable :: Int -> [Benchmark]
908+o_1_space_async_concatFoldable value =
909+ [ bgroup
910+ "asyncly"
911+ [ bgroup
912+ "concat-foldable"
913+ [ benchSrcIO asyncly "foldMapWith" (sourceFoldMapWith value)
914+ , benchSrcIO
915+ asyncly
916+ "foldMapWithM"
917+ (sourceFoldMapWithM value)
918+ , benchSrcIO asyncly "foldMapM" (sourceFoldMapM value)
919+ ]
920+ ]
921+ ]
922+
923+o_1_space_async_concatMap :: Int -> [Benchmark]
924+o_1_space_async_concatMap value =
925+ value2 `seq`
926+ [ bgroup
927+ "asyncly"
928+ [ bgroup
929+ "concatMap"
930+ [ benchMonadicSrcIO
931+ "concatMapWith (2,x/2)"
932+ (concatStreamsWith async 2 (value `div` 2))
933+ , benchMonadicSrcIO
934+ "concatMapWith (sqrt x,sqrt x)"
935+ (concatStreamsWith async value2 value2)
936+ , benchMonadicSrcIO
937+ "concatMapWith (sqrt x * 2,sqrt x / 2)"
938+ (concatStreamsWith async (value2 * 2) (value2 `div` 2))
939+ ]
940+ ]
941+ ]
942+ where
943+ value2 = round $ sqrt $ (fromIntegral value :: Double)
944+
945+
946+o_1_space_wAsync_generation :: Int -> [Benchmark]
947+o_1_space_wAsync_generation value =
948+ [ bgroup
949+ "wAsyncly"
950+ [ bgroup
951+ "generation"
952+ [ benchSrcIO wAsyncly "unfoldr" (sourceUnfoldr value)
953+ , benchSrcIO wAsyncly "unfoldrM" (sourceUnfoldrM value)
954+ , benchSrcIO wAsyncly "fromFoldable" (sourceFromFoldable value)
955+ , benchSrcIO
956+ wAsyncly
957+ "fromFoldableM"
958+ (sourceFromFoldableM value)
959+ , benchSrcIO
960+ wAsyncly
961+ "unfoldrM maxThreads 1"
962+ (maxThreads 1 . sourceUnfoldrM value)
963+ , benchSrcIO
964+ wAsyncly
965+ "unfoldrM maxBuffer 1 (x/10 ops)"
966+ (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
967+ ]
968+ ]
969+ ]
970+
971+
972+o_1_space_wAsync_concatFoldable :: Int -> [Benchmark]
973+o_1_space_wAsync_concatFoldable value =
974+ [ bgroup
975+ "wAsyncly"
976+ [ bgroup
977+ "concat-foldable"
978+ [ benchSrcIO wAsyncly "foldMapWith" (sourceFoldMapWith value)
979+ , benchSrcIO wAsyncly "foldMapWithM" (sourceFoldMapWithM value)
980+ , benchSrcIO wAsyncly "foldMapM" (sourceFoldMapM value)
981+ ]
982+ ]
983+ ]
984+
985+
986+-- When we merge streams using wAsync the size of the queue increases
987+-- slowly because of the binary composition adding just one more item
988+-- to the work queue only after every scheduling pass through the
989+-- work queue.
990+--
991+-- We should see the memory consumption increasing slowly if these
992+-- benchmarks are left to run on infinite number of streams of infinite
993+-- sizes.
994+o_1_space_wAsync_concatMap :: Int -> [Benchmark]
995+o_1_space_wAsync_concatMap value =
996+ value2 `seq`
997+ [ bgroup
998+ "wAsyncly"
999+ [ benchMonadicSrcIO
1000+ "concatMapWith (2,x/2)"
1001+ (concatStreamsWith wAsync 2 (value `div` 2))
1002+ , benchMonadicSrcIO
1003+ "concatMapWith (sqrt x,sqrt x)"
1004+ (concatStreamsWith wAsync value2 value2)
1005+ , benchMonadicSrcIO
1006+ "concatMapWith (sqrt x * 2,sqrt x / 2)"
1007+ (concatStreamsWith wAsync (value2 * 2) (value2 `div` 2))
1008+ ]
1009+ ]
1010+ where
1011+ value2 = round $ sqrt $ (fromIntegral value :: Double)
1012+
1013+
1014+-- unfoldr and fromFoldable are always serial and therefore the same for
1015+-- all stream types. They can be removed to reduce the number of benchmarks.
1016+o_1_space_ahead_generation :: Int -> [Benchmark]
1017+o_1_space_ahead_generation value =
1018+ [ bgroup
1019+ "aheadly"
1020+ [ bgroup
1021+ "generation"
1022+ [ benchSrcIO aheadly "unfoldr" (sourceUnfoldr value)
1023+ , benchSrcIO aheadly "unfoldrM" (sourceUnfoldrM value)
1024+-- , benchSrcIO aheadly "fromFoldable" (sourceFromFoldable value)
1025+ , benchSrcIO
1026+ aheadly
1027+ "fromFoldableM"
1028+ (sourceFromFoldableM value)
1029+ , benchSrcIO
1030+ aheadly
1031+ "unfoldrM maxThreads 1"
1032+ (maxThreads 1 . sourceUnfoldrM value)
1033+ , benchSrcIO
1034+ aheadly
1035+ "unfoldrM maxBuffer 1 (x/10 ops)"
1036+ (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
1037+ ]
1038+ ]
1039+ ]
1040+
1041+o_1_space_ahead_concatFoldable :: Int -> [Benchmark]
1042+o_1_space_ahead_concatFoldable value =
1043+ [ bgroup
1044+ "aheadly"
1045+ [ bgroup
1046+ "concat-foldable"
1047+ [ benchSrcIO aheadly "foldMapWith" (sourceFoldMapWith value)
1048+ , benchSrcIO aheadly "foldMapWithM" (sourceFoldMapWithM value)
1049+ , benchSrcIO aheadly "foldMapM" (sourceFoldMapM value)
1050+ ]
1051+ ]
1052+ ]
1053+
1054+o_1_space_ahead_concatMap :: Int -> [Benchmark]
1055+o_1_space_ahead_concatMap value =
1056+ value2 `seq`
1057+ [ bgroup
1058+ "aheadly"
1059+ [ benchMonadicSrcIO
1060+ "concatMapWith (2,x/2)"
1061+ (concatStreamsWith ahead 2 (value `div` 2))
1062+ , benchMonadicSrcIO
1063+ "concatMapWith (sqrt x,sqrt x)"
1064+ (concatStreamsWith ahead value2 value2)
1065+ , benchMonadicSrcIO
1066+ "concatMapWith (sqrt x * 2,sqrt x / 2)"
1067+ (concatStreamsWith ahead (value2 * 2) (value2 `div` 2))
1068+ ]
1069+ ]
1070+ where
1071+ value2 = round $ sqrt $ (fromIntegral value :: Double)
1072+
1073+
1074+o_1_space_async_zip :: Int -> [Benchmark]
1075+o_1_space_async_zip value =
1076+ [ bgroup
1077+ "asyncly"
1078+ [ bgroup
1079+ "zip"
1080+ [ benchSrcIO
1081+ serially
1082+ "zipAsync (2,x/2)"
1083+ (zipAsync (value `div` 2))
1084+ , benchSrcIO
1085+ serially
1086+ "zipAsyncM (2,x/2)"
1087+ (zipAsyncM (value `div` 2))
1088+ , benchSrcIO
1089+ serially
1090+ "zipAsyncAp (2,x/2)"
1091+ (zipAsyncAp (value `div` 2))
1092+ , benchIOSink value "fmap zipAsyncly" $ fmap' S.zipAsyncly 1
1093+ , benchSrcIO
1094+ serially
1095+ "mergeAsyncBy (2,x/2)"
1096+ (mergeAsyncBy (value `div` 2))
1097+ , benchSrcIO
1098+ serially
1099+ "mergeAsyncByM (2,x/2)"
1100+ (mergeAsyncByM (value `div` 2))
1101+ -- Parallel stages in a pipeline
1102+ , benchIOSink value "parAppMap" parAppMap
1103+ , benchIOSink value "parAppSum" parAppSum
1104+ ]
1105+ ]
1106+ ]
1107+
1108+o_n_space_parallel_generation :: Int -> [Benchmark]
1109+o_n_space_parallel_generation value =
1110+ [ bgroup
1111+ "parallely"
1112+ [ bgroup
1113+ "generation"
1114+ [ benchSrcIO parallely "unfoldr" (sourceUnfoldr value)
1115+ , benchSrcIO parallely "unfoldrM" (sourceUnfoldrM value)
1116+-- , benchSrcIO parallely "fromFoldable" (sourceFromFoldable value)
1117+ , benchSrcIO
1118+ parallely
1119+ "fromFoldableM"
1120+ (sourceFromFoldableM value)
1121+ , benchSrcIO
1122+ parallely
1123+ "unfoldrM maxThreads 1"
1124+ (maxThreads 1 . sourceUnfoldrM value)
1125+ , benchSrcIO
1126+ parallely
1127+ "unfoldrM maxBuffer 1 (x/10 ops)"
1128+ (maxBuffer 1 . sourceUnfoldrMN (value `div` 10))
1129+ ]
1130+ ]
1131+ ]
1132+
1133+o_n_space_parallel_concatFoldable :: Int -> [Benchmark]
1134+o_n_space_parallel_concatFoldable value =
1135+ [ bgroup
1136+ "parallely"
1137+ [ bgroup
1138+ "concat-foldable"
1139+ [ benchSrcIO parallely "foldMapWith" (sourceFoldMapWith value)
1140+ , benchSrcIO parallely "foldMapWithM" (sourceFoldMapWithM value)
1141+ , benchSrcIO parallely "foldMapM" (sourceFoldMapM value)
1142+ ]
1143+ ]
1144+ ]
1145+
1146+o_n_space_parallel_concatMap :: Int -> [Benchmark]
1147+o_n_space_parallel_concatMap value =
1148+ value2 `seq`
1149+ [ bgroup
1150+ "parallely"
1151+ [ benchMonadicSrcIO
1152+ "concatMapWith (2,x/2)"
1153+ (concatStreamsWith parallel 2 (value `div` 2))
1154+ , benchMonadicSrcIO
1155+ "concatMapWith (sqrt x,sqrt x)"
1156+ (concatStreamsWith parallel value2 value2)
1157+ , benchMonadicSrcIO
1158+ "concatMapWith (sqrt x * 2,sqrt x / 2)"
1159+ (concatStreamsWith parallel (value2 * 2) (value2 `div` 2))
1160+ ]
1161+ ]
1162+ where
1163+ value2 = round $ sqrt $ (fromIntegral value :: Double)
1164+
1165+
1166+o_n_space_parallel_outerProductStreams :: Int -> [Benchmark]
1167+o_n_space_parallel_outerProductStreams value =
1168+ [ bgroup
1169+ "parallely"
1170+ [ bgroup
1171+ "outer-product-streams"
1172+ [ benchIO "toNullAp" $ Nested.toNullAp value parallely
1173+ , benchIO "toNull" $ Nested.toNull value parallely
1174+ , benchIO "toNull3" $ Nested.toNull3 value parallely
1175+ , benchIO "filterAllOut" $ Nested.filterAllOut value parallely
1176+ , benchIO "filterAllIn" $ Nested.filterAllIn value parallely
1177+ , benchIO "filterSome" $ Nested.filterSome value parallely
1178+ , benchIO "breakAfterSome" $
1179+ Nested.breakAfterSome value parallely
1180+ ]
1181+ ]
1182+ ]
1183+
1184+o_n_space_parallel_outerProductStreams2 :: Int -> [Benchmark]
1185+o_n_space_parallel_outerProductStreams2 value =
1186+ [ bgroup
1187+ "parallely"
1188+ [ bgroup
1189+ "outer-product-streams"
1190+ [ benchIO "toList" $ Nested.toList value parallely
1191+ , benchIO "toListSome" $ Nested.toListSome value parallely
1192+ ]
1193+ ]
1194+ ]
1195+
1196+
1197+
1198+-- XXX arbitrarily large rate should be the same as rate Nothing
1199+o_1_space_async_avgRate :: Int -> [Benchmark]
1200+o_1_space_async_avgRate value =
1201+ [ bgroup
1202+ "asyncly"
1203+ [ bgroup
1204+ "avgRate"
1205+ -- benchIO "unfoldr" $ toNull asyncly
1206+ -- benchSrcIO asyncly "unfoldrM" (sourceUnfoldrM value)
1207+ [ benchSrcIO
1208+ asyncly
1209+ "unfoldrM/Nothing"
1210+ (S.rate Nothing . sourceUnfoldrM value)
1211+ , benchSrcIO
1212+ asyncly
1213+ "unfoldrM/1,000,000"
1214+ (S.avgRate 1000000 . sourceUnfoldrM value)
1215+ , benchSrcIO
1216+ asyncly
1217+ "unfoldrM/3,000,000"
1218+ (S.avgRate 3000000 . sourceUnfoldrM value)
1219+ , benchSrcIO
1220+ asyncly
1221+ "unfoldrM/10,000,000/maxThreads1"
1222+ (maxThreads 1 .
1223+ S.avgRate 10000000 . sourceUnfoldrM value)
1224+ , benchSrcIO
1225+ asyncly
1226+ "unfoldrM/10,000,000"
1227+ (S.avgRate 10000000 . sourceUnfoldrM value)
1228+ , benchSrcIO
1229+ asyncly
1230+ "unfoldrM/20,000,000"
1231+ (S.avgRate 20000000 . sourceUnfoldrM value)
1232+ ]
1233+ ]
1234+ ]
1235+
1236+o_1_space_ahead_avgRate :: Int -> [Benchmark]
1237+o_1_space_ahead_avgRate value =
1238+ [ bgroup
1239+ "aheadly"
1240+ [ bgroup
1241+ "avgRate"
1242+ [ benchSrcIO
1243+ aheadly
1244+ "unfoldrM/1,000,000"
1245+ (S.avgRate 1000000 . sourceUnfoldrM value)
1246+ ]
1247+ ]
1248+ ]
benchmark/lib/Streamly/Benchmark/Prelude/Transformation.hsnew file+1013
@@ -0,0 +1,1013 @@
1+-- |
2+-- Module : Streamly.Benchmark.Prelude
3+-- Copyright : (c) 2018 Harendra Kumar
4+--
5+-- License : MIT
6+-- Maintainer : streamly@composewell.com
7+
8+{-# LANGUAGE CPP #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE DeriveAnyClass #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE RankNTypes #-}
14+{-# LANGUAGE TupleSections #-}
15+
16+#ifdef __HADDOCK_VERSION__
17+#undef INSPECTION
18+#endif
19+
20+#ifdef INSPECTION
21+{-# LANGUAGE TemplateHaskell #-}
22+{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
23+#endif
24+
25+module Streamly.Benchmark.Prelude.Transformation
26+ ( o_1_space_serial_pipes
27+ , o_1_space_serial_pipesX4
28+ , o_1_space_serial_transformer
29+ , o_1_space_serial_transformation
30+ , o_1_space_serial_transformationX4
31+ , o_1_space_serial_filtering
32+ , o_1_space_serial_filteringX4
33+ , o_1_space_serial_mixed
34+ , o_1_space_serial_mixedX4
35+
36+ , o_1_space_wSerial_transformation
37+
38+ , o_1_space_zipSerial_transformation
39+
40+ , o_n_space_serial
41+
42+ , o_n_stack_serial_iterated
43+
44+ , o_1_space_async_transformation
45+
46+ , o_1_space_wAsync_transformation
47+
48+ , o_1_space_ahead_transformation
49+
50+ , o_n_space_parallel_transformation
51+ ) where
52+
53+import Control.DeepSeq (NFData(..))
54+import Control.Monad (when)
55+import Control.Monad.IO.Class (MonadIO(..))
56+import Control.Monad.State.Strict (StateT, get, put)
57+import Data.Functor.Identity (Identity)
58+import Data.IORef (newIORef, modifyIORef')
59+import GHC.Generics (Generic)
60+import System.Random (randomRIO)
61+import Prelude
62+ (Monad, String, Int, (+), ($), (.), return, even, (>), (<=), (==), (>=),
63+ undefined, Maybe(..), not, (>>=),
64+ maxBound, div, IO, compare, subtract, const, Bool(..), Either(..))
65+import qualified Prelude as P
66+
67+#ifdef INSPECTION
68+import Test.Inspection
69+
70+#endif
71+
72+import qualified Streamly as S hiding (runStream)
73+import qualified Streamly.Prelude as S
74+import qualified Streamly.Internal.Prelude as Internal
75+import qualified Streamly.Internal.Data.Fold as FL
76+import qualified Streamly.Internal.Data.Pipe as Pipe
77+import qualified Streamly.Internal.Data.Stream.Parallel as Par
78+import Streamly.Internal.Data.Time.Units
79+
80+import Gauge
81+import Streamly hiding (runStream)
82+
83+type Stream m a = S.SerialT m a
84+
85+-------------------------------------------------------------------------------
86+-- Stream generation
87+-------------------------------------------------------------------------------
88+
89+-- unfoldr
90+
91+{-# INLINE sourceUnfoldr #-}
92+sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
93+sourceUnfoldr value n = S.unfoldr step n
94+ where
95+ step cnt =
96+ if cnt > n + value
97+ then Nothing
98+ else Just (cnt, cnt + 1)
99+
100+{-# INLINE sourceUnfoldrM #-}
101+sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
102+sourceUnfoldrM value n = S.unfoldrM step n
103+ where
104+ step cnt =
105+ if cnt > n + value
106+ then return Nothing
107+ else return (Just (cnt, cnt + 1))
108+
109+{-# INLINE source #-}
110+source :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
111+source = sourceUnfoldrM
112+
113+{-# INLINE sourceUnfoldrMN #-}
114+sourceUnfoldrMN :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
115+sourceUnfoldrMN upto start = S.unfoldrM step start
116+ where
117+ step cnt =
118+ if cnt > start + upto
119+ then return Nothing
120+ else return (Just (cnt, cnt + 1))
121+
122+{-# INLINE sourceUnfoldrMAction #-}
123+sourceUnfoldrMAction :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (m Int)
124+sourceUnfoldrMAction value n = S.serially $ S.unfoldrM step n
125+ where
126+ step cnt =
127+ if cnt > n + value
128+ then return Nothing
129+ else return (Just (return cnt, cnt + 1))
130+
131+-------------------------------------------------------------------------------
132+-- Elimination
133+-------------------------------------------------------------------------------
134+
135+{-# INLINE runStream #-}
136+runStream :: Monad m => Stream m a -> m ()
137+runStream = S.drain
138+
139+{-# INLINE toNull #-}
140+toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m ()
141+toNull t = runStream . t
142+
143+
144+{-# INLINE tail #-}
145+tail :: Monad m => Stream m a -> m ()
146+tail s = S.tail s >>= P.mapM_ tail
147+
148+
149+{-# INLINE nullHeadTail #-}
150+nullHeadTail :: Monad m => Stream m Int -> m ()
151+nullHeadTail s = do
152+ r <- S.null s
153+ when (not r) $ do
154+ _ <- S.head s
155+ S.tail s >>= P.mapM_ nullHeadTail
156+
157+{-# INLINE foldl'ReduceMap #-}
158+foldl'ReduceMap :: Monad m => Stream m Int -> m Int
159+foldl'ReduceMap = P.fmap (+ 1) . S.foldl' (+) 0
160+
161+-------------------------------------------------------------------------------
162+-- Transformation
163+-------------------------------------------------------------------------------
164+
165+{-# INLINE transform #-}
166+transform :: Monad m => Stream m a -> m ()
167+transform = runStream
168+
169+{-# INLINE composeN #-}
170+composeN ::
171+ MonadIO m
172+ => Int
173+ -> (Stream m Int -> Stream m Int)
174+ -> Stream m Int
175+ -> m ()
176+composeN n f =
177+ case n of
178+ 1 -> transform . f
179+ 2 -> transform . f . f
180+ 3 -> transform . f . f . f
181+ 4 -> transform . f . f . f . f
182+ _ -> undefined
183+
184+-- polymorphic stream version of composeN
185+{-# INLINE composeN' #-}
186+composeN' ::
187+ (S.IsStream t, Monad m)
188+ => Int
189+ -> (t m Int -> Stream m Int)
190+ -> t m Int
191+ -> m ()
192+composeN' n f =
193+ case n of
194+ 1 -> transform . f
195+ 2 -> transform . f . S.adapt . f
196+ 3 -> transform . f . S.adapt . f . S.adapt . f
197+ 4 -> transform . f . S.adapt . f . S.adapt . f . S.adapt . f
198+ _ -> undefined
199+
200+{-# INLINE scan #-}
201+scan :: MonadIO m => Int -> Stream m Int -> m ()
202+scan n = composeN n $ S.scanl' (+) 0
203+
204+{-# INLINE scanl1' #-}
205+scanl1' :: MonadIO m => Int -> Stream m Int -> m ()
206+scanl1' n = composeN n $ S.scanl1' (+)
207+
208+{-# INLINE fmap #-}
209+fmap :: MonadIO m => Int -> Stream m Int -> m ()
210+fmap n = composeN n $ P.fmap (+ 1)
211+
212+{-# INLINE fmap' #-}
213+fmap' ::
214+ (S.IsStream t, S.MonadAsync m, P.Functor (t m))
215+ => (t m Int -> S.SerialT m Int)
216+ -> Int
217+ -> t m Int
218+ -> m ()
219+fmap' t n = composeN' n $ t . P.fmap (+ 1)
220+
221+{-# INLINE map #-}
222+map :: MonadIO m => Int -> Stream m Int -> m ()
223+map n = composeN n $ S.map (+ 1)
224+
225+{-# INLINE map' #-}
226+map' ::
227+ (S.IsStream t, S.MonadAsync m)
228+ => (t m Int -> S.SerialT m Int)
229+ -> Int
230+ -> t m Int
231+ -> m ()
232+map' t n = composeN' n $ t . S.map (+ 1)
233+
234+{-# INLINE mapM #-}
235+mapM ::
236+ (S.IsStream t, S.MonadAsync m)
237+ => (t m Int -> S.SerialT m Int)
238+ -> Int
239+ -> t m Int
240+ -> m ()
241+mapM t n = composeN' n $ t . S.mapM return
242+
243+{-# INLINE tap #-}
244+tap :: MonadIO m => Int -> Stream m Int -> m ()
245+tap n = composeN n $ S.tap FL.sum
246+
247+{-# INLINE tapRate #-}
248+tapRate :: Int -> Stream IO Int -> IO ()
249+tapRate n str = do
250+ cref <- newIORef 0
251+ composeN n (Internal.tapRate 1 (\c -> modifyIORef' cref (c +))) str
252+
253+{-# INLINE pollCounts #-}
254+pollCounts :: Int -> Stream IO Int -> IO ()
255+pollCounts n str = do
256+ composeN n (Internal.pollCounts (P.const P.True) f FL.drain) str
257+ where
258+ f = Internal.rollingMap (P.-) . Internal.delayPost 1
259+
260+{-# INLINE tapAsyncS #-}
261+tapAsyncS :: S.MonadAsync m => Int -> Stream m Int -> m ()
262+tapAsyncS n = composeN n $ Par.tapAsync S.sum
263+
264+{-# INLINE tapAsync #-}
265+tapAsync :: S.MonadAsync m => Int -> Stream m Int -> m ()
266+tapAsync n = composeN n $ Internal.tapAsync FL.sum
267+
268+{-# INLINE timestamped #-}
269+timestamped :: (S.MonadAsync m) => Stream m Int -> m ()
270+timestamped = transform . Internal.timestamped
271+
272+{-# INLINE classifySessionsOf #-}
273+classifySessionsOf :: (S.MonadAsync m) => Stream m Int -> m ()
274+classifySessionsOf =
275+ transform
276+ . Internal.classifySessionsOf
277+ 3 (const (return False)) (P.fmap Right FL.drain)
278+ . S.map (\(ts,(k,a)) -> (k, a, ts))
279+ . Internal.timestamped
280+ . S.concatMap (\x -> S.map (x,) (S.enumerateFromTo 1 (10 :: Int)))
281+
282+{-# INLINE mapMaybe #-}
283+mapMaybe :: MonadIO m => Int -> Stream m Int -> m ()
284+mapMaybe n =
285+ composeN n $
286+ S.mapMaybe
287+ (\x ->
288+ if P.odd x
289+ then Nothing
290+ else Just x)
291+
292+{-# INLINE mapMaybeM #-}
293+mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
294+mapMaybeM n =
295+ composeN n $
296+ S.mapMaybeM
297+ (\x ->
298+ if P.odd x
299+ then return Nothing
300+ else return $ Just x)
301+
302+{-# INLINE sequence #-}
303+sequence ::
304+ (S.IsStream t, S.MonadAsync m)
305+ => (t m Int -> S.SerialT m Int)
306+ -> t m (m Int)
307+ -> m ()
308+sequence t = transform . t . S.sequence
309+
310+{-# INLINE filterEven #-}
311+filterEven :: MonadIO m => Int -> Stream m Int -> m ()
312+filterEven n = composeN n $ S.filter even
313+
314+{-# INLINE filterAllOut #-}
315+filterAllOut :: MonadIO m => Int -> Int -> Stream m Int -> m ()
316+filterAllOut value n = composeN n $ S.filter (> (value + 1))
317+
318+{-# INLINE filterAllIn #-}
319+filterAllIn :: MonadIO m => Int -> Int -> Stream m Int -> m ()
320+filterAllIn value n = composeN n $ S.filter (<= (value + 1))
321+
322+{-# INLINE _takeOne #-}
323+_takeOne :: MonadIO m => Int -> Stream m Int -> m ()
324+_takeOne n = composeN n $ S.take 1
325+
326+{-# INLINE takeAll #-}
327+takeAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
328+takeAll value n = composeN n $ S.take (value + 1)
329+
330+{-# INLINE takeWhileTrue #-}
331+takeWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
332+takeWhileTrue value n = composeN n $ S.takeWhile (<= (value + 1))
333+
334+{-# INLINE _takeWhileMTrue #-}
335+_takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
336+_takeWhileMTrue value n = composeN n $ S.takeWhileM (return . (<= (value + 1)))
337+
338+{-# INLINE dropOne #-}
339+dropOne :: MonadIO m => Int -> Stream m Int -> m ()
340+dropOne n = composeN n $ S.drop 1
341+
342+{-# INLINE dropAll #-}
343+dropAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
344+dropAll value n = composeN n $ S.drop (value + 1)
345+
346+{-# INLINE dropWhileTrue #-}
347+dropWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
348+dropWhileTrue value n = composeN n $ S.dropWhile (<= (value + 1))
349+
350+{-# INLINE _dropWhileMTrue #-}
351+_dropWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
352+_dropWhileMTrue value n = composeN n $ S.dropWhileM (return . (<= (value + 1)))
353+
354+{-# INLINE dropWhileFalse #-}
355+dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m ()
356+dropWhileFalse value n = composeN n $ S.dropWhile (> (value + 1))
357+
358+{-# INLINE findIndices #-}
359+findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
360+findIndices value n = composeN n $ S.findIndices (== (value + 1))
361+
362+{-# INLINE elemIndices #-}
363+elemIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
364+elemIndices value n = composeN n $ S.elemIndices (value + 1)
365+
366+{-# INLINE intersperse #-}
367+intersperse :: S.MonadAsync m => Int -> Int -> Stream m Int -> m ()
368+intersperse value n = composeN n $ S.intersperse (value + 1)
369+
370+{-# INLINE insertBy #-}
371+insertBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
372+insertBy value n = composeN n $ S.insertBy compare (value + 1)
373+
374+{-# INLINE deleteBy #-}
375+deleteBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
376+deleteBy value n = composeN n $ S.deleteBy (>=) (value + 1)
377+
378+{-# INLINE foldrS #-}
379+foldrS :: MonadIO m => Int -> Stream m Int -> m ()
380+foldrS n = composeN n $ Internal.foldrS S.cons S.nil
381+
382+{-# INLINE foldrSMap #-}
383+foldrSMap :: MonadIO m => Int -> Stream m Int -> m ()
384+foldrSMap n = composeN n $ Internal.foldrS (\x xs -> x + 1 `S.cons` xs) S.nil
385+
386+{-# INLINE foldrT #-}
387+foldrT :: MonadIO m => Int -> Stream m Int -> m ()
388+foldrT n = composeN n $ Internal.foldrT S.cons S.nil
389+
390+{-# INLINE foldrTMap #-}
391+foldrTMap :: MonadIO m => Int -> Stream m Int -> m ()
392+foldrTMap n = composeN n $ Internal.foldrT (\x xs -> x + 1 `S.cons` xs) S.nil
393+
394+{-# INLINE takeByTime #-}
395+takeByTime :: NanoSecond64 -> Int -> Stream IO Int -> IO ()
396+takeByTime i n = composeN n (Internal.takeByTime i)
397+
398+#ifdef INSPECTION
399+-- inspect $ hasNoType 'takeByTime ''SPEC
400+inspect $ hasNoTypeClasses 'takeByTime
401+-- inspect $ 'takeByTime `hasNoType` ''D.Step
402+#endif
403+
404+{-# INLINE dropByTime #-}
405+dropByTime :: NanoSecond64 -> Int -> Stream IO Int -> IO ()
406+dropByTime i n = composeN n (Internal.dropByTime i)
407+
408+#ifdef INSPECTION
409+inspect $ hasNoTypeClasses 'dropByTime
410+-- inspect $ 'dropByTime `hasNoType` ''D.Step
411+#endif
412+
413+-------------------------------------------------------------------------------
414+-- Pipes
415+-------------------------------------------------------------------------------
416+
417+{-# INLINE transformMapM #-}
418+transformMapM ::
419+ (S.IsStream t, S.MonadAsync m)
420+ => (t m Int -> S.SerialT m Int)
421+ -> Int
422+ -> t m Int
423+ -> m ()
424+transformMapM t n = composeN' n $ t . Internal.transform (Pipe.mapM return)
425+
426+{-# INLINE transformComposeMapM #-}
427+transformComposeMapM ::
428+ (S.IsStream t, S.MonadAsync m)
429+ => (t m Int -> S.SerialT m Int)
430+ -> Int
431+ -> t m Int
432+ -> m ()
433+transformComposeMapM t n =
434+ composeN' n $
435+ t .
436+ Internal.transform
437+ (Pipe.mapM (\x -> return (x + 1)) `Pipe.compose`
438+ Pipe.mapM (\x -> return (x + 2)))
439+
440+{-# INLINE transformTeeMapM #-}
441+transformTeeMapM ::
442+ (S.IsStream t, S.MonadAsync m)
443+ => (t m Int -> S.SerialT m Int)
444+ -> Int
445+ -> t m Int
446+ -> m ()
447+transformTeeMapM t n =
448+ composeN' n $
449+ t .
450+ Internal.transform
451+ (Pipe.mapM (\x -> return (x + 1)) `Pipe.tee`
452+ Pipe.mapM (\x -> return (x + 2)))
453+
454+{-# INLINE transformZipMapM #-}
455+transformZipMapM ::
456+ (S.IsStream t, S.MonadAsync m)
457+ => (t m Int -> S.SerialT m Int)
458+ -> Int
459+ -> t m Int
460+ -> m ()
461+transformZipMapM t n =
462+ composeN' n $
463+ t .
464+ Internal.transform
465+ (Pipe.zipWith
466+ (+)
467+ (Pipe.mapM (\x -> return (x + 1)))
468+ (Pipe.mapM (\x -> return (x + 2))))
469+
470+
471+-------------------------------------------------------------------------------
472+-- Mixed Transformation
473+-------------------------------------------------------------------------------
474+
475+{-# INLINE scanMap #-}
476+scanMap :: MonadIO m => Int -> Stream m Int -> m ()
477+scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
478+
479+{-# INLINE dropMap #-}
480+dropMap :: MonadIO m => Int -> Stream m Int -> m ()
481+dropMap n = composeN n $ S.map (subtract 1) . S.drop 1
482+
483+{-# INLINE dropScan #-}
484+dropScan :: MonadIO m => Int -> Stream m Int -> m ()
485+dropScan n = composeN n $ S.scanl' (+) 0 . S.drop 1
486+
487+{-# INLINE takeDrop #-}
488+takeDrop :: MonadIO m => Int -> Int -> Stream m Int -> m ()
489+takeDrop value n = composeN n $ S.drop 1 . S.take (value + 1)
490+
491+{-# INLINE takeScan #-}
492+takeScan :: MonadIO m => Int -> Int -> Stream m Int -> m ()
493+takeScan value n = composeN n $ S.scanl' (+) 0 . S.take (value + 1)
494+
495+{-# INLINE takeMap #-}
496+takeMap :: MonadIO m => Int -> Int -> Stream m Int -> m ()
497+takeMap value n = composeN n $ S.map (subtract 1) . S.take (value + 1)
498+
499+{-# INLINE filterDrop #-}
500+filterDrop :: MonadIO m => Int -> Int -> Stream m Int -> m ()
501+filterDrop value n = composeN n $ S.drop 1 . S.filter (<= (value + 1))
502+
503+{-# INLINE filterTake #-}
504+filterTake :: MonadIO m => Int -> Int -> Stream m Int -> m ()
505+filterTake value n = composeN n $ S.take (value + 1) . S.filter (<= (value + 1))
506+
507+{-# INLINE filterScan #-}
508+filterScan :: MonadIO m => Int -> Stream m Int -> m ()
509+filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
510+
511+{-# INLINE filterScanl1 #-}
512+filterScanl1 :: MonadIO m => Int -> Stream m Int -> m ()
513+filterScanl1 n = composeN n $ S.scanl1' (+) . S.filter (<= maxBound)
514+
515+{-# INLINE filterMap #-}
516+filterMap :: MonadIO m => Int -> Int -> Stream m Int -> m ()
517+filterMap value n = composeN n $ S.map (subtract 1) . S.filter (<= (value + 1))
518+
519+-------------------------------------------------------------------------------
520+-- Scan and fold
521+-------------------------------------------------------------------------------
522+
523+data Pair a b =
524+ Pair !a !b
525+ deriving (Generic, NFData)
526+
527+{-# INLINE sumProductFold #-}
528+sumProductFold :: Monad m => Stream m Int -> m (Int, Int)
529+sumProductFold = S.foldl' (\(s, p) x -> (s + x, p P.* x)) (0, 1)
530+
531+{-# INLINE sumProductScan #-}
532+sumProductScan :: Monad m => Stream m Int -> m (Pair Int Int)
533+sumProductScan =
534+ S.foldl' (\(Pair _ p) (s0, x) -> Pair s0 (p P.* x)) (Pair 0 1) .
535+ S.scanl' (\(s, _) x -> (s + x, x)) (0, 0)
536+
537+-------------------------------------------------------------------------------
538+-- Iteration
539+-------------------------------------------------------------------------------
540+
541+{-# INLINE iterStreamLen #-}
542+iterStreamLen :: Int
543+iterStreamLen = 10
544+
545+{-# INLINE maxIters #-}
546+maxIters :: Int
547+maxIters = 10000
548+
549+{-# INLINE iterateSource #-}
550+iterateSource ::
551+ S.MonadAsync m
552+ => (Stream m Int -> Stream m Int)
553+ -> Int
554+ -> Int
555+ -> Stream m Int
556+iterateSource g i n = f i (sourceUnfoldrMN iterStreamLen n)
557+ where
558+ f (0 :: Int) m = g m
559+ f x m = g (f (x P.- 1) m)
560+
561+-- this is quadratic
562+{-# INLINE iterateScan #-}
563+iterateScan :: S.MonadAsync m => Int -> Stream m Int
564+iterateScan = iterateSource (S.scanl' (+) 0) (maxIters `div` 10)
565+
566+-- this is quadratic
567+{-# INLINE iterateScanl1 #-}
568+iterateScanl1 :: S.MonadAsync m => Int -> Stream m Int
569+iterateScanl1 = iterateSource (S.scanl1' (+)) (maxIters `div` 10)
570+
571+{-# INLINE iterateMapM #-}
572+iterateMapM :: S.MonadAsync m => Int -> Stream m Int
573+iterateMapM = iterateSource (S.mapM return) maxIters
574+
575+{-# INLINE iterateFilterEven #-}
576+iterateFilterEven :: S.MonadAsync m => Int -> Stream m Int
577+iterateFilterEven = iterateSource (S.filter even) maxIters
578+
579+{-# INLINE iterateTakeAll #-}
580+iterateTakeAll :: S.MonadAsync m => Int -> Int -> Stream m Int
581+iterateTakeAll value = iterateSource (S.take (value + 1)) maxIters
582+
583+{-# INLINE iterateDropOne #-}
584+iterateDropOne :: S.MonadAsync m => Int -> Stream m Int
585+iterateDropOne = iterateSource (S.drop 1) maxIters
586+
587+{-# INLINE iterateDropWhileFalse #-}
588+iterateDropWhileFalse :: S.MonadAsync m => Int -> Int -> Stream m Int
589+iterateDropWhileFalse value =
590+ iterateSource (S.dropWhile (> (value + 1))) maxIters
591+
592+{-# INLINE iterateDropWhileTrue #-}
593+iterateDropWhileTrue :: S.MonadAsync m => Int -> Int -> Stream m Int
594+iterateDropWhileTrue value =
595+ iterateSource (S.dropWhile (<= (value + 1))) maxIters
596+
597+-------------------------------------------------------------------------------
598+-- Monad transformation (hoisting etc.)
599+-------------------------------------------------------------------------------
600+
601+{-# INLINE sourceUnfoldrState #-}
602+sourceUnfoldrState :: (S.IsStream t, S.MonadAsync m)
603+ => Int -> Int -> t (StateT Int m) Int
604+sourceUnfoldrState value n = S.unfoldrM step n
605+ where
606+ step cnt =
607+ if cnt > n + value
608+ then return Nothing
609+ else do
610+ s <- get
611+ put (s + 1)
612+ return (Just (s, cnt + 1))
613+
614+{-# INLINE evalStateT #-}
615+evalStateT :: S.MonadAsync m => Int -> Int -> Stream m Int
616+evalStateT value n = Internal.evalStateT 0 (sourceUnfoldrState value n)
617+
618+{-# INLINE withState #-}
619+withState :: S.MonadAsync m => Int -> Int -> Stream m Int
620+withState value n =
621+ Internal.evalStateT (0 :: Int) (Internal.liftInner (sourceUnfoldrM value n))
622+
623+-------------------------------------------------------------------------------
624+-- Traversable Instance
625+-------------------------------------------------------------------------------
626+
627+{-# INLINE traversableTraverse #-}
628+traversableTraverse :: Stream Identity Int -> IO (Stream Identity Int)
629+traversableTraverse = P.traverse return
630+
631+{-# INLINE traversableSequenceA #-}
632+traversableSequenceA :: Stream Identity Int -> IO (Stream Identity Int)
633+traversableSequenceA = P.sequenceA . P.fmap return
634+
635+{-# INLINE traversableMapM #-}
636+traversableMapM :: Stream Identity Int -> IO (Stream Identity Int)
637+traversableMapM = P.mapM return
638+
639+{-# INLINE traversableSequence #-}
640+traversableSequence :: Stream Identity Int -> IO (Stream Identity Int)
641+traversableSequence = P.sequence . P.fmap return
642+
643+-------------------------------------------------------------------------------
644+-- Benchmark groups
645+-------------------------------------------------------------------------------
646+
647+-- We need a monadic bind here to make sure that the function f does not get
648+-- completely optimized out by the compiler in some cases.
649+
650+-- | Takes a fold method, and uses it with a default source.
651+{-# INLINE benchIOSink #-}
652+benchIOSink
653+ :: (IsStream t, NFData b)
654+ => Int -> String -> (t IO Int -> IO b) -> Benchmark
655+benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . source value
656+
657+-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
658+-- we can't use it as it requires MonadAsync constraint.
659+
660+-- | Takes a source, and uses it with a default drain/fold method.
661+{-# INLINE benchIOSrc #-}
662+benchIOSrc
663+ :: (t IO a -> SerialT IO a)
664+ -> String
665+ -> (Int -> t IO a)
666+ -> Benchmark
667+benchIOSrc t name f =
668+ bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f
669+
670+{-# INLINE benchPureSinkIO #-}
671+benchPureSinkIO
672+ :: NFData b
673+ => Int -> String -> (SerialT Identity Int -> IO b) -> Benchmark
674+benchPureSinkIO value name f =
675+ bench name $ nfIO $ randomRIO (1, 1) >>= f . sourceUnfoldr value
676+
677+-------------------------------------------------------------------------------
678+-- Benchmark groups
679+-------------------------------------------------------------------------------
680+
681+o_1_space_serial_pipes :: Int -> [Benchmark]
682+o_1_space_serial_pipes value =
683+ [ bgroup
684+ "serially"
685+ [ bgroup
686+ "pipes"
687+ [ benchIOSink value "mapM" (transformMapM serially 1)
688+ , benchIOSink
689+ value
690+ "compose"
691+ (transformComposeMapM serially 1)
692+ , benchIOSink value "tee" (transformTeeMapM serially 1)
693+ , benchIOSink value "zip" (transformZipMapM serially 1)
694+ ]
695+ ]
696+ ]
697+
698+o_1_space_serial_pipesX4 :: Int -> [Benchmark]
699+o_1_space_serial_pipesX4 value =
700+ [ bgroup
701+ "serially"
702+ [ bgroup
703+ "pipesX4"
704+ [ benchIOSink value "mapM" (transformMapM serially 4)
705+ , benchIOSink
706+ value
707+ "compose"
708+ (transformComposeMapM serially 4)
709+ , benchIOSink value "tee" (transformTeeMapM serially 4)
710+ , benchIOSink value "zip" (transformZipMapM serially 4)
711+ ]
712+ ]
713+ ]
714+
715+
716+o_1_space_serial_transformer :: Int -> [Benchmark]
717+o_1_space_serial_transformer value =
718+ [ bgroup
719+ "serially"
720+ [ bgroup
721+ "transformer"
722+ [ benchIOSrc serially "evalState" (evalStateT value)
723+ , benchIOSrc serially "withState" (withState value)
724+ ]
725+ ]
726+ ]
727+
728+o_1_space_serial_transformation :: Int -> [Benchmark]
729+o_1_space_serial_transformation value =
730+ [ bgroup
731+ "serially"
732+ [ bgroup
733+ "transformation"
734+ [ benchIOSink value "scanl" (scan 1)
735+ , benchIOSink value "scanl1'" (scanl1' 1)
736+ , benchIOSink value "map" (map 1)
737+ , benchIOSink value "fmap" (fmap 1)
738+ , benchIOSink value "mapM" (mapM serially 1)
739+ , benchIOSink value "mapMaybe" (mapMaybe 1)
740+ , benchIOSink value "mapMaybeM" (mapMaybeM 1)
741+ , bench "sequence" $
742+ nfIO $
743+ randomRIO (1, 1000) >>= \n ->
744+ sequence serially (sourceUnfoldrMAction value n)
745+ , benchIOSink value "findIndices" (findIndices value 1)
746+ , benchIOSink value "elemIndices" (elemIndices value 1)
747+ , benchIOSink value "foldrS" (foldrS 1)
748+ , benchIOSink value "foldrSMap" (foldrSMap 1)
749+ , benchIOSink value "foldrT" (foldrT 1)
750+ , benchIOSink value "foldrTMap" (foldrTMap 1)
751+ , benchIOSink value "tap" (tap 1)
752+ , benchIOSink value "tapRate 1 second" (tapRate 1)
753+ , benchIOSink value "pollCounts 1 second" (pollCounts 1)
754+ , benchIOSink value "tapAsync" (tapAsync 1)
755+ , benchIOSink value "tapAsyncS" (tapAsyncS 1)
756+ , benchIOSink value "timestamped" timestamped
757+ ]
758+ ]
759+ ]
760+
761+o_1_space_serial_transformationX4 :: Int -> [Benchmark]
762+o_1_space_serial_transformationX4 value =
763+ [ bgroup
764+ "serially"
765+ [ bgroup
766+ "transformationX4"
767+ [ benchIOSink value "scan" (scan 4)
768+ , benchIOSink value "scanl1'" (scanl1' 4)
769+ , benchIOSink value "map" (map 4)
770+ , benchIOSink value "fmap" (fmap 4)
771+ , benchIOSink value "mapM" (mapM serially 4)
772+ , benchIOSink value "mapMaybe" (mapMaybe 4)
773+ , benchIOSink value "mapMaybeM" (mapMaybeM 4)
774+ -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
775+ -- sequence serially (sourceUnfoldrMAction n)
776+ , benchIOSink value "findIndices" (findIndices value 4)
777+ , benchIOSink value "elemIndices" (elemIndices value 4)
778+ ]
779+ ]
780+ ]
781+
782+o_1_space_serial_filtering :: Int -> [Benchmark]
783+o_1_space_serial_filtering value =
784+ [ bgroup
785+ "serially"
786+ [ bgroup
787+ "filtering"
788+ [ benchIOSink value "filter-even" (filterEven 1)
789+ , benchIOSink value "filter-all-out" (filterAllOut value 1)
790+ , benchIOSink value "filter-all-in" (filterAllIn value 1)
791+ , benchIOSink value "take-all" (takeAll value 1)
792+ , benchIOSink
793+ value
794+ "takeByTime-all"
795+ (takeByTime (NanoSecond64 maxBound) 1)
796+ , benchIOSink value "takeWhile-true" (takeWhileTrue value 1)
797+ --, benchIOSink value "takeWhileM-true" (_takeWhileMTrue 1)
798+ -- "drop-one" is dual to "last"
799+ , benchIOSink value "drop-one" (dropOne 1)
800+ , benchIOSink value "drop-all" (dropAll value 1)
801+ , benchIOSink
802+ value
803+ "dropByTime-all"
804+ (dropByTime (NanoSecond64 maxBound) 1)
805+ , benchIOSink value "dropWhile-true" (dropWhileTrue value 1)
806+ --, benchIOSink value "dropWhileM-true" (_dropWhileMTrue 1)
807+ , benchIOSink
808+ value
809+ "dropWhile-false"
810+ (dropWhileFalse value 1)
811+ , benchIOSink value "deleteBy" (deleteBy value 1)
812+ , benchIOSink value "intersperse" (intersperse value 1)
813+ , benchIOSink value "insertBy" (insertBy value 1)
814+ ]
815+ ]
816+ ]
817+
818+o_1_space_serial_filteringX4 :: Int -> [Benchmark]
819+o_1_space_serial_filteringX4 value =
820+ [ bgroup
821+ "serially"
822+ [ bgroup
823+ "filteringX4"
824+ [ benchIOSink value "filter-even" (filterEven 4)
825+ , benchIOSink value "filter-all-out" (filterAllOut value 4)
826+ , benchIOSink value "filter-all-in" (filterAllIn value 4)
827+ , benchIOSink value "take-all" (takeAll value 4)
828+ , benchIOSink value "takeWhile-true" (takeWhileTrue value 4)
829+ --, benchIOSink value "takeWhileM-true" (_takeWhileMTrue 4)
830+ , benchIOSink value "drop-one" (dropOne 4)
831+ , benchIOSink value "drop-all" (dropAll value 4)
832+ , benchIOSink value "dropWhile-true" (dropWhileTrue value 4)
833+ --, benchIOSink value "dropWhileM-true" (_dropWhileMTrue 4)
834+ , benchIOSink
835+ value
836+ "dropWhile-false"
837+ (dropWhileFalse value 4)
838+ , benchIOSink value "deleteBy" (deleteBy value 4)
839+ , benchIOSink value "intersperse" (intersperse value 4)
840+ , benchIOSink value "insertBy" (insertBy value 4)
841+ ]
842+ ]
843+ ]
844+
845+
846+o_1_space_serial_mixed :: Int -> [Benchmark]
847+o_1_space_serial_mixed value =
848+ [ bgroup
849+ "serially"
850+ -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
851+ -- library. If scan/fold followed by a map is efficient enough we may not
852+ -- need monolithic implementations of these.
853+ [ bgroup
854+ "mixed"
855+ [ benchIOSink value "scanl-map" (scanMap 1)
856+ , benchIOSink value "foldl-map" foldl'ReduceMap
857+ , benchIOSink value "sum-product-fold" sumProductFold
858+ , benchIOSink value "sum-product-scan" sumProductScan
859+ ]
860+ ]
861+ ]
862+
863+o_1_space_serial_mixedX4 :: Int -> [Benchmark]
864+o_1_space_serial_mixedX4 value =
865+ [ bgroup
866+ "serially"
867+ [ bgroup
868+ "mixedX4"
869+ [ benchIOSink value "scan-map" (scanMap 4)
870+ , benchIOSink value "drop-map" (dropMap 4)
871+ , benchIOSink value "drop-scan" (dropScan 4)
872+ , benchIOSink value "take-drop" (takeDrop value 4)
873+ , benchIOSink value "take-scan" (takeScan value 4)
874+ , benchIOSink value "take-map" (takeMap value 4)
875+ , benchIOSink value "filter-drop" (filterDrop value 4)
876+ , benchIOSink value "filter-take" (filterTake value 4)
877+ , benchIOSink value "filter-scan" (filterScan 4)
878+ , benchIOSink value "filter-scanl1" (filterScanl1 4)
879+ , benchIOSink value "filter-map" (filterMap value 4)
880+ ]
881+ ]
882+ ]
883+
884+o_1_space_wSerial_transformation :: Int -> [Benchmark]
885+o_1_space_wSerial_transformation value =
886+ [ bgroup
887+ "wSerially"
888+ [ bgroup
889+ "transformation"
890+ [benchIOSink value "fmap" $ fmap' wSerially 1]
891+ ]
892+ ]
893+
894+o_1_space_zipSerial_transformation :: Int -> [Benchmark]
895+o_1_space_zipSerial_transformation value =
896+ [ bgroup
897+ "zipSerially"
898+ [ bgroup
899+ "transformation"
900+ [benchIOSink value "fmap" $ fmap' zipSerially 1]
901+ -- XXX needs fixing
902+ {-
903+ , bgroup "outer-product"
904+ [ benchIO "toNullAp" $ Nested.toNullAp value zipSerially
905+ ]
906+ -}
907+ ]
908+ ]
909+
910+
911+o_n_space_serial :: Int -> [Benchmark]
912+o_n_space_serial value =
913+ [ bgroup
914+ "serially"
915+ -- Buffering operations using heap proportional to number of elements.
916+ [ bgroup
917+ "traversable" -- < 2MB
918+ -- Traversable instance
919+ [ benchPureSinkIO value "traverse" traversableTraverse
920+ , benchPureSinkIO value "sequenceA" traversableSequenceA
921+ , benchPureSinkIO value "mapM" traversableMapM
922+ , benchPureSinkIO value "sequence" traversableSequence
923+ ]
924+ , benchIOSink (value `div` 10) "classifySessionsOf"
925+ classifySessionsOf
926+ ]
927+ ]
928+
929+
930+-- Head recursive operations.
931+o_n_stack_serial_iterated :: Int -> [Benchmark]
932+o_n_stack_serial_iterated value =
933+ [ bgroup
934+ "serially"
935+ [ bgroup
936+ "iterated"
937+ [ benchIOSrc serially "mapMx10K" iterateMapM
938+ , benchIOSrc serially "scanx100" iterateScan
939+ , benchIOSrc serially "scanl1x100" iterateScanl1
940+ , benchIOSrc serially "filterEvenx10K" iterateFilterEven
941+ , benchIOSrc serially "takeAllx10K" (iterateTakeAll value)
942+ , benchIOSrc serially "dropOnex10K" iterateDropOne
943+ , benchIOSrc
944+ serially
945+ "dropWhileFalsex10K"
946+ (iterateDropWhileFalse value)
947+ , benchIOSrc
948+ serially
949+ "dropWhileTruex10K"
950+ (iterateDropWhileTrue value)
951+ , benchIOSink value "tail" tail
952+ , benchIOSink value "nullHeadTail" nullHeadTail
953+ ]
954+ ]
955+ ]
956+
957+
958+o_1_space_async_transformation :: Int -> [Benchmark]
959+o_1_space_async_transformation value =
960+ [ bgroup
961+ "asyncly"
962+ [ bgroup
963+ "transformation"
964+ [ benchIOSink value "map" $ map' asyncly 1
965+ , benchIOSink value "fmap" $ fmap' asyncly 1
966+ , benchIOSink value "mapM" $ mapM asyncly 1
967+ ]
968+ ]
969+ ]
970+
971+
972+o_1_space_wAsync_transformation :: Int -> [Benchmark]
973+o_1_space_wAsync_transformation value =
974+ [ bgroup
975+ "wAsyncly"
976+ [ bgroup
977+ "transformation"
978+ [ benchIOSink value "map" $ map' wAsyncly 1
979+ , benchIOSink value "fmap" $ fmap' wAsyncly 1
980+ , benchIOSink value "mapM" $ mapM wAsyncly 1
981+ ]
982+ ]
983+ ]
984+
985+
986+
987+o_1_space_ahead_transformation :: Int -> [Benchmark]
988+o_1_space_ahead_transformation value =
989+ [ bgroup
990+ "aheadly"
991+ [ bgroup
992+ "transformation"
993+ [ benchIOSink value "map" $ map' aheadly 1
994+ , benchIOSink value "fmap" $ fmap' aheadly 1
995+ , benchIOSink value "mapM" $ mapM aheadly 1
996+ ]
997+ ]
998+ ]
999+
1000+
1001+
1002+o_n_space_parallel_transformation :: Int -> [Benchmark]
1003+o_n_space_parallel_transformation value =
1004+ [ bgroup
1005+ "parallely"
1006+ [ bgroup
1007+ "transformation"
1008+ [ benchIOSink value "map" $ map' parallely 1
1009+ , benchIOSink value "fmap" $ fmap' parallely 1
1010+ , benchIOSink value "mapM" $ mapM parallely 1
1011+ ]
1012+ ]
1013+ ]
benchmark/streamly-benchmarks.cabal+4
@@ -139,6 +139,10 @@ library lib-prelude
139139 Streamly.Benchmark.Prelude
140140 other-modules: Streamly.Benchmark.Common
141141 , Streamly.Benchmark.Prelude.NestedOps
142+ , Streamly.Benchmark.Prelude.Generation
143+ , Streamly.Benchmark.Prelude.Elimination
144+ , Streamly.Benchmark.Prelude.Transformation
145+
142146 -- XXX GHCJS build fails for this library.
143147 if impl(ghcjs)
144148 buildable: False
streamly.cabal+1
@@ -138,6 +138,7 @@ extra-source-files:
138138 benchmark/README.md
139139 benchmark/*.hs
140140 benchmark/lib/Streamly/Benchmark/*.hs
141+ benchmark/lib/Streamly/Benchmark/Prelude/*.hs
141142 benchmark/Streamly/Benchmark/Memory/*.hs
142143 benchmark/Streamly/Benchmark/Data/*.hs
143144 benchmark/Streamly/Benchmark/Data/Prim/*.hs