on efecb26 help sign in
687 lines 23 kB history raw
1-- |
2-- Module : Stream.Transform
3-- Copyright : (c) 2018 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
7{-# LANGUAGE CPP #-}
8{-# LANGUAGE FlexibleContexts #-}
9{-# LANGUAGE FlexibleInstances #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE RankNTypes #-}
13{-# OPTIONS_GHC -Wno-orphans #-}
14#ifdef USE_PRELUDE
15{-# OPTIONS_GHC -Wno-deprecations #-}
16#endif
18#ifdef __HADDOCK_VERSION__
19#undef INSPECTION
20#endif
22#ifdef INSPECTION
23{-# LANGUAGE TemplateHaskell #-}
24{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
25#endif
27module Stream.Transform (benchmarks) where
29import Control.Monad.IO.Class (MonadIO(..))
31import System.Random (randomRIO)
33import qualified Streamly.Internal.Data.Fold as FL
35import qualified Stream.Common as Common
36import qualified Streamly.Internal.Data.Unfold as Unfold
38#ifdef USE_PRELUDE
39import Control.DeepSeq (NFData(..))
40import Data.Functor.Identity (Identity(..))
41import qualified Prelude
42import qualified Streamly.Internal.Data.Fold as Fold
43import qualified Streamly.Internal.Data.Stream.IsStream as Stream
44import Streamly.Internal.Data.Time.Units
45#else
46import Streamly.Internal.Data.Stream (Stream)
47import qualified Streamly.Internal.Data.Stream as Stream
48#ifndef USE_STREAMLY_CORE
49import qualified Streamly.Internal.Data.Stream.Time as Stream
50#endif
51#ifdef USE_STREAMK
52import Control.DeepSeq (NFData(..))
53import Data.Functor.Identity (Identity(..))
54import qualified Prelude
55import qualified Streamly.Internal.Data.Fold as Fold
56import Streamly.Internal.Data.StreamK (StreamK)
57import qualified Streamly.Internal.Data.StreamK as StreamK
58#endif
59#endif
61import Gauge
62import Stream.Common hiding (scanl')
63import Streamly.Benchmark.Common
64import Prelude hiding (sequence, mapM)
66#ifdef USE_PRELUDE
67type Stream = Stream.SerialT
68#endif
70-------------------------------------------------------------------------------
71-- Pipelines (stream-to-stream transformations)
72-------------------------------------------------------------------------------
74-------------------------------------------------------------------------------
75-- one-to-one transformations
76-------------------------------------------------------------------------------
78-------------------------------------------------------------------------------
79-- Traversable Instance
80-------------------------------------------------------------------------------
82#ifdef USE_STREAMK
83{-# INLINE traversableTraverse #-}
84traversableTraverse :: StreamK Identity Int -> IO (StreamK Identity Int)
85traversableTraverse = traverse return
87{-# INLINE traversableSequenceA #-}
88traversableSequenceA :: StreamK Identity Int -> IO (StreamK Identity Int)
89traversableSequenceA = sequenceA . Prelude.fmap return
91{-# INLINE traversableMapM #-}
92traversableMapM :: StreamK Identity Int -> IO (StreamK Identity Int)
93traversableMapM = Prelude.mapM return
95{-# INLINE traversableSequence #-}
96traversableSequence :: StreamK Identity Int -> IO (StreamK Identity Int)
97traversableSequence = Prelude.sequence . Prelude.fmap return
99{-# INLINE benchPureSinkIO #-}
100benchPureSinkIO
101 :: NFData b
102 => Int -> String -> (StreamK Identity Int -> IO b) -> Benchmark
103benchPureSinkIO value name f =
104 bench name
105 $ nfIO $ randomRIO (1, 1) >>= f . fromStream . sourceUnfoldr value
107instance NFData a => NFData (StreamK Identity a) where
108 {-# INLINE rnf #-}
109 rnf xs =
110 runIdentity
111 $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) (toStream xs)
113o_n_space_traversable :: Int -> [Benchmark]
114o_n_space_traversable value =
115 -- Buffering operations using heap proportional to number of elements.
116 [ bgroup "traversable"
117 -- Traversable instance
118 [ benchPureSinkIO value "traverse" traversableTraverse
119 , benchPureSinkIO value "sequenceA" traversableSequenceA
120 , benchPureSinkIO value "mapM" traversableMapM
121 , benchPureSinkIO value "sequence" traversableSequence
122 ]
123 ]
124#endif
126-------------------------------------------------------------------------------
127-- maps and scans
128-------------------------------------------------------------------------------
130#ifdef USE_PRELUDE
131{-# INLINE scanl' #-}
132scanl' :: MonadIO m => Int -> Stream m Int -> m ()
133scanl' n = composeN n $ Stream.scanl' (+) 0
135{-# INLINE scanlM' #-}
136scanlM' :: MonadIO m => Int -> Stream m Int -> m ()
137scanlM' n = composeN n $ Stream.scanlM' (\b a -> return $ b + a) (return 0)
139{-# INLINE scanl1' #-}
140scanl1' :: MonadIO m => Int -> Stream m Int -> m ()
141scanl1' n = composeN n $ Stream.scanl1' (+)
143{-# INLINE scanl1M' #-}
144scanl1M' :: MonadIO m => Int -> Stream m Int -> m ()
145scanl1M' n = composeN n $ Stream.scanl1M' (\b a -> return $ b + a)
146#endif
148{-# INLINE scan #-}
149scan :: MonadIO m => Int -> Stream m Int -> m ()
150scan n = composeN n $ Stream.scan FL.sum
152#ifdef USE_PRELUDE
153{-# INLINE postscanl' #-}
154postscanl' :: MonadIO m => Int -> Stream m Int -> m ()
155postscanl' n = composeN n $ Stream.postscanl' (+) 0
157{-# INLINE postscanlM' #-}
158postscanlM' :: MonadIO m => Int -> Stream m Int -> m ()
159postscanlM' n = composeN n $ Stream.postscanlM' (\b a -> return $ b + a) (return 0)
160#endif
162{-# INLINE postscan #-}
163postscan :: MonadIO m => Int -> Stream m Int -> m ()
164postscan n = composeN n $ Stream.postscan FL.sum
166{-# INLINE sequence #-}
167sequence :: MonadAsync m => Stream m (m Int) -> m ()
168sequence = Common.drain . Stream.sequence
170{-# INLINE tap #-}
171tap :: MonadIO m => Int -> Stream m Int -> m ()
172tap n = composeN n $ Stream.tap FL.sum
174#ifdef USE_PRELUDE
175{-# INLINE pollCounts #-}
176pollCounts :: Int -> Stream IO Int -> IO ()
177pollCounts n =
178 composeN n (Stream.pollCounts (const True) f)
180 where
182 f = Stream.drain . Stream.rollingMap2 (-) . Stream.delayPost 1
184{-# INLINE timestamped #-}
185timestamped :: (MonadAsync m) => Stream m Int -> m ()
186timestamped = Stream.drain . Stream.timestamped
187#endif
189#ifdef USE_STREAMK
190{-# INLINE foldrS #-}
191foldrS :: MonadIO m => Int -> Stream m Int -> m ()
192foldrS n =
193 composeN n (toStream . StreamK.foldrS StreamK.cons StreamK.nil . fromStream)
195{-# INLINE foldrSMap #-}
196foldrSMap :: MonadIO m => Int -> Stream m Int -> m ()
197foldrSMap n =
198 composeN n
199 ( toStream
200 . StreamK.foldrS (\x xs -> x + 1 `StreamK.cons` xs) StreamK.nil
201 . fromStream
202 )
203#endif
205{-
206{-# INLINE foldrT #-}
207foldrT :: MonadIO m => Int -> Stream m Int -> m ()
208foldrT n = composeN n (unCrossStream . Stream.foldrT cns (CrossStream Stream.nil))
210 where cns x (CrossStream xs) = CrossStream (Stream.cons x xs)
212{-# INLINE foldrTMap #-}
213foldrTMap :: MonadIO m => Int -> Stream m Int -> m ()
214foldrTMap n = composeN n $ Stream.foldrT (\x xs -> x + 1 `Stream.cons` xs) Stream.nil
215-}
217{-# INLINE trace #-}
218trace :: MonadAsync m => Int -> Stream m Int -> m ()
219trace n = composeN n $ Stream.trace return
221o_1_space_mapping :: Int -> [Benchmark]
222o_1_space_mapping value =
223 [ bgroup
224 "mapping"
225 [
226#ifdef USE_STREAMK
227 -- Right folds
228 benchIOSink value "foldrS" (foldrS 1)
229 , benchIOSink value "foldrSMap" (foldrSMap 1)
230 ,
231#endif
232 -- , benchIOSink value "foldrT" (foldrT 1)
233 -- , benchIOSink value "foldrTMap" (foldrTMap 1)
235 -- Mapping
236 benchIOSink value "map" (mapN 1)
237 , bench "sequence" $ nfIO $ randomRIO (1, 1000) >>= \n ->
238 sequence (sourceUnfoldrAction value n)
239 , benchIOSink value "mapM" (mapM 1)
240 , benchIOSink value "tap" (tap 1)
241#ifdef USE_PRELUDE
242 , benchIOSink value "pollCounts 1 second" (pollCounts 1)
243 , benchIOSink value "timestamped" timestamped
245 -- Scanning
246 , benchIOSink value "scanl'" (scanl' 1)
247 , benchIOSink value "scanl1'" (scanl1' 1)
248 , benchIOSink value "scanlM'" (scanlM' 1)
249 , benchIOSink value "scanl1M'" (scanl1M' 1)
250 , benchIOSink value "postscanl'" (postscanl' 1)
251 , benchIOSink value "postscanlM'" (postscanlM' 1)
252#endif
253 , benchIOSink value "scan" (scan 1)
254 , benchIOSink value "postscan" (postscan 1)
255 ]
256 ]
258o_1_space_mappingX4 :: Int -> [Benchmark]
259o_1_space_mappingX4 value =
260 [ bgroup "mappingX4"
261 [ benchIOSink value "map" (mapN 4)
262 , benchIOSink value "mapM" (mapM 4)
263 , benchIOSink value "trace" (trace 4)
265#ifdef USE_PRELUDE
266 , benchIOSink value "scanl'" (scanl' 4)
267 , benchIOSink value "scanl1'" (scanl1' 4)
268 , benchIOSink value "scanlM'" (scanlM' 4)
269 , benchIOSink value "scanl1M'" (scanl1M' 4)
270 , benchIOSink value "postscanl'" (postscanl' 4)
271 , benchIOSink value "postscanlM'" (postscanlM' 4)
272#endif
273 ]
274 ]
276{-# INLINE sieveScan #-}
277sieveScan :: Monad m => Stream m Int -> Stream m Int
278sieveScan =
279 Stream.mapMaybe snd
280 . Stream.scan (FL.foldlM' (\(primes, _) n -> do
281 return $
282 let ps = takeWhile (\p -> p * p <= n) primes
283 in if all (\p -> n `mod` p /= 0) ps
284 then (primes ++ [n], Just n)
285 else (primes, Nothing)) (return ([2], Just 2)))
287o_n_space_mapping :: Int -> [Benchmark]
288o_n_space_mapping value =
289 [ bgroup "mapping"
290 [ benchIO "naive prime sieve"
291 (\n -> Stream.fold FL.sum $ sieveScan $ Stream.enumerateFromTo 2 (value + n))
292 ]
293 ]
295-------------------------------------------------------------------------------
296-- Functor
297-------------------------------------------------------------------------------
299o_1_space_functor :: Int -> [Benchmark]
300o_1_space_functor value =
301 [ bgroup "Functor"
302 [ benchIOSink value "fmap" (mapN 1)
303 , benchIOSink value "fmap x 4" (mapN 4)
304 ]
305 ]
307-------------------------------------------------------------------------------
308-- Iteration/looping utilities
309-------------------------------------------------------------------------------
311{-# INLINE iterateN #-}
312iterateN :: (Int -> a -> a) -> a -> Int -> a
313iterateN g initial count = f count initial
315 where
317 f (0 :: Int) x = x
318 f i x = f (i - 1) (g i x)
320#ifdef USE_STREAMK
321-- Iterate a transformation over a singleton stream
322{-# INLINE iterateSingleton #-}
323iterateSingleton :: Applicative m =>
324 (Int -> StreamK m Int -> StreamK m Int)
325 -> Int
326 -> Int
327 -> Stream m Int
328iterateSingleton g count n = toStream $ iterateN g (StreamK.fromPure n) count
329#else
330-- Iterate a transformation over a singleton stream
331{-# INLINE iterateSingleton #-}
332iterateSingleton :: Applicative m =>
333 (Int -> Stream m Int -> Stream m Int)
334 -> Int
335 -> Int
336 -> Stream m Int
337iterateSingleton g count n = iterateN g (Stream.fromPure n) count
338#endif
340{-
341-- XXX need to check why this is slower than the explicit recursion above, even
342-- if the above code is written in a foldr like head recursive way. We also
343-- need to try this with foldlM' once #150 is fixed.
344-- However, it is perhaps best to keep the iteration benchmarks independent of
345-- foldrM and any related fusion issues.
346{-# INLINE _iterateSingleton #-}
347_iterateSingleton ::
348 Monad m
349 => (Int -> Stream m Int -> Stream m Int)
350 -> Int
351 -> Int
352 -> Stream m Int
353_iterateSingleton g value n = S.foldrM g (return n) $ sourceIntFromTo value n
354-}
356o_n_space_iterated :: Int -> [Benchmark]
357o_n_space_iterated value =
358 [ bgroup "iterated"
359 [ benchIO "(+) (n times) (baseline)" $ \i0 ->
360 iterateN (\i acc -> acc >>= \n -> return $ i + n) (return i0) value
361 , benchIOSrc "(<$) (n times)" $
362 iterateSingleton (<$) value
363 , benchIOSrc "fmap (n times)" $
364 iterateSingleton (fmap . (+)) value
365 {-
366 , benchIOSrc fromSerial "_(<$) (n times)" $
367 _iterateSingleton (<$) value
368 , benchIOSrc fromSerial "_fmap (n times)" $
369 _iterateSingleton (fmap . (+)) value
370 -}
371 ]
372 ]
374-------------------------------------------------------------------------------
375-- Size reducing transformations (filtering)
376-------------------------------------------------------------------------------
378{-# INLINE filterEven #-}
379filterEven :: MonadIO m => Int -> Stream m Int -> m ()
380filterEven n = composeN n $ Stream.filter even
382{-# INLINE filterAllOut #-}
383filterAllOut :: MonadIO m => Int -> Int -> Stream m Int -> m ()
384filterAllOut value n = composeN n $ Stream.filter (> (value + 1))
386{-# INLINE filterAllIn #-}
387filterAllIn :: MonadIO m => Int -> Int -> Stream m Int -> m ()
388filterAllIn value n = composeN n $ Stream.filter (<= (value + 1))
390{-# INLINE filterMEven #-}
391filterMEven :: MonadIO m => Int -> Stream m Int -> m ()
392filterMEven n = composeN n $ Stream.filterM (return . even)
394{-# INLINE filterMAllOut #-}
395filterMAllOut :: MonadIO m => Int -> Int -> Stream m Int -> m ()
396filterMAllOut value n = composeN n $ Stream.filterM (\x -> return $ x > (value + 1))
398{-# INLINE filterMAllIn #-}
399filterMAllIn :: MonadIO m => Int -> Int -> Stream m Int -> m ()
400filterMAllIn value n = composeN n $ Stream.filterM (\x -> return $ x <= (value + 1))
402{-# INLINE _takeOne #-}
403_takeOne :: MonadIO m => Int -> Stream m Int -> m ()
404_takeOne n = composeN n $ Stream.take 1
406{-# INLINE takeAll #-}
407takeAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
408takeAll value n = composeN n $ Stream.take (value + 1)
410{-# INLINE takeWhileTrue #-}
411takeWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
412takeWhileTrue value n = composeN n $ Stream.takeWhile (<= (value + 1))
414{-# INLINE takeWhileMTrue #-}
415takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
416takeWhileMTrue value n = composeN n $ Stream.takeWhileM (return . (<= (value + 1)))
418#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE)
419{-# INLINE takeInterval #-}
420takeInterval :: Double -> Int -> Stream IO Int -> IO ()
421takeInterval i n = composeN n (Stream.takeInterval i)
423-- Inspection testing is disabled for takeInterval
424-- Enable it when looking at it throughly
425#ifdef INSPECTION
426-- inspect $ hasNoType 'takeInterval ''SPEC
427-- inspect $ hasNoTypeClasses 'takeInterval
428-- inspect $ 'takeInterval `hasNoType` ''D.Step
429#endif
431{-# INLINE dropInterval #-}
432dropInterval :: Double -> Int -> Stream IO Int -> IO ()
433dropInterval i n = composeN n (Stream.dropInterval i)
435-- Inspection testing is disabled for dropInterval
436-- Enable it when looking at it throughly
437#ifdef INSPECTION
438-- inspect $ hasNoTypeClasses 'dropInterval
439-- inspect $ 'dropInterval `hasNoType` ''D.Step
440#endif
441#endif
443{-# INLINE dropOne #-}
444dropOne :: MonadIO m => Int -> Stream m Int -> m ()
445dropOne n = composeN n $ Stream.drop 1
447{-# INLINE dropAll #-}
448dropAll :: MonadIO m => Int -> Int -> Stream m Int -> m ()
449dropAll value n = composeN n $ Stream.drop (value + 1)
451{-# INLINE dropWhileTrue #-}
452dropWhileTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
453dropWhileTrue value n = composeN n $ Stream.dropWhile (<= (value + 1))
455{-# INLINE dropWhileMTrue #-}
456dropWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
457dropWhileMTrue value n = composeN n $ Stream.dropWhileM (return . (<= (value + 1)))
459{-# INLINE dropWhileFalse #-}
460dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m ()
461dropWhileFalse value n = composeN n $ Stream.dropWhile (> (value + 1))
463#ifdef USE_PRELUDE
464-- XXX Decide on the time interval
465{-# INLINE _intervalsOfSum #-}
466_intervalsOfSum :: MonadAsync m => Double -> Int -> Stream m Int -> m ()
467_intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum)
468#endif
470{-# INLINE findIndices #-}
471findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
472findIndices value n = composeN n $ Stream.findIndices (== (value + 1))
474{-# INLINE elemIndices #-}
475elemIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
476elemIndices value n = composeN n $ Stream.elemIndices (value + 1)
478{-# INLINE deleteBy #-}
479deleteBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
480deleteBy value n = composeN n $ Stream.deleteBy (>=) (value + 1)
482-- uniq . uniq == uniq, composeN 2 ~ composeN 1
483{-# INLINE uniq #-}
484uniq :: MonadIO m => Int -> Stream m Int -> m ()
485uniq n = composeN n Stream.uniq
487{-# INLINE mapMaybe #-}
488mapMaybe :: MonadIO m => Int -> Stream m Int -> m ()
489mapMaybe n =
490 composeN n $
491 Stream.mapMaybe
492 (\x ->
493 if odd x
494 then Nothing
495 else Just x)
497{-# INLINE mapMaybeM #-}
498mapMaybeM :: MonadAsync m => Int -> Stream m Int -> m ()
499mapMaybeM n =
500 composeN n $
501 Stream.mapMaybeM
502 (\x ->
503 if odd x
504 then return Nothing
505 else return $ Just x)
507o_1_space_filtering :: Int -> [Benchmark]
508o_1_space_filtering value =
509 [ bgroup "filtering"
510 [ benchIOSink value "filter-even" (filterEven 1)
511 , benchIOSink value "filter-all-out" (filterAllOut value 1)
512 , benchIOSink value "filter-all-in" (filterAllIn value 1)
514 , benchIOSink value "filterM-even" (filterMEven 1)
515 , benchIOSink value "filterM-all-out" (filterMAllOut value 1)
516 , benchIOSink value "filterM-all-in" (filterMAllIn value 1)
518 -- Trimming
519 , benchIOSink value "take-all" (takeAll value 1)
520 , benchIOSink value "takeWhile-true" (takeWhileTrue value 1)
521 -- , benchIOSink value "takeWhileM-true" (_takeWhileMTrue value 1)
522 , benchIOSink value "drop-one" (dropOne 1)
523 , benchIOSink value "drop-all" (dropAll value 1)
524#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE)
525 , benchIOSink value "takeInterval-all" (takeInterval 10000 1)
526 , benchIOSink value "dropInterval-all" (dropInterval 10000 1)
527#endif
528 , benchIOSink value "dropWhile-true" (dropWhileTrue value 1)
529 -- , benchIOSink value "dropWhileM-true" (_dropWhileMTrue value 1)
530 , benchIOSink
531 value
532 "dropWhile-false"
533 (dropWhileFalse value 1)
534 , benchIOSink value "deleteBy" (deleteBy value 1)
536 , benchIOSink value "uniq" (uniq 1)
538 -- Map and filter
539 , benchIOSink value "mapMaybe" (mapMaybe 1)
540 , benchIOSink value "mapMaybeM" (mapMaybeM 1)
542 -- Searching (stateful map and filter)
543 , benchIOSink value "findIndices" (findIndices value 1)
544 , benchIOSink value "elemIndices" (elemIndices value 1)
545 ]
546 ]
548o_1_space_filteringX4 :: Int -> [Benchmark]
549o_1_space_filteringX4 value =
550 [ bgroup "filteringX4"
551 [ benchIOSink value "filter-even" (filterEven 4)
552 , benchIOSink value "filter-all-out" (filterAllOut value 4)
553 , benchIOSink value "filter-all-in" (filterAllIn value 4)
555 , benchIOSink value "filterM-even" (filterMEven 4)
556 , benchIOSink value "filterM-all-out" (filterMAllOut value 4)
557 , benchIOSink value "filterM-all-in" (filterMAllIn value 4)
559 -- trimming
560 , benchIOSink value "take-all" (takeAll value 4)
561 , benchIOSink value "takeWhile-true" (takeWhileTrue value 4)
562 , benchIOSink value "takeWhileM-true" (takeWhileMTrue value 4)
563 , benchIOSink value "drop-one" (dropOne 4)
564 , benchIOSink value "drop-all" (dropAll value 4)
565 , benchIOSink value "dropWhile-true" (dropWhileTrue value 4)
566 , benchIOSink value "dropWhileM-true" (dropWhileMTrue value 4)
567 , benchIOSink
568 value
569 "dropWhile-false"
570 (dropWhileFalse value 4)
571 , benchIOSink value "deleteBy" (deleteBy value 4)
573 , benchIOSink value "uniq" (uniq 4)
575 -- map and filter
576 , benchIOSink value "mapMaybe" (mapMaybe 4)
577 , benchIOSink value "mapMaybeM" (mapMaybeM 4)
579 -- searching
580 , benchIOSink value "findIndices" (findIndices value 4)
581 , benchIOSink value "elemIndices" (elemIndices value 4)
582 ]
583 ]
585-------------------------------------------------------------------------------
586-- Size increasing transformations (insertions)
587-------------------------------------------------------------------------------
589{-# INLINE intersperse #-}
590intersperse :: MonadAsync m => Int -> Int -> Stream m Int -> m ()
591intersperse value n = composeN n $ Stream.intersperse (value + 1)
593{-# INLINE intersperseM #-}
594intersperseM :: MonadAsync m => Int -> Int -> Stream m Int -> m ()
595intersperseM value n = composeN n $ Stream.intersperseM (return $ value + 1)
597{-# INLINE insertBy #-}
598insertBy :: MonadIO m => Int -> Int -> Stream m Int -> m ()
599insertBy value n = composeN n $ Stream.insertBy compare (value + 1)
601{-# INLINE interposeSuffix #-}
602interposeSuffix :: Monad m => Int -> Int -> Stream m Int -> m ()
603interposeSuffix value n =
604 composeN n $ Stream.interposeSuffix (value + 1) Unfold.identity
606{-# INLINE intercalateSuffix #-}
607intercalateSuffix :: Monad m => Int -> Int -> Stream m Int -> m ()
608intercalateSuffix value n =
609 composeN n $ Stream.intercalateSuffix Unfold.identity (value + 1)
611o_1_space_inserting :: Int -> [Benchmark]
612o_1_space_inserting value =
613 [ bgroup "inserting"
614 [ benchIOSink value "intersperse" (intersperse value 1)
615 , benchIOSink value "intersperseM" (intersperseM value 1)
616 , benchIOSink value "insertBy" (insertBy value 1)
617 , benchIOSink value "interposeSuffix" (interposeSuffix value 1)
618 , benchIOSink value "intercalateSuffix" (intercalateSuffix value 1)
619 ]
620 ]
622o_1_space_insertingX4 :: Int -> [Benchmark]
623o_1_space_insertingX4 value =
624 [ bgroup "insertingX4"
625 [ benchIOSink value "intersperse" (intersperse value 4)
626 , benchIOSink value "insertBy" (insertBy value 4)
627 ]
628 ]
630-------------------------------------------------------------------------------
631-- Indexing
632-------------------------------------------------------------------------------
634{-# INLINE indexed #-}
635indexed :: MonadIO m => Int -> Stream m Int -> m ()
636indexed n = composeN n (fmap snd . Stream.indexed)
638{-# INLINE indexedR #-}
639indexedR :: MonadIO m => Int -> Int -> Stream m Int -> m ()
640indexedR value n = composeN n (fmap snd . Stream.indexedR value)
642o_1_space_indexing :: Int -> [Benchmark]
643o_1_space_indexing value =
644 [ bgroup "indexing"
645 [ benchIOSink value "indexed" (indexed 1)
646 , benchIOSink value "indexedR" (indexedR value 1)
647 ]
648 ]
650o_1_space_indexingX4 :: Int -> [Benchmark]
651o_1_space_indexingX4 value =
652 [ bgroup "indexingx4"
653 [ benchIOSink value "indexed" (indexed 4)
654 , benchIOSink value "indexedR" (indexedR value 4)
655 ]
656 ]
658-------------------------------------------------------------------------------
659-- Main
660-------------------------------------------------------------------------------
662-- In addition to gauge options, the number of elements in the stream can be
663-- passed using the --stream-size option.
664--
665benchmarks :: String -> Int -> [Benchmark]
666benchmarks moduleName size =
667 [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
668 [ o_1_space_functor size
669 , o_1_space_mapping size
670 , o_1_space_mappingX4 size
671 , o_1_space_filtering size
672 , o_1_space_filteringX4 size
673 , o_1_space_inserting size
674 , o_1_space_insertingX4 size
675 , o_1_space_indexing size
676 , o_1_space_indexingX4 size
677 ]
678 , bgroup (o_n_space_prefix moduleName) $ Prelude.concat
679 [
680#ifdef USE_STREAMK
681 o_n_space_traversable size
682 ,
683#endif
684 o_n_space_mapping size
685 , o_n_space_iterated size
686 ]
687 ]