2-- Module : Streamly.Benchmark.Data.Stream.StreamK
3-- Copyright : (c) 2018 Harendra Kumar
6-- Maintainer : streamly@composewell.com
9{-# LANGUAGE FlexibleContexts #-}
10{-# LANGUAGE ScopedTypeVariables #-}
12#ifdef __HADDOCK_VERSION__
17{-# LANGUAGE TemplateHaskell #-}
18{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
21module Main (main) where
23import Control.Monad (when)
24import Data.Maybe (isJust)
25import System.Random (randomRIO)
27 (tail, mapM_, foldl, last, map, mapM, concatMap, zip, init)
29import qualified Prelude as P
30import qualified Data.List as List
32import qualified Streamly.Internal.Data.Stream.StreamK as S
33import qualified Streamly.Internal.Data.Stream.Prelude as SP
34import qualified Streamly.Internal.Data.SVar as S
36import Gauge (bench, nfIO, bgroup, Benchmark, defaultMain)
38import Streamly.Benchmark.Common
44value, value2, value3, value16, maxValue :: Int
46value2 = round (P.fromIntegral value**(1/2::P.Double)) -- double nested loop
47value3 = round (P.fromIntegral value**(1/3::P.Double)) -- triple nested loop
48value16 = round (P.fromIntegral value**(1/16::P.Double)) -- triple nested loop
51-------------------------------------------------------------------------------
53-------------------------------------------------------------------------------
57{-# INLINE nullTail #-}
58{-# INLINE headTail #-}
60toNull, uncons, nullTail, headTail, zip
62 => Stream m Int -> m ()
65toList :: Monad m => Stream m Int -> m [Int]
67foldl :: Monad m => Stream m Int -> m Int
69last :: Monad m => Stream m Int -> m (Maybe Int)
71-------------------------------------------------------------------------------
72-- Stream generation and elimination
73-------------------------------------------------------------------------------
75type Stream m a = S.Stream m a
77{-# INLINE sourceUnfoldr #-}
78sourceUnfoldr :: Int -> Stream m Int
79sourceUnfoldr n = S.unfoldr step n
84 else Just (cnt, cnt + 1)
86{-# INLINE sourceUnfoldrN #-}
87sourceUnfoldrN :: Int -> Int -> Stream m Int
88sourceUnfoldrN m n = S.unfoldr step n
93 else Just (cnt, cnt + 1)
95{-# INLINE sourceUnfoldrM #-}
96sourceUnfoldrM :: S.MonadAsync m => Int -> Stream m Int
97sourceUnfoldrM n = S.unfoldrM step n
102 else return (Just (cnt, cnt + 1))
104{-# INLINE sourceUnfoldrMN #-}
105sourceUnfoldrMN :: S.MonadAsync m => Int -> Int -> Stream m Int
106sourceUnfoldrMN m n = S.unfoldrM step n
111 else return (Just (cnt, cnt + 1))
113{-# INLINE sourceFromFoldable #-}
114sourceFromFoldable :: Int -> Stream m Int
115sourceFromFoldable n = S.fromFoldable [n..n+value]
117{-# INLINE sourceFromFoldableM #-}
118sourceFromFoldableM :: S.MonadAsync m => Int -> Stream m Int
119sourceFromFoldableM n =
120 Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+value])
122{-# INLINE sourceFoldMapWith #-}
123sourceFoldMapWith :: Int -> Stream m Int
124sourceFoldMapWith n = SP.concatMapFoldableWith S.serial S.yield [n..n+value]
126{-# INLINE sourceFoldMapWithM #-}
127sourceFoldMapWithM :: Monad m => Int -> Stream m Int
128sourceFoldMapWithM n = SP.concatMapFoldableWith S.serial (S.yieldM . return) [n..n+value]
130-------------------------------------------------------------------------------
132-------------------------------------------------------------------------------
134{-# INLINE runStream #-}
135runStream :: Monad m => Stream m a -> m ()
137-- runStream = S.mapM_ (\_ -> return ())
140mapM_ :: Monad m => Stream m a -> m ()
141mapM_ = S.mapM_ (\_ -> return ())
148 Just (_, t) -> uncons t
151init :: (Monad m, S.IsStream t) => t m a -> m ()
157tail :: (Monad m, S.IsStream t) => t m a -> m ()
158tail s = S.tail s >>= P.mapM_ tail
162 when (not r) $ S.tail s >>= P.mapM_ nullTail
166 when (isJust h) $ S.tail s >>= P.mapM_ headTail
169foldl = S.foldl' (+) 0
172-------------------------------------------------------------------------------
174-------------------------------------------------------------------------------
176{-# INLINE transform #-}
177transform :: Monad m => Stream m a -> m ()
180{-# INLINE composeN #-}
183 => Int -> (Stream m Int -> Stream m Int) -> Stream m Int -> m ()
187 2 -> transform . f . f
188 3 -> transform . f . f . f
189 4 -> transform . f . f . f . f
195{-# INLINE filterEven #-}
196{-# INLINE filterAllOut #-}
197{-# INLINE filterAllIn #-}
198{-# INLINE _takeOne #-}
199{-# INLINE takeAll #-}
200{-# INLINE takeWhileTrue #-}
201{-# INLINE dropOne #-}
202{-# INLINE dropAll #-}
203{-# INLINE dropWhileTrue #-}
204{-# INLINE dropWhileFalse #-}
207scan, map, fmapK, filterEven, filterAllOut,
208 filterAllIn, _takeOne, takeAll, takeWhileTrue, dropAll, dropOne,
209 dropWhileTrue, dropWhileFalse, foldrS, foldlS
211 => Int -> Stream m Int -> m ()
214{-# INLINE mapMSerial #-}
215{-# INLINE intersperse #-}
216mapM, mapMSerial, intersperse
217 :: S.MonadAsync m => Int -> Stream m Int -> m ()
219scan n = composeN n $ S.scanl' (+) 0
220map n = composeN n $ P.fmap (+1)
221fmapK n = composeN n $ P.fmap (+1)
222mapM n = composeN n $ S.mapM return
223mapMSerial n = composeN n $ S.mapMSerial return
224filterEven n = composeN n $ S.filter even
225filterAllOut n = composeN n $ S.filter (> maxValue)
226filterAllIn n = composeN n $ S.filter (<= maxValue)
227_takeOne n = composeN n $ S.take 1
228takeAll n = composeN n $ S.take maxValue
229takeWhileTrue n = composeN n $ S.takeWhile (<= maxValue)
230dropOne n = composeN n $ S.drop 1
231dropAll n = composeN n $ S.drop maxValue
232dropWhileTrue n = composeN n $ S.dropWhile (<= maxValue)
233dropWhileFalse n = composeN n $ S.dropWhile (<= 1)
234foldrS n = composeN n $ S.foldrS S.cons S.nil
235foldlS n = composeN n $ S.foldlS (flip S.cons) S.nil
236intersperse n = composeN n $ S.intersperse maxValue
238-------------------------------------------------------------------------------
240-------------------------------------------------------------------------------
242iterStreamLen, maxIters :: Int
246{-# INLINE iterateSource #-}
249 => (Stream m Int -> Stream m Int) -> Int -> Int -> Stream m Int
250iterateSource g i n = f i (sourceUnfoldrMN iterStreamLen n)
253 f x m = g (f (x P.- 1) m)
255{-# INLINE iterateMapM #-}
256{-# INLINE iterateScan #-}
257{-# INLINE iterateFilterEven #-}
258{-# INLINE iterateTakeAll #-}
259{-# INLINE iterateDropOne #-}
260{-# INLINE iterateDropWhileFalse #-}
261{-# INLINE iterateDropWhileTrue #-}
262iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
263 iterateDropWhileFalse, iterateDropWhileTrue
265 => Int -> Stream m Int
268iterateScan = iterateSource (S.scanl' (+) 0) (maxIters `div` 10)
269iterateDropWhileFalse = iterateSource (S.dropWhile (> maxValue))
272iterateMapM = iterateSource (S.mapM return) maxIters
273iterateFilterEven = iterateSource (S.filter even) maxIters
274iterateTakeAll = iterateSource (S.take maxValue) maxIters
275iterateDropOne = iterateSource (S.drop 1) maxIters
276iterateDropWhileTrue = iterateSource (S.dropWhile (<= maxValue)) maxIters
278-------------------------------------------------------------------------------
280-------------------------------------------------------------------------------
282zip src = transform $ S.zipWith (,) src src
284-------------------------------------------------------------------------------
286-------------------------------------------------------------------------------
288{-# INLINE scanMap #-}
289{-# INLINE dropMap #-}
290{-# INLINE dropScan #-}
291{-# INLINE takeDrop #-}
292{-# INLINE takeScan #-}
293{-# INLINE takeMap #-}
294{-# INLINE filterDrop #-}
295{-# INLINE filterTake #-}
296{-# INLINE filterScan #-}
297{-# INLINE filterMap #-}
298scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
299 filterTake, filterScan, filterMap
300 :: Monad m => Int -> Stream m Int -> m ()
302scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
303dropMap n = composeN n $ S.map (subtract 1) . S.drop 1
304dropScan n = composeN n $ S.scanl' (+) 0 . S.drop 1
305takeDrop n = composeN n $ S.drop 1 . S.take maxValue
306takeScan n = composeN n $ S.scanl' (+) 0 . S.take maxValue
307takeMap n = composeN n $ S.map (subtract 1) . S.take maxValue
308filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
309filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
310filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
311filterMap n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
313-------------------------------------------------------------------------------
315-------------------------------------------------------------------------------
317-- concatMap unfoldrM/unfoldrM
319{-# INLINE concatMap #-}
320concatMap :: Int -> Int -> Int -> IO ()
321concatMap outer inner n =
322 S.drain $ S.concatMap
323 (\_ -> sourceUnfoldrMN inner n)
324 (sourceUnfoldrMN outer n)
327inspect $ hasNoTypeClasses 'concatMap
330-- concatMap unfoldr/unfoldr
332{-# INLINE concatMapPure #-}
333concatMapPure :: Int -> Int -> Int -> IO ()
334concatMapPure outer inner n =
335 S.drain $ S.concatMap
336 (\_ -> sourceUnfoldrN inner n)
337 (sourceUnfoldrN outer n)
340inspect $ hasNoTypeClasses 'concatMapPure
343-- concatMap replicate/unfoldrM
345{-# INLINE concatMapRepl #-}
346concatMapRepl :: Int -> Int -> Int -> IO ()
347concatMapRepl outer inner n =
348 S.drain $ S.concatMap (S.replicate inner) (sourceUnfoldrMN outer n)
351inspect $ hasNoTypeClasses 'concatMapRepl
356{-# INLINE sourceConcatMapId #-}
357sourceConcatMapId :: Monad m
358 => Int -> Int -> Stream m (Stream m Int)
359sourceConcatMapId val n =
360 S.fromFoldable $ fmap (S.yieldM . return) [n..n+val]
362{-# INLINE concatStreamsWith #-}
363concatStreamsWith :: Int -> Int -> Int -> IO ()
364concatStreamsWith outer inner n =
365 S.drain $ S.concatMapBy S.serial
366 (sourceUnfoldrMN inner)
367 (sourceUnfoldrMN outer n)
369-------------------------------------------------------------------------------
371-------------------------------------------------------------------------------
373{-# INLINE toNullApNested #-}
374toNullApNested :: Monad m => Stream m Int -> m ()
375toNullApNested s = runStream $ do
378{-# INLINE toNullNested #-}
379toNullNested :: Monad m => Stream m Int -> m ()
380toNullNested s = runStream $ do
385{-# INLINE toNullNested3 #-}
386toNullNested3 :: Monad m => Stream m Int -> m ()
387toNullNested3 s = runStream $ do
393{-# INLINE filterAllOutNested #-}
396 => Stream m Int -> m ()
397filterAllOutNested str = runStream $ do
405{-# INLINE filterAllInNested #-}
408 => Stream m Int -> m ()
409filterAllInNested str = runStream $ do
417-------------------------------------------------------------------------------
418-- Nested Composition Pure lists
419-------------------------------------------------------------------------------
421{-# INLINE sourceUnfoldrList #-}
422sourceUnfoldrList :: Int -> Int -> [Int]
423sourceUnfoldrList maxval n = List.unfoldr step n
428 else Just (cnt, cnt + 1)
430{-# INLINE toNullApNestedList #-}
431toNullApNestedList :: [Int] -> [Int]
432toNullApNestedList s = (+) <$> s <*> s
434{-# INLINE toNullNestedList #-}
435toNullNestedList :: [Int] -> [Int]
436toNullNestedList s = do
441{-# INLINE toNullNestedList3 #-}
442toNullNestedList3 :: [Int] -> [Int]
443toNullNestedList3 s = do
449{-# INLINE filterAllOutNestedList #-}
450filterAllOutNestedList :: [Int] -> [Int]
451filterAllOutNestedList str = do
459{-# INLINE filterAllInNestedList #-}
460filterAllInNestedList :: [Int] -> [Int]
461filterAllInNestedList str = do
469-------------------------------------------------------------------------------
471-------------------------------------------------------------------------------
474moduleName = "Data.Stream.StreamK"
476o_1_space :: [Benchmark]
478 [ bgroup (o_1_space_prefix moduleName)
479 [ bgroup "generation"
480 [ benchFold "unfoldr" toNull sourceUnfoldr
481 , benchFold "unfoldrM" toNull sourceUnfoldrM
483 , benchFold "fromFoldable" toNull sourceFromFoldable
484 , benchFold "fromFoldableM" toNull sourceFromFoldableM
487 , benchFold "concatMapFoldableWith" toNull sourceFoldMapWith
488 , benchFold "concatMapFoldableWithM" toNull sourceFoldMapWithM
490 , bgroup "elimination"
491 [ benchFold "toNull" toNull sourceUnfoldrM
492 , benchFold "mapM_" mapM_ sourceUnfoldrM
493 , benchFold "uncons" uncons sourceUnfoldrM
494 , benchFold "init" init sourceUnfoldrM
495 , benchFold "foldl'" foldl sourceUnfoldrM
496 , benchFold "last" last sourceUnfoldrM
499 [ benchFold "toNullAp" toNullApNested (sourceUnfoldrMN value2)
500 , benchFold "toNull" toNullNested (sourceUnfoldrMN value2)
501 , benchFold "toNull3" toNullNested3 (sourceUnfoldrMN value3)
502 , benchFold "filterAllIn" filterAllInNested (sourceUnfoldrMN value2)
503 , benchFold "filterAllOut" filterAllOutNested (sourceUnfoldrMN value2)
504 , benchFold "toNullApPure" toNullApNested (sourceUnfoldrN value2)
505 , benchFold "toNullPure" toNullNested (sourceUnfoldrN value2)
506 , benchFold "toNull3Pure" toNullNested3 (sourceUnfoldrN value3)
507 , benchFold "filterAllInPure" filterAllInNested (sourceUnfoldrN value2)
508 , benchFold "filterAllOutPure" filterAllOutNested (sourceUnfoldrN value2)
510 , bgroup "transformation"
511 [ benchFold "foldrS" (foldrS 1) sourceUnfoldrM
512 , benchFold "scan" (scan 1) sourceUnfoldrM
513 , benchFold "map" (map 1) sourceUnfoldrM
514 , benchFold "fmap" (fmapK 1) sourceUnfoldrM
515 , benchFold "mapM" (mapM 1) sourceUnfoldrM
516 , benchFold "mapMSerial" (mapMSerial 1) sourceUnfoldrM
518 , bgroup "transformationX4"
519 [ benchFold "scan" (scan 4) sourceUnfoldrM
520 , benchFold "map" (map 4) sourceUnfoldrM
521 , benchFold "fmap" (fmapK 4) sourceUnfoldrM
522 , benchFold "mapM" (mapM 4) sourceUnfoldrM
523 , benchFold "mapMSerial" (mapMSerial 4) sourceUnfoldrM
524 -- XXX this is horribly slow
525 -- , benchFold "concatMap" (concatMap 4) (sourceUnfoldrMN value16)
528 [ benchIOSrc1 "concatMapPure (n of 1)"
529 (concatMapPure value 1)
530 , benchIOSrc1 "concatMapPure (sqrt n of sqrt n)"
531 (concatMapPure value2 value2)
532 , benchIOSrc1 "concatMapPure (1 of n)"
533 (concatMapPure 1 value)
535 , benchIOSrc1 "concatMap (n of 1)"
537 , benchIOSrc1 "concatMap (sqrt n of sqrt n)"
538 (concatMap value2 value2)
539 , benchIOSrc1 "concatMap (1 of n)"
542 , benchIOSrc1 "concatMapRepl (sqrt n of sqrt n)"
543 (concatMapRepl value2 value2)
545 -- This is for comparison with concatMapFoldableWith
546 , benchIOSrc1 "concatMapWithId (n of 1) (fromFoldable)"
547 (S.drain . S.concatMapBy S.serial id . sourceConcatMapId value)
549 , benchIOSrc1 "concatMapWith (n of 1)"
550 (concatStreamsWith value 1)
551 , benchIOSrc1 "concatMapWith (sqrt n of sqrt n)"
552 (concatStreamsWith value2 value2)
553 , benchIOSrc1 "concatMapWith (1 of n)"
554 (concatStreamsWith 1 value)
557 [ benchFold "filter-even" (filterEven 1) sourceUnfoldrM
558 , benchFold "filter-all-out" (filterAllOut 1) sourceUnfoldrM
559 , benchFold "filter-all-in" (filterAllIn 1) sourceUnfoldrM
560 , benchFold "take-all" (takeAll 1) sourceUnfoldrM
561 , benchFold "takeWhile-true" (takeWhileTrue 1) sourceUnfoldrM
562 , benchFold "drop-one" (dropOne 1) sourceUnfoldrM
563 , benchFold "drop-all" (dropAll 1) sourceUnfoldrM
564 , benchFold "dropWhile-true" (dropWhileTrue 1) sourceUnfoldrM
565 , benchFold "dropWhile-false" (dropWhileFalse 1) sourceUnfoldrM
567 , bgroup "filteringX4"
568 [ benchFold "filter-even" (filterEven 4) sourceUnfoldrM
569 , benchFold "filter-all-out" (filterAllOut 4) sourceUnfoldrM
570 , benchFold "filter-all-in" (filterAllIn 4) sourceUnfoldrM
571 , benchFold "take-all" (takeAll 4) sourceUnfoldrM
572 , benchFold "takeWhile-true" (takeWhileTrue 4) sourceUnfoldrM
573 , benchFold "drop-one" (dropOne 4) sourceUnfoldrM
574 , benchFold "drop-all" (dropAll 4) sourceUnfoldrM
575 , benchFold "dropWhile-true" (dropWhileTrue 4) sourceUnfoldrM
576 , benchFold "dropWhile-false" (dropWhileFalse 4) sourceUnfoldrM
579 [ benchFold "zip" zip sourceUnfoldrM
582 [ benchFold "scan-map" (scanMap 1) sourceUnfoldrM
583 , benchFold "drop-map" (dropMap 1) sourceUnfoldrM
584 , benchFold "drop-scan" (dropScan 1) sourceUnfoldrM
585 , benchFold "take-drop" (takeDrop 1) sourceUnfoldrM
586 , benchFold "take-scan" (takeScan 1) sourceUnfoldrM
587 , benchFold "take-map" (takeMap 1) sourceUnfoldrM
588 , benchFold "filter-drop" (filterDrop 1) sourceUnfoldrM
589 , benchFold "filter-take" (filterTake 1) sourceUnfoldrM
590 , benchFold "filter-scan" (filterScan 1) sourceUnfoldrM
591 , benchFold "filter-map" (filterMap 1) sourceUnfoldrM
594 [ benchFold "scan-map" (scanMap 2) sourceUnfoldrM
595 , benchFold "drop-map" (dropMap 2) sourceUnfoldrM
596 , benchFold "drop-scan" (dropScan 2) sourceUnfoldrM
597 , benchFold "take-drop" (takeDrop 2) sourceUnfoldrM
598 , benchFold "take-scan" (takeScan 2) sourceUnfoldrM
599 , benchFold "take-map" (takeMap 2) sourceUnfoldrM
600 , benchFold "filter-drop" (filterDrop 2) sourceUnfoldrM
601 , benchFold "filter-take" (filterTake 2) sourceUnfoldrM
602 , benchFold "filter-scan" (filterScan 2) sourceUnfoldrM
603 , benchFold "filter-map" (filterMap 2) sourceUnfoldrM
606 [ benchFold "scan-map" (scanMap 4) sourceUnfoldrM
607 , benchFold "drop-map" (dropMap 4) sourceUnfoldrM
608 , benchFold "drop-scan" (dropScan 4) sourceUnfoldrM
609 , benchFold "take-drop" (takeDrop 4) sourceUnfoldrM
610 , benchFold "take-scan" (takeScan 4) sourceUnfoldrM
611 , benchFold "take-map" (takeMap 4) sourceUnfoldrM
612 , benchFold "filter-drop" (filterDrop 4) sourceUnfoldrM
613 , benchFold "filter-take" (filterTake 4) sourceUnfoldrM
614 , benchFold "filter-scan" (filterScan 4) sourceUnfoldrM
615 , benchFold "filter-map" (filterMap 4) sourceUnfoldrM
620o_n_heap :: [Benchmark]
622 [ bgroup (o_n_heap_prefix moduleName)
623 [ bgroup "transformation"
624 [ benchFold "foldlS" (foldlS 1) sourceUnfoldrM
630benchK :: P.String -> (Int -> Stream P.IO Int) -> Benchmark
631benchK name f = bench name $ nfIO $ randomRIO (1,1) >>= toNull . f
633o_n_stack :: [Benchmark]
635 [ bgroup (o_n_stack_prefix moduleName)
636 [ bgroup "elimination"
637 [ benchFold "tail" tail sourceUnfoldrM
638 , benchFold "nullTail" nullTail sourceUnfoldrM
639 , benchFold "headTail" headTail sourceUnfoldrM
641 , bgroup "transformation"
643 -- XXX why do these need so much stack
644 benchFold "intersperse" (intersperse 1) (sourceUnfoldrMN value2)
645 , benchFold "interspersePure" (intersperse 1) (sourceUnfoldrN value2)
647 , bgroup "transformationX4"
649 benchFold "intersperse" (intersperse 4) (sourceUnfoldrMN value16)
652 [ benchK "mapM" iterateMapM
653 , benchK "scan(1/10)" iterateScan
654 , benchK "filterEven" iterateFilterEven
655 , benchK "takeAll" iterateTakeAll
656 , benchK "dropOne" iterateDropOne
657 , benchK "dropWhileFalse(1/10)" iterateDropWhileFalse
658 , benchK "dropWhileTrue" iterateDropWhileTrue
663o_n_space :: [Benchmark]
665 [ bgroup (o_n_space_prefix moduleName)
666 [ bgroup "elimination"
667 [ benchFold "toList" toList sourceUnfoldrM
672{-# INLINE benchList #-}
673benchList :: P.String -> ([Int] -> [Int]) -> (Int -> [Int]) -> Benchmark
674benchList name run f = bench name $ nfIO $ randomRIO (1,1) >>= return . run . f
676o_1_space_list :: [Benchmark]
679 [ bgroup "elimination"
680 [ benchList "last" (\xs -> [List.last xs]) (sourceUnfoldrList value)
683 [ benchList "toNullAp" toNullApNestedList (sourceUnfoldrList value2)
684 , benchList "toNull" toNullNestedList (sourceUnfoldrList value2)
685 , benchList "toNull3" toNullNestedList3 (sourceUnfoldrList value3)
686 , benchList "filterAllIn" filterAllInNestedList (sourceUnfoldrList value2)
687 , benchList "filterAllOut" filterAllOutNestedList (sourceUnfoldrList value2)
693main = defaultMain $ concat
695 , [bgroup (o_1_space_prefix moduleName) o_1_space_list]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list