From a54e958e5e8883ba0765dbc8477b37dcb569d2c1 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Thu, 27 Nov 2025 18:49:50 +0530 Subject: [PATCH 01/24] Prepare to remove Streamly.Prelude benchmarks --- .../Streamly/Benchmark/Data/Stream/Common.hs | 82 ++-------- .../Benchmark/Data/Stream/Eliminate.hs | 72 ++------- .../Benchmark/Data/Stream/Exceptions.hs | 23 --- .../Streamly/Benchmark/Data/Stream/Expand.hs | 37 ----- .../Benchmark/Data/Stream/Generate.hs | 46 ++---- .../Streamly/Benchmark/Data/Stream/Lift.hs | 13 -- .../Streamly/Benchmark/Data/Stream/Reduce.hs | 80 +--------- .../Benchmark/Data/Stream/Transform.hs | 53 +------ .../Streamly/Benchmark/Prelude/Adaptive.hs | 143 ------------------ .../Streamly/Benchmark/Prelude/Concurrent.hs | 111 -------------- 10 files changed, 48 insertions(+), 612 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Adaptive.hs delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Concurrent.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Common.hs b/benchmark/Streamly/Benchmark/Data/Stream/Common.hs index bad046667d..4f40a35702 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Common.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Common.hs @@ -9,15 +9,13 @@ -- License : BSD-3-Clause -- Maintainer : streamly@composewell.com -#ifdef USE_PRELUDE -#endif - module Stream.Common ( MonadAsync -- Generation , fromListM , fromFoldableM + , repeat , append , append2 @@ -67,11 +65,9 @@ module Stream.Common , transformComposeMapM , transformTeeMapM -- , transformZipMapM -#ifndef USE_PRELUDE , scanMapM , scanComposeMapM , scanTeeMapM -#endif ) where @@ -88,28 +84,14 @@ import qualified Streamly.Internal.Data.Pipe as Pipe import qualified Streamly.Internal.Data.Scanl as Scanl import qualified Streamly.Internal.Data.Scanr as Scanr -#ifdef USE_PRELUDE -import Streamly.Prelude (foldl', scanl') -import qualified Streamly.Internal.Data.Stream.IsStream as Stream -import qualified Streamly.Prelude as Stream -import Streamly.Benchmark.Prelude - ( composeN, sourceConcatMapId, benchIOSink - ) -#else + import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as D import qualified Streamly.Internal.Data.Stream as Stream -#endif import Test.Tasty.Bench -import Prelude hiding (Foldable(..), mapM, replicate) - -#ifdef USE_PRELUDE -type Stream = Stream.SerialT -type MonadAsync m = Stream.MonadAsync m -mkCross = id -unCross = id -#else +import Prelude hiding (Foldable(..), mapM, replicate, repeat) + type MonadAsync = Monad mkCross :: Stream m a -> Stream.Nested m a @@ -117,52 +99,34 @@ mkCross = Stream.Nested unCross :: Stream.Nested m a -> Stream m a unCross = Stream.unNested -#endif -#ifdef USE_PRELUDE {-# INLINE append #-} append :: Monad m => Stream m a -> Stream m a -> Stream m a -append = Stream.serial -#else -append :: Monad m => Stream m a -> Stream m a -> Stream m a append = Stream.append -#endif {-# INLINE append2 #-} append2 :: Monad m => Stream m a -> Stream m a -> Stream m a -#ifdef USE_PRELUDE -append2 = Stream.append -#else append2 = D.append -#endif {-# INLINE drain #-} drain :: Monad m => Stream m a -> m () +drain = Stream.drain + {-# INLINE toList #-} toList :: Monad m => Stream m a -> m [a] -#ifdef USE_PRELUDE -drain = Stream.drain toList = Stream.toList -#else -drain = Stream.fold Fold.drain -toList = Stream.fold Fold.toList -#endif + +{-# INLINE repeat #-} +repeat :: Monad m => Int -> Int -> Stream m Int +repeat count = Stream.take count . Stream.repeat {-# INLINE fromListM #-} fromListM :: MonadAsync m => [m a] -> Stream m a -#ifdef USE_PRELUDE -fromListM = Stream.fromListM -#else fromListM = Stream.sequence . Stream.fromList -#endif {-# INLINE fromFoldableM #-} fromFoldableM :: MonadAsync m => [m a] -> Stream m a -#ifdef USE_PRELUDE -fromFoldableM = Stream.fromFoldableM -#else fromFoldableM = Stream.sequence . Stream.fromFoldable -#endif {-# INLINE sourceUnfoldrM #-} sourceUnfoldrM :: MonadAsync m => Int -> Int -> Stream m Int @@ -201,7 +165,6 @@ sourceUnfoldrAction value n = Stream.unfoldr step n sourceFromFoldable :: Monad m => Int -> Int -> Stream m Int sourceFromFoldable value n = Stream.fromFoldable [n..n+value] -#ifndef USE_PRELUDE {-# INLINE benchIOSink #-} benchIOSink :: (NFData b) @@ -215,7 +178,6 @@ benchIOSinkPureSrc => Int -> String -> (Stream IO Int -> IO b) -> Benchmark benchIOSinkPureSrc value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldr value -#endif -- | Takes a source, and uses it with a default drain/fold method. {-# INLINE benchIOSrc #-} @@ -230,13 +192,11 @@ benchIOSrc name f = benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f -#ifndef USE_PRELUDE {-# INLINE sourceConcatMapId #-} sourceConcatMapId :: (Monad m) => Int -> Int -> Stream m (Stream m Int) sourceConcatMapId value n = Stream.fromList $ fmap (D.fromEffect . return) [n..n+value] -#endif {-# INLINE apDiscardFst #-} apDiscardFst :: MonadAsync m => @@ -436,7 +396,6 @@ toListSome linearCount start = where nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) -#ifndef USE_PRELUDE {-# INLINE composeN #-} composeN :: (Monad m) @@ -451,7 +410,6 @@ composeN n f = 3 -> drain . f . f . f 4 -> drain . f . f . f . f _ -> undefined -#endif {-# INLINE mapN #-} mapN :: @@ -469,13 +427,11 @@ mapM :: -> m () mapM n = composeN n $ Stream.mapM return -#ifndef USE_PRELUDE foldl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> m b foldl' f z = Stream.fold (Fold.foldl' f z) scanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b scanl' f z = Stream.scanl (Scanl.mkScanl f z) -#endif {-# INLINE transformMapM #-} transformMapM :: @@ -483,13 +439,8 @@ transformMapM :: => Int -> Stream m Int -> m () -#ifndef USE_PRELUDE transformMapM n = composeN n $ Stream.pipe (Pipe.mapM return) -#else -transformMapM n = composeN n $ Stream.transform (Pipe.mapM return) -#endif -#ifndef USE_PRELUDE {-# INLINE scanMapM #-} scanMapM :: (Monad m) @@ -497,7 +448,6 @@ scanMapM :: -> Stream m Int -> m () scanMapM n = composeN n $ Stream.scanr (Scanr.functionM return) -#endif {-# INLINE transformComposeMapM #-} transformComposeMapM :: @@ -507,15 +457,10 @@ transformComposeMapM :: -> m () transformComposeMapM n = composeN n $ -#ifndef USE_PRELUDE Stream.pipe -#else - Stream.transform -#endif (Pipe.mapM (\x -> return (x + 1)) `Pipe.compose` Pipe.mapM (\x -> return (x + 2))) -#ifndef USE_PRELUDE {-# INLINE scanComposeMapM #-} scanComposeMapM :: (Monad m) @@ -527,7 +472,6 @@ scanComposeMapM n = Stream.scanr (Scanr.functionM (\x -> return (x + 1)) `Scanr.compose` Scanr.functionM (\x -> return (x + 2))) -#endif {-# INLINE transformTeeMapM #-} transformTeeMapM :: @@ -537,15 +481,10 @@ transformTeeMapM :: -> m () transformTeeMapM n = composeN n $ -#ifndef USE_PRELUDE Stream.pipe -#else - Stream.transform -#endif (Pipe.mapM (\x -> return (x + 1)) `Pipe.teeMerge` Pipe.mapM (\x -> return (x + 2))) -#ifndef USE_PRELUDE {-# INLINE scanTeeMapM #-} scanTeeMapM :: (Monad m) @@ -557,7 +496,6 @@ scanTeeMapM n = Stream.scanr (Scanr.teeWith (+) (Scanr.functionM (\x -> return (x + 1))) (Scanr.functionM (\x -> return (x + 2)))) -#endif {- {-# INLINE transformZipMapM #-} diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs b/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs index 4006de45db..6f1e659116 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs @@ -11,8 +11,6 @@ {-# LANGUAGE RankNTypes #-} {-# OPTIONS_GHC -Wno-orphans #-} -#ifdef USE_PRELUDE -#endif #ifdef __HADDOCK_VERSION__ #undef INSPECTION @@ -40,15 +38,9 @@ import Test.Inspection import qualified Streamly.Internal.Data.Stream as D #endif -#ifdef USE_PRELUDE -import Streamly.Prelude (fromSerial) -import Streamly.Benchmark.Prelude -import qualified Streamly.Internal.Data.Stream.IsStream as S -#else import Stream.Common import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as S -#endif import Test.Tasty.Bench import Streamly.Benchmark.Common @@ -56,15 +48,6 @@ import Prelude hiding (length, sum, or, and, any, all, notElem, elem, (!!), lookup, repeat, minimum, maximum, product, last, mapM_, init) import qualified Prelude -#ifdef USE_PRELUDE -type Stream = S.SerialT -fromStream = id - -{-# INLINE repeat #-} -repeat :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -repeat count = S.take count . S.repeat -#endif - ------------------------------------------------------------------------------- -- Elimination ------------------------------------------------------------------------------- @@ -239,11 +222,9 @@ o_1_space_elimination_foldable value = -- Stream folds ------------------------------------------------------------------------------- -#ifndef USE_PRELUDE instance NFData a => NFData (Stream Identity a) where {-# INLINE rnf #-} rnf xs = runIdentity $ S.fold (Fold.foldl' (\_ x -> rnf x) ()) xs -#endif {-# INLINE benchPureSink #-} benchPureSink :: NFData b @@ -277,17 +258,12 @@ uncons s = do Nothing -> return () Just (_, t) -> uncons t -#ifndef USE_PRELUDE {-# INLINE toNull #-} toNull :: Monad m => Stream m Int -> m () toNull = S.drain -#endif - -#ifdef USE_PRELUDE {-# INLINE init #-} init :: Monad m => Stream m a -> m () init s = S.init s >>= Prelude.mapM_ S.drain -#endif {-# INLINE mapM_ #-} mapM_ :: Monad m => Stream m Int -> m () @@ -325,10 +301,9 @@ foldl'Reduce = S.foldl' (+) 0 last :: Monad m => Stream m Int -> m (Maybe Int) last = S.last -#ifdef USE_PRELUDE {-# INLINE foldl1'Reduce #-} foldl1'Reduce :: Monad m => Stream m Int -> m (Maybe Int) -foldl1'Reduce = S.foldl1' (+) +foldl1'Reduce = S.fold (Fold.foldl1' (+)) {-# INLINE foldlM'Reduce #-} foldlM'Reduce :: Monad m => Stream m Int -> m Int @@ -348,7 +323,7 @@ notElem value = S.notElem (value + 1) {-# INLINE length #-} length :: Monad m => Stream m Int -> m Int -length = S.length +length = S.fold Fold.length {-# INLINE all #-} all :: Monad m => Int -> Stream m Int -> m Bool @@ -360,11 +335,11 @@ any value = S.any (> (value + 1)) {-# INLINE and #-} and :: Monad m => Int -> Stream m Int -> m Bool -and value = S.and . S.map (<= (value + 1)) +and value = S.fold Fold.and . S.map (<= (value + 1)) {-# INLINE or #-} or :: Monad m => Int -> Stream m Int -> m Bool -or value = S.or . S.map (> (value + 1)) +or value = S.fold Fold.or . S.map (> (value + 1)) {-# INLINE find #-} find :: Monad m => Int -> Stream m Int -> m (Maybe Int) @@ -376,11 +351,11 @@ findM value = S.findM (\z -> return $ z == (value + 1)) {-# INLINE findIndex #-} findIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int) -findIndex value = S.findIndex (== (value + 1)) +findIndex value = S.head . S.findIndices (== (value + 1)) {-# INLINE elemIndex #-} elemIndex :: Monad m => Int -> Stream m Int -> m (Maybe Int) -elemIndex value = S.elemIndex (value + 1) +elemIndex value = S.head . S.elemIndices (value + 1) {-# INLINE maximum #-} maximum :: Monad m => Stream m Int -> m (Maybe Int) @@ -392,11 +367,11 @@ minimum = S.minimum {-# INLINE sum #-} sum :: Monad m => Stream m Int -> m Int -sum = S.sum +sum = S.fold Fold.sum {-# INLINE product #-} product :: Monad m => Stream m Int -> m Int -product = S.product +product = S.fold Fold.product {-# INLINE minimumBy #-} minimumBy :: Monad m => Stream m Int -> m (Maybe Int) @@ -412,11 +387,7 @@ the = S.the {-# INLINE drainN #-} drainN :: Monad m => Int -> Stream m Int -> m () -drainN = S.drainN - -{-# INLINE drainWhile #-} -drainWhile :: Monad m => Stream m Int -> m () -drainWhile = S.drainWhile (const True) +drainN n = S.fold (Fold.drainN n) {-# INLINE (!!) #-} (!!) :: Monad m => Int -> Stream m Int -> m (Maybe Int) @@ -425,14 +396,11 @@ drainWhile = S.drainWhile (const True) {-# INLINE lookup #-} lookup :: Monad m => Int -> Stream m Int -> m (Maybe Int) lookup val = S.lookup val . S.map (\x -> (x, x)) -#endif - o_1_space_elimination_folds :: Int -> [Benchmark] o_1_space_elimination_folds value = [ bgroup "elimination" -- Basic folds [ -#ifdef USE_PRELUDE bgroup "reduce" [ bgroup "IO" @@ -448,7 +416,6 @@ o_1_space_elimination_folds value = , benchIdentitySink value "foldlM'" foldlM'Reduce ] ] , -#endif bgroup "build" [ bgroup "IO" [ benchIOSink value "foldrMElem" (foldrMElem value) @@ -472,20 +439,14 @@ o_1_space_elimination_folds value = , benchIOSink value "uncons" uncons , benchIOSink value "mapM_" mapM_ , benchIOSink value "last" last -#ifndef USE_PRELUDE , benchHoistSink value "length . generalizeInner" (S.fold Fold.length . S.generalizeInner) , benchIOSink value "toNull" toNull , benchIOSink value "foldBreak" foldBreak - , benchIOSink value "foldl" foldl'Reduce -#endif -#ifdef USE_PRELUDE , benchIOSink value "init" init -- draining - , benchIOSink value "drain" $ toNull fromSerial , benchIOSink value "drainN" $ drainN value - , benchIOSink value "drainWhile" drainWhile , benchPureSink value "drain (pure)" id -- this is too fast, causes all benchmarks reported in ns @@ -514,7 +475,6 @@ o_1_space_elimination_folds value = , benchIOSink value "any" (any value) , benchIOSink value "and" (and value) , benchIOSink value "or" (or value) -#endif -- length is used to check for foldr/build fusion , benchPureSink value "length . IsList.toList" (Prelude.length . GHC.toList) @@ -525,7 +485,6 @@ o_1_space_elimination_folds value = -- Buffered Transformations by fold ------------------------------------------------------------------------------- -#ifdef USE_PRELUDE {-# INLINE foldl'Build #-} foldl'Build :: Monad m => Stream m Int -> m [Int] foldl'Build = S.foldl' (flip (:)) [] @@ -545,8 +504,6 @@ o_n_heap_elimination_foldl value = , benchIdentitySink value "foldlM'/build/Identity" foldlM'Build ] ] -#endif - -- For comparisons {-# INLINE showInstanceList #-} showInstanceList :: [Int] -> String @@ -585,14 +542,13 @@ o_n_space_elimination_foldr value = ] ] -#ifdef USE_PRELUDE o_n_heap_elimination_toList :: Int -> [Benchmark] o_n_heap_elimination_toList value = [ bgroup "toList" -- Converting the stream to a list or pure stream in a strict monad [ benchIOSink value "toListRev" S.toListRev , benchIOSink value "toStreamRev" - (S.toStreamRev :: (Stream IO Int -> IO (Stream Identity Int))) + (S.fold Fold.toStreamRev :: (Stream IO Int -> IO (Stream Identity Int))) ] ] @@ -601,14 +557,10 @@ o_n_space_elimination_toList value = [ bgroup "toList" -- Converting the stream to a list or pure stream in a strict monad [ benchIOSink value "toList" S.toList -#ifndef USE_PRELUDE , benchIOSink value "toStream" - (S.toStream :: (Stream IO Int -> IO (Stream Identity Int))) -#endif + (S.fold Fold.toStream :: (Stream IO Int -> IO (Stream Identity Int))) ] ] -#endif - ------------------------------------------------------------------------------- -- Multi-stream folds ------------------------------------------------------------------------------- @@ -731,11 +683,9 @@ benchmarks moduleName size = , bgroup (o_n_heap_prefix moduleName) $ o_n_heap_elimination_buffered size -#ifdef USE_PRELUDE ++ o_n_heap_elimination_foldl size ++ o_n_heap_elimination_toList size ++ o_n_space_elimination_toList size -#endif , bgroup (o_n_space_prefix moduleName) $ o_n_space_elimination_foldr size ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs b/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs index 861064f9f4..173c980dee 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs @@ -10,9 +10,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} -#ifdef USE_PRELUDE -#endif - #ifdef __HADDOCK_VERSION__ #undef INSPECTION #endif @@ -37,12 +34,8 @@ import qualified Streamly.Internal.FileSystem.Handle as IFH import qualified Streamly.Internal.Data.Unfold as IUF import qualified Streamly.Internal.Data.Unfold.Prelude as IUF -#ifdef USE_PRELUDE -import qualified Streamly.Internal.Data.Stream.IsStream as Stream -#else import qualified Streamly.Internal.Data.Stream as Stream import qualified Streamly.Internal.Data.Stream.Prelude as Stream -#endif import Test.Tasty.Bench hiding (env) import Prelude hiding (last, length) @@ -56,30 +49,18 @@ import Test.Inspection import qualified Streamly.Internal.Data.Stream as D #endif -#ifdef USE_PRELUDE -type Stream = Stream.SerialT -toStreamD = Stream.toStream -fromStreamD = Stream.fromStream -#else type Stream = Stream.Stream toStreamD :: a -> a toStreamD = id fromStreamD :: a -> a fromStreamD = id -#endif afterUnsafe :: IO b -> Stream IO a -> Stream IO a finallyUnsafe :: IO b -> Stream IO a -> Stream IO a bracketUnsafe :: IO b -> (b -> IO c) -> (b -> Stream IO a) -> Stream IO a -#ifdef USE_PRELUDE -afterUnsafe = Stream.after_ -finallyUnsafe = Stream.finally_ -bracketUnsafe = Stream.bracket_ -#else afterUnsafe = Stream.afterUnsafe finallyUnsafe = Stream.finallyUnsafe bracketUnsafe = Stream.bracketUnsafe -#endif ------------------------------------------------------------------------------- -- stream exceptions @@ -178,11 +159,7 @@ inspect $ hasNoTypeClasses 'readWriteOnExceptionStream readWriteHandleExceptionStream :: Handle -> Handle -> IO () readWriteHandleExceptionStream inh devNull = let handler (_e :: SomeException) = -#ifndef USE_PRELUDE return $ Stream.fromEffect (hClose inh >> return 10) -#else - Stream.fromEffect (hClose inh >> return 10) -#endif readEx = Stream.handle handler (Stream.unfold FH.reader inh) in Stream.fold (FH.write devNull) readEx diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index e8e57cdfc1..ca79466758 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -9,9 +9,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RankNTypes #-} -#ifdef USE_PRELUDE -#endif - #ifdef __HADDOCK_VERSION__ #undef INSPECTION #endif @@ -33,12 +30,6 @@ import qualified Streamly.Internal.Data.Stream as D import qualified Stream.Common as Common import qualified Streamly.Internal.Data.Unfold as UF -#ifdef USE_PRELUDE -import qualified Streamly.Internal.Data.Stream.IsStream as S -import Streamly.Benchmark.Prelude - ( sourceFoldMapM, sourceFoldMapWith, sourceFoldMapWithM - , sourceFoldMapWithStream, concatFoldableWith, concatForFoldableWith) -#else import Streamly.Data.Stream (Stream) import Streamly.Data.Unfold (Unfold) import qualified Streamly.Internal.Data.Stream as S @@ -46,8 +37,6 @@ import qualified Streamly.Internal.Data.Unfold as Unfold import qualified Streamly.Internal.Data.Fold as Fold import qualified Streamly.Internal.Data.Stream as Stream import qualified Streamly.Internal.Data.StreamK as StreamK -#endif - import Test.Tasty.Bench import Stream.Common import Streamly.Benchmark.Common @@ -89,29 +78,6 @@ o_1_space_joining value = ] ] -------------------------------------------------------------------------------- --- Concat Foldable containers -------------------------------------------------------------------------------- - -#ifdef USE_PRELUDE -o_1_space_concatFoldable :: Int -> [Benchmark] -o_1_space_concatFoldable value = - [ bgroup "concat-foldable" - [ benchIOSrc "foldMapWith (<>) (List)" - (sourceFoldMapWith value) - , benchIOSrc "foldMapWith (<>) (Stream)" - (sourceFoldMapWithStream value) - , benchIOSrc "foldMapWithM (<>) (List)" - (sourceFoldMapWithM value) - , benchIOSrc "S.concatFoldableWith (<>) (List)" - (concatFoldableWith value) - , benchIOSrc "S.concatForFoldableWith (<>) (List)" - (concatForFoldableWith value) - , benchIOSrc "foldMapM (List)" (sourceFoldMapM value) - ] - ] -#endif - ------------------------------------------------------------------------------- -- Concat ------------------------------------------------------------------------------- @@ -712,9 +678,6 @@ benchmarks moduleName size = [ -- multi-stream o_1_space_joining size -#ifdef USE_PRELUDE - , o_1_space_concatFoldable size -#endif , o_1_space_concat size , o_1_space_applicative size , o_1_space_monad size diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs b/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs index 83dc14cd27..0f2779d555 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs @@ -11,28 +11,20 @@ {-# LANGUAGE RankNTypes #-} {-# OPTIONS_GHC -Wno-orphans #-} -#ifdef USE_PRELUDE -#endif module Stream.Generate (benchmarks) where import Control.DeepSeq (NFData(..)) +import Control.Monad.IO.Class (MonadIO) import Data.Functor.Identity (Identity(..)) +import Streamly.Internal.Data.Time.Units (AbsTime) import qualified GHC.Exts as GHC import qualified Streamly.Internal.Data.Fold as Fold -#ifdef USE_PRELUDE -import Streamly.Prelude (MonadAsync) -import Stream.Common hiding (MonadAsync) -import Streamly.Benchmark.Prelude (sourceFromFoldableM, absTimes) -import qualified Streamly.Prelude as S -import qualified Streamly.Internal.Data.Stream.IsStream as Stream -#else import Stream.Common import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as Stream -#endif import Test.Tasty.Bench import Streamly.Benchmark.Common @@ -44,13 +36,8 @@ import Prelude hiding (repeat, replicate, iterate) -- Generation ------------------------------------------------------------------------------- -#ifdef USE_PRELUDE -type Stream = Stream.SerialT -toStreamD = Stream.toStream -#else toStreamD :: a -> a toStreamD = id -#endif ------------------------------------------------------------------------------- -- fromList @@ -89,10 +76,6 @@ readInstanceList str = [(x,"")] -> x _ -> error "readInstance: no parse" -{-# INLINE repeat #-} -repeat :: Monad m => Int -> Int -> Stream m Int -repeat count = Stream.take count . Stream.repeat - {-# INLINE replicate #-} replicate :: Monad m => Int -> Int -> Stream m Int replicate = Stream.replicate @@ -166,15 +149,21 @@ repeatM count = Stream.take count . Stream.repeatM . return replicateM :: MonadAsync m => Int -> Int -> Stream m Int replicateM count = Stream.replicateM count . return -#ifdef USE_PRELUDE {-# INLINE fromIndices #-} -fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -fromIndices value n = S.take value $ S.fromIndices (+ n) +fromIndices :: Monad m => Int -> Int -> Stream m Int +fromIndices value n = Stream.take value $ Stream.fromIndices (+ n) {-# INLINE fromIndicesM #-} -fromIndicesM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int -fromIndicesM value n = S.take value $ S.fromIndicesM (return <$> (+ n)) -#endif +fromIndicesM :: Monad m => Int -> Int -> Stream m Int +fromIndicesM value n = Stream.take value $ Stream.fromIndicesM (return <$> (+ n)) + +{-# INLINE absTimes #-} +absTimes :: MonadIO m => Int -> Int -> Stream m AbsTime +absTimes value _ = Stream.take value Stream.absTimes + +{-# INLINE sourceFromFoldableM #-} +sourceFromFoldableM :: Monad m => Int -> Int -> Stream m Int +sourceFromFoldableM value n = Stream.fromFoldableM (fmap return [n..n+value]) o_1_space_generation :: Int -> [Benchmark] o_1_space_generation value = @@ -202,26 +191,19 @@ o_1_space_generation value = , benchIOSrc "enumerateTo" (enumerateTo value) , benchIOSrc "repeatM" (repeatM value) , benchIOSrc "replicateM" (replicateM value) -#ifdef USE_PRELUDE , benchIOSrc "fromIndices" (fromIndices value) , benchIOSrc "fromIndicesM" (fromIndicesM value) -#endif -- These essentially test cons and consM -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16) - -#ifdef USE_PRELUDE , benchIOSrc "fromFoldableM" (sourceFromFoldableM value) , benchIOSrc "absTimes" $ absTimes value -#endif ] ] -#ifndef USE_PRELUDE instance NFData a => NFData (Stream Identity a) where {-# INLINE rnf #-} rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs -#endif o_n_heap_generation :: Int -> [Benchmark] o_n_heap_generation value = diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Lift.hs b/benchmark/Streamly/Benchmark/Data/Stream/Lift.hs index 92c030a8bd..059e79d762 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Lift.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Lift.hs @@ -9,9 +9,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RankNTypes #-} -#ifdef USE_PRELUDE -#endif - module Stream.Lift (benchmarks) where import Control.DeepSeq (NFData(..)) @@ -23,21 +20,13 @@ import System.Random (randomRIO) import qualified Stream.Common as Common import qualified Streamly.Internal.Data.Fold as Fold -#ifdef USE_PRELUDE -import qualified Streamly.Internal.Data.Stream.IsStream as Stream -#else import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as Stream -#endif import Test.Tasty.Bench import Streamly.Benchmark.Common import Prelude hiding (reverse, tail) -#ifdef USE_PRELUDE -type Stream = Stream.SerialT -#endif - ------------------------------------------------------------------------------- -- Monad transformation (hoisting etc.) ------------------------------------------------------------------------------- @@ -78,11 +67,9 @@ o_1_space_hoisting value = [ bgroup "hoisting" [ benchIOSrc "evalState" (evalStateT value) , benchIOSrc "withState" (withState value) -#ifndef USE_PRELUDE , benchHoistSink value "generalizeInner" ((\xs -> Stream.fold Fold.length xs :: IO Int) . Stream.generalizeInner) -#endif ] ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs b/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs index e547c74b7d..d4d9534e9f 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs @@ -11,9 +11,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE RankNTypes #-} -#ifdef USE_PRELUDE -#endif - module Stream.Reduce (benchmarks) where import Control.DeepSeq (NFData(..)) @@ -33,33 +30,19 @@ import Data.Proxy (Proxy(..)) import Streamly.Internal.Data.IsMap.HashMap () #endif -#ifdef USE_PRELUDE -import qualified Streamly.Internal.Data.Stream.IsStream as S -import qualified Streamly.Prelude as S -import Streamly.Prelude (fromSerial) -import Streamly.Benchmark.Prelude hiding - ( benchIO, benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2 - , toNullAp, monadThen, toNullM, toNullM3, filterAllInM, filterAllOutM - , filterSome, breakAfterSome, toListM, toListSome, transformMapM - , transformComposeMapM, transformTeeMapM, transformZipMapM) -#else - import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as S #ifndef USE_STREAMLY_CORE import qualified Streamly.Data.Stream.Prelude as S import qualified Streamly.Internal.Data.Stream.Prelude as S #endif -#endif import Test.Tasty.Bench import Streamly.Benchmark.Common import Stream.Common import Prelude hiding (reverse, tail) -#ifdef USE_PRELUDE -type Stream = S.SerialT -#endif + -- Apply transformation g count times on a stream of length len {-# INLINE iterateSource #-} @@ -83,49 +66,23 @@ iterateSource g count len n = f count (sourceUnfoldrM len n) {-# INLINE groups #-} groups :: MonadIO m => Stream m Int -> m () -groups = -#ifdef USE_PRELUDE - Common.drain . S.groups FL.drain -#else - Common.drain . S.groupsWhile (==) FL.drain -#endif +groups = Common.drain . S.groupsWhile (==) FL.drain {-# INLINE groupsWhileLT #-} groupsWhileLT :: MonadIO m => Stream m Int -> m () -groupsWhileLT = -#ifdef USE_PRELUDE - Common.drain . S.groupsBy (>) FL.drain -#else - Common.drain . S.groupsWhile (<) FL.drain -#endif +groupsWhileLT = Common.drain . S.groupsWhile (<) FL.drain {-# INLINE groupsWhileEq #-} groupsWhileEq :: MonadIO m => Stream m Int -> m () -groupsWhileEq = -#ifdef USE_PRELUDE - Common.drain . S.groupsBy (==) FL.drain -#else - Common.drain . S.groupsWhile (==) FL.drain -#endif - +groupsWhileEq = Common.drain . S.groupsWhile (==) FL.drain {-# INLINE groupsByRollingLT #-} groupsByRollingLT :: MonadIO m => Stream m Int -> m () -groupsByRollingLT = -#ifdef USE_PRELUDE - Common.drain . S.groupsByRolling (<) FL.drain -#else - Common.drain . S.groupsRollingBy (<) FL.drain -#endif +groupsByRollingLT = Common.drain . S.groupsRollingBy (<) FL.drain {-# INLINE groupsByRollingEq #-} groupsByRollingEq :: MonadIO m => Stream m Int -> m () -groupsByRollingEq = -#ifdef USE_PRELUDE - Common.drain . S.groupsByRolling (==) FL.drain -#else - Common.drain . S.groupsRollingBy (==) FL.drain -#endif +groupsByRollingEq = Common.drain . S.groupsRollingBy (==) FL.drain {-# INLINE foldMany #-} foldMany :: Monad m => Stream m Int -> m () @@ -135,7 +92,6 @@ foldMany = . S.foldMany (FL.take 2 FL.mconcat) . fmap Sum -#ifndef USE_PRELUDE {-# INLINE foldMany1 #-} foldMany1 :: Monad m => Stream m Int -> m () foldMany1 = @@ -143,7 +99,6 @@ foldMany1 = . fmap getSum . S.foldManyPost (FL.take 2 FL.mconcat) . fmap Sum -#endif {-# INLINE refoldMany #-} refoldMany :: Monad m => Stream m Int -> m () @@ -187,9 +142,7 @@ o_1_space_grouping value = -- modules we can bring those here. chunksOf benchmarks are in -- Parser/ParserD/Array.Stream/FileSystem.Handle. benchIOSink value "foldMany" foldMany -#ifndef USE_PRELUDE , benchIOSink value "foldMany1" foldMany1 -#endif , benchIOSink value "refoldMany" refoldMany , benchIOSink value "foldIterateM" foldIterateM , benchIOSink value "refoldIterateM" refoldIterateM @@ -218,7 +171,6 @@ o_1_space_grouping value = -- Size conserving transformations (reordering, buffering, etc.) ------------------------------------------------------------------------------- -#ifndef USE_PRELUDE {-# INLINE reverse #-} reverse :: MonadIO m => Int -> Stream m Int -> m () reverse n = composeN n S.reverse @@ -226,19 +178,14 @@ reverse n = composeN n S.reverse {-# INLINE reverse' #-} reverse' :: MonadIO m => Int -> Stream m Int -> m () reverse' n = composeN n S.reverseUnbox -#endif o_n_heap_buffering :: Int -> [Benchmark] o_n_heap_buffering value = [ bgroup "buffered" [ -#ifndef USE_PRELUDE -- Reversing a stream benchIOSink value "reverse" (reverse 1) , benchIOSink value "reverse'" (reverse' 1) -#else - benchIOSink value "mkAsync" (mkAsync fromSerial) -#endif ] ] @@ -308,11 +255,9 @@ filterTake value n = composeN n $ S.take (value + 1) . S.filter (<= (value + 1)) filterScan :: MonadIO m => Int -> Stream m Int -> m () filterScan n = composeN n $ Common.scanl' (+) 0 . S.filter (<= maxBound) -#ifdef USE_PRELUDE {-# INLINE filterScanl1 #-} filterScanl1 :: MonadIO m => Int -> Stream m Int -> m () filterScanl1 n = composeN n $ S.scanl1' (+) . S.filter (<= maxBound) -#endif {-# INLINE filterMap #-} filterMap :: MonadIO m => Int -> Int -> Stream m Int -> m () @@ -375,9 +320,7 @@ o_1_space_transformations_mixedX2 value = , benchIOSink value "filter-drop" (filterDrop value 2) , benchIOSink value "filter-take" (filterTake value 2) , benchIOSink value "filter-scan" (filterScan 2) -#ifdef USE_PRELUDE , benchIOSink value "filter-scanl1" (filterScanl1 2) -#endif , benchIOSink value "filter-map" (filterMap value 2) ] ] @@ -394,9 +337,7 @@ o_1_space_transformations_mixedX4 value = , benchIOSink value "filter-drop" (filterDrop value 4) , benchIOSink value "filter-take" (filterTake value 4) , benchIOSink value "filter-scan" (filterScan 4) -#ifdef USE_PRELUDE , benchIOSink value "filter-scanl1" (filterScanl1 4) -#endif , benchIOSink value "filter-map" (filterMap value 4) ] ] @@ -410,13 +351,10 @@ o_1_space_transformations_mixedX4 value = iterateScan :: MonadAsync m => Int -> Int -> Int -> Stream m Int iterateScan = iterateSource (Common.scanl' (+) 0) -#ifdef USE_PRELUDE -- this is quadratic {-# INLINE iterateScanl1 #-} iterateScanl1 :: MonadAsync m => Int -> Int -> Int -> Stream m Int iterateScanl1 = iterateSource (S.scanl1' (+)) -#endif - {-# INLINE iterateMapM #-} iterateMapM :: MonadAsync m => Int -> Int -> Int -> Stream m Int iterateMapM = iterateSource (S.mapM return) @@ -472,9 +410,7 @@ o_n_stack_iterated value = by10 `seq` by100 `seq` [ benchIOSrc "mapM (n/10 x 10)" $ iterateMapM by10 10 , benchIOSrc "scanl' (quadratic) (n/100 x 100)" $ iterateScan by100 100 -#ifdef USE_PRELUDE , benchIOSrc "scanl1' (n/10 x 10)" $ iterateScanl1 by10 10 -#endif , benchIOSrc "filterEven (n/10 x 10)" $ iterateFilterEven by10 10 , benchIOSrc "takeAll (n/10 x 10)" $ @@ -530,7 +466,6 @@ o_1_space_pipesX4 value = -- Scans ------------------------------------------------------------------------------- -#ifndef USE_PRELUDE o_1_space_scans :: Int -> [Benchmark] o_1_space_scans value = [ bgroup "scans" @@ -549,7 +484,6 @@ o_1_space_scansX4 value = , benchIOSink value "tee" (scanTeeMapM 4) ] ] -#endif ------------------------------------------------------------------------------- -- Main @@ -570,11 +504,9 @@ benchmarks moduleName size = , o_1_space_pipes size , o_1_space_pipesX4 size -#ifndef USE_PRELUDE -- scans , o_1_space_scans size , o_1_space_scansX4 size -#endif ] , bgroup (o_n_stack_prefix moduleName) (o_n_stack_iterated size) , bgroup (o_n_heap_prefix moduleName) (o_n_heap_buffering size) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs index a9ad82d465..19e0e3590a 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs @@ -11,8 +11,6 @@ {-# LANGUAGE RankNTypes #-} {-# OPTIONS_GHC -Wno-orphans #-} -#ifdef USE_PRELUDE -#endif #ifdef __HADDOCK_VERSION__ #undef INSPECTION @@ -35,30 +33,18 @@ import qualified Streamly.Internal.Data.Scanl as Scanl import qualified Stream.Common as Common import qualified Streamly.Internal.Data.Unfold as Unfold -#ifdef USE_PRELUDE -import Control.DeepSeq (NFData(..)) -import Data.Functor.Identity (Identity(..)) -import qualified Prelude -import qualified Streamly.Internal.Data.Fold as Fold -import qualified Streamly.Internal.Data.Scanl as Scanl -import qualified Streamly.Internal.Data.Stream.IsStream as Stream -import Streamly.Internal.Data.Time.Units -#else import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as Stream #ifndef USE_STREAMLY_CORE import qualified Streamly.Internal.Data.Stream.Prelude as Stream #endif -#endif import Test.Tasty.Bench import Stream.Common hiding (scanl') import Streamly.Benchmark.Common import Prelude hiding (sequence, mapM) -#ifdef USE_PRELUDE -type Stream = Stream.SerialT -#endif + ------------------------------------------------------------------------------- -- Pipelines (stream-to-stream transformations) @@ -72,7 +58,6 @@ type Stream = Stream.SerialT -- maps and scans ------------------------------------------------------------------------------- -#ifdef USE_PRELUDE {-# INLINE scanl' #-} scanl' :: MonadIO m => Int -> Stream m Int -> m () scanl' n = composeN n $ Stream.scanl' (+) 0 @@ -88,9 +73,7 @@ scanl1' n = composeN n $ Stream.scanl1' (+) {-# INLINE scanl1M' #-} scanl1M' :: MonadIO m => Int -> Stream m Int -> m () scanl1M' n = composeN n $ Stream.scanl1M' (\b a -> return $ b + a) -#endif -#ifndef USE_PRELUDE {-# INLINE scan #-} scan :: MonadIO m => Int -> Stream m Int -> m () scan n = composeN n $ Stream.scanl Scanl.sum @@ -98,9 +81,7 @@ scan n = composeN n $ Stream.scanl Scanl.sum {-# INLINE postscan #-} postscan :: MonadIO m => Int -> Stream m Int -> m () postscan n = composeN n $ Stream.postscanl Scanl.sum -#endif -#ifdef USE_PRELUDE {-# INLINE postscanl' #-} postscanl' :: MonadIO m => Int -> Stream m Int -> m () postscanl' n = composeN n $ Stream.postscanl' (+) 0 @@ -108,7 +89,6 @@ postscanl' n = composeN n $ Stream.postscanl' (+) 0 {-# INLINE postscanlM' #-} postscanlM' :: MonadIO m => Int -> Stream m Int -> m () postscanlM' n = composeN n $ Stream.postscanlM' (\b a -> return $ b + a) (return 0) -#endif {-# INLINE sequence #-} sequence :: MonadAsync m => Stream m (m Int) -> m () @@ -118,21 +98,18 @@ sequence = Common.drain . Stream.sequence tap :: MonadIO m => Int -> Stream m Int -> m () tap n = composeN n $ Stream.tap FL.sum -#ifdef USE_PRELUDE {-# INLINE pollCounts #-} pollCounts :: Int -> Stream IO Int -> IO () pollCounts n = - composeN n (Stream.pollCounts (const True) f) + composeN n (Stream.parTapCount (const True) f) where f = Stream.drain . Stream.rollingMap2 (-) . Stream.delayPost 1 {-# INLINE timestamped #-} -timestamped :: (MonadAsync m) => Stream m Int -> m () +timestamped :: MonadIO m => Stream m Int -> m () timestamped = Stream.drain . Stream.timestamped -#endif - {- {-# INLINE foldrT #-} foldrT :: MonadIO m => Int -> Stream m Int -> m () @@ -163,10 +140,8 @@ o_1_space_mapping value = sequence (sourceUnfoldrAction value n) , benchIOSink value "mapM" (mapM 1) , benchIOSink value "tap" (tap 1) -#ifdef USE_PRELUDE - , benchIOSink value "pollCounts 1 second" (pollCounts 1) + , benchIOSink value "parTapCount 1 second" (pollCounts 1) , benchIOSink value "timestamped" timestamped - -- Scanning , benchIOSink value "scanl'" (scanl' 1) , benchIOSink value "scanl1'" (scanl1' 1) @@ -174,11 +149,8 @@ o_1_space_mapping value = , benchIOSink value "scanl1M'" (scanl1M' 1) , benchIOSink value "postscanl'" (postscanl' 1) , benchIOSink value "postscanlM'" (postscanlM' 1) -#endif -#ifndef USE_PRELUDE , benchIOSink value "scan" (scan 1) , benchIOSink value "postscan" (postscan 1) -#endif ] ] @@ -189,15 +161,12 @@ o_1_space_mappingX4 value = , benchIOSink value "mapM" (mapM 4) , benchIOSink value "trace" (trace 4) -#ifdef USE_PRELUDE , benchIOSink value "scanl'" (scanl' 4) , benchIOSink value "scanl1'" (scanl1' 4) , benchIOSink value "scanlM'" (scanlM' 4) , benchIOSink value "scanl1M'" (scanl1M' 4) , benchIOSink value "postscanl'" (postscanl' 4) , benchIOSink value "postscanlM'" (postscanlM' 4) -#endif -#ifndef USE_PRELUDE , benchIOSink value "scan" (scan 4) , benchIOSink value "postscan" (postscan 4) {- @@ -205,11 +174,9 @@ o_1_space_mappingX4 value = , let value16 = round (fromIntegral value**(1/16::Double)) benchFold "concatMap" (concatMap 4) (sourceUnfoldrMN value16) -} -#endif ] ] -#ifndef USE_PRELUDE {-# INLINE sieveScan #-} sieveScan :: Monad m => Stream m Int -> Stream m Int sieveScan = @@ -220,16 +187,13 @@ sieveScan = in if all (\p -> n `mod` p /= 0) ps then (primes ++ [n], Just n) else (primes, Nothing)) (return ([2], Just 2))) -#endif o_n_space_mapping :: Int -> [Benchmark] o_n_space_mapping value = [ bgroup "mapping" [ -#ifndef USE_PRELUDE benchIO "naive prime sieve" (\n -> Stream.fold FL.sum $ sieveScan $ Stream.enumerateFromTo 2 (value + n)) -#endif ] ] @@ -345,7 +309,7 @@ takeWhileTrue value n = composeN n $ Stream.takeWhile (<= (value + 1)) takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m () takeWhileMTrue value n = composeN n $ Stream.takeWhileM (return . (<= (value + 1))) -#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE) +#if !defined(USE_STREAMLY_CORE) {-# INLINE takeInterval #-} takeInterval :: Double -> Int -> Stream IO Int -> IO () takeInterval i n = composeN n (Stream.takeInterval i) @@ -390,13 +354,10 @@ dropWhileMTrue value n = composeN n $ Stream.dropWhileM (return . (<= (value + 1 dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m () dropWhileFalse value n = composeN n $ Stream.dropWhile (> (value + 1)) -#ifdef USE_PRELUDE -- XXX Decide on the time interval {-# INLINE _intervalsOfSum #-} -_intervalsOfSum :: MonadAsync m => Double -> Int -> Stream m Int -> m () +_intervalsOfSum :: Stream.MonadAsync m => Double -> Int -> Stream m Int -> m () _intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum) -#endif - {-# INLINE findIndices #-} findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m () findIndices value n = composeN n $ Stream.findIndices (== (value + 1)) @@ -451,7 +412,7 @@ o_1_space_filtering value = -- , benchIOSink value "takeWhileM-true" (_takeWhileMTrue value 1) , benchIOSink value "drop-one" (dropOne 1) , benchIOSink value "drop-all" (dropAll value 1) -#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE) +#if !defined(USE_STREAMLY_CORE) , benchIOSink value "takeInterval-all" (takeInterval 10000 1) , benchIOSink value "dropInterval-all" (dropInterval 10000 1) #endif diff --git a/benchmark/Streamly/Benchmark/Prelude/Adaptive.hs b/benchmark/Streamly/Benchmark/Prelude/Adaptive.hs deleted file mode 100644 index 29a8c7016f..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Adaptive.hs +++ /dev/null @@ -1,143 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Control.Concurrent (threadDelay) -import Control.Monad (when) -import Control.Monad.IO.Class (liftIO) -import Test.Tasty.Bench -import Streamly.Prelude as S -import System.Random (randomRIO) - --- Note that we should also compare the cpuTime especially when threaded --- runtime is used with this benchmark because thread scheduling is not --- predictable and can add non-deterministic delay to the total time measured. --- --- Also, the worker dispatch depends on the worker dispatch latency which is --- set to fixed 200 us. We need to keep that in mind when designing tests. - -moduleName :: String -moduleName = "Prelude.Adaptive" - -value :: Int -value = 1000 - -{-# INLINE source #-} -source :: IsStream t => (Int, Int) -> t IO Int -source range = S.replicateM value $ do - r <- randomRIO range - when (r /= 0) $ liftIO $ threadDelay r - return r - -{-# INLINE run #-} -run :: IsStream t => (Int, Int) -> (Int, Int) -> (t IO Int -> SerialT IO Int) -> IO () -run srange crange t = S.drain $ S.mapM action (t $ source srange) - - where - - action x = liftIO $ do - d <- randomRIO crange - when (d /= 0) $ threadDelay d - return x - -low, medium, high :: Int -low = 10 -medium = 20 -high = 30 - -{-# INLINE noDelay #-} -noDelay :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -noDelay = run (0,0) (0,0) - -{-# INLINE alwaysConstSlowSerial #-} -alwaysConstSlowSerial :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -alwaysConstSlowSerial = run (0,0) (medium,medium) - -{-# INLINE alwaysConstSlow #-} -alwaysConstSlow :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -alwaysConstSlow = run (low,low) (medium,medium) - -{-# INLINE alwaysConstFast #-} -alwaysConstFast :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -alwaysConstFast = run (high,high) (medium,medium) - -{-# INLINE alwaysVarSlow #-} -alwaysVarSlow :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -alwaysVarSlow = run (low,low) (low,high) - -{-# INLINE alwaysVarFast #-} -alwaysVarFast :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -alwaysVarFast = run (high,high) (low,high) - --- XXX add variable producer tests as well - -{-# INLINE runVarSometimesFast #-} -runVarSometimesFast :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -runVarSometimesFast = run (medium,medium) (low,high) - -{-# INLINE randomVar #-} -randomVar :: IsStream t => (t IO Int -> SerialT IO Int) -> IO () -randomVar = run (low,high) (low,high) - -main :: IO () -main = - defaultMain [bgroup moduleName allBenchmarks] - - where - - allBenchmarks = - [ - bgroup "serialConstantSlowConsumer" - [ bench "serially" $ nfIO $ alwaysConstSlowSerial fromSerial - , bench "wSerially" $ nfIO $ alwaysConstSlowSerial fromWSerial - ] - , bgroup "default" - [ bench "serially" $ nfIO $ noDelay fromSerial - , bench "wSerially" $ nfIO $ noDelay fromWSerial - , bench "aheadly" $ nfIO $ noDelay fromAhead - , bench "asyncly" $ nfIO $ noDelay fromAsync - , bench "wAsyncly" $ nfIO $ noDelay fromWAsync - , bench "parallely" $ nfIO $ noDelay fromParallel - ] - , bgroup "constantSlowConsumer" - [ bench "aheadly" $ nfIO $ alwaysConstSlow fromAhead - , bench "asyncly" $ nfIO $ alwaysConstSlow fromAsync - , bench "wAsyncly" $ nfIO $ alwaysConstSlow fromWAsync - , bench "parallely" $ nfIO $ alwaysConstSlow fromParallel - ] - , bgroup "constantFastConsumer" - [ bench "aheadly" $ nfIO $ alwaysConstFast fromAhead - , bench "asyncly" $ nfIO $ alwaysConstFast fromAsync - , bench "wAsyncly" $ nfIO $ alwaysConstFast fromWAsync - , bench "parallely" $ nfIO $ alwaysConstFast fromParallel - ] - , bgroup "variableSlowConsumer" - [ bench "aheadly" $ nfIO $ alwaysVarSlow fromAhead - , bench "asyncly" $ nfIO $ alwaysVarSlow fromAsync - , bench "wAsyncly" $ nfIO $ alwaysVarSlow fromWAsync - , bench "parallely" $ nfIO $ alwaysVarSlow fromParallel - ] - , bgroup "variableFastConsumer" - [ bench "aheadly" $ nfIO $ alwaysVarFast fromAhead - , bench "asyncly" $ nfIO $ alwaysVarFast fromAsync - , bench "wAsyncly" $ nfIO $ alwaysVarFast fromWAsync - , bench "parallely" $ nfIO $ alwaysVarFast fromParallel - ] - , bgroup "variableSometimesFastConsumer" - [ bench "aheadly" $ nfIO $ runVarSometimesFast fromAhead - , bench "asyncly" $ nfIO $ runVarSometimesFast fromAsync - , bench "wAsyncly" $ nfIO $ runVarSometimesFast fromWAsync - , bench "parallely" $ nfIO $ runVarSometimesFast fromParallel - ] - , bgroup "variableFullOverlap" - [ bench "aheadly" $ nfIO $ randomVar fromAhead - , bench "asyncly" $ nfIO $ randomVar fromAsync - , bench "wAsyncly" $ nfIO $ randomVar fromWAsync - , bench "parallely" $ nfIO $ randomVar fromParallel - ] - ] diff --git a/benchmark/Streamly/Benchmark/Prelude/Concurrent.hs b/benchmark/Streamly/Benchmark/Prelude/Concurrent.hs deleted file mode 100644 index 188343444c..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Concurrent.hs +++ /dev/null @@ -1,111 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE RankNTypes #-} --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Control.Concurrent -import Control.Monad (when, replicateM) -import Streamly.Prelude - ( IsStream, SerialT, serial, async, fromAsync, ahead, fromAhead, wAsync - , fromWAsync, parallel, fromParallel - ) - -import Test.Tasty.Bench -import qualified Streamly.Prelude as S - -------------------------------------------------------------------------------- --- Append -------------------------------------------------------------------------------- - --- | Run @tcount@ number of actions concurrently using the given concurrency --- style. Each thread produces a single output after a delay of @d@ --- microseconds. --- -{-# INLINE append #-} -append :: IsStream t - => Int -> Int -> Int -> (t IO Int -> SerialT IO Int) -> IO () -append buflen tcount d t = - let work = (\i -> when (d /= 0) (threadDelay d) >> return i) - in S.drain - $ t - $ S.maxBuffer buflen - $ S.maxThreads (-1) - $ S.fromFoldableM $ fmap work [1..tcount] - --- | Run @threads@ concurrently, each producing streams of @elems@ elements --- with a delay of @d@ microseconds between successive elements, and merge --- their outputs in a single output stream. The individual streams are produced --- serially but merged using the provided concurrency style. --- -{-# INLINE concated #-} -concated - :: Int - -> Int - -> Int - -> Int - -> (forall a. SerialT IO a -> SerialT IO a -> SerialT IO a) - -> IO () -concated buflen threads d elems t = - let work = \i -> S.replicateM i (when (d /= 0) (threadDelay d) >> return i) - in S.drain - $ S.adapt - $ S.maxThreads (-1) - $ S.maxBuffer buflen - $ S.concatMapWith t work - $ S.replicate threads elems - -appendGroup :: Int -> Int -> Int -> [Benchmark] -appendGroup buflen threads usec = - [ -- bench "serial" $ nfIO $ append buflen threads delay fromSerial - bench "ahead" $ nfIO $ append buflen threads usec fromAhead - , bench "async" $ nfIO $ append buflen threads usec fromAsync - , bench "wAsync" $ nfIO $ append buflen threads usec fromWAsync - , bench "parallel" $ nfIO $ append buflen threads usec fromParallel - ] - -concatGroup :: Int -> Int -> Int -> Int -> [Benchmark] -concatGroup buflen threads usec n = - [ bench "serial" $ nfIO $ concated buflen threads usec n serial - , bench "ahead" $ nfIO $ concated buflen threads usec n ahead - , bench "async" $ nfIO $ concated buflen threads usec n async - , bench "wAsync" $ nfIO $ concated buflen threads usec n wAsync - , bench "parallel" $ nfIO $ concated buflen threads usec n parallel - ] - -main :: IO () -main = -#ifdef MIN_VERSION_gauge - defaultMainWith (defaultConfig - { timeLimit = Just 0 - , minSamples = Just 1 - , minDuration = 0 - , includeFirstIter = True - , quickMode = True - }) -#else - defaultMain -#endif - - [ -- bgroup "append/buf-1-threads-10k-0sec" (appendGroup 1 10000 0) - -- , bgroup "append/buf-100-threads-100k-0sec" (appendGroup 100 100000 0) - bgroup "stream1x10k/buf10k-threads10k-5sec" (appendGroup 10000 10000 5000000) - -- bgroup "concat/buf-1-threads-100k-count-1" (concatGroup 1 100000 0 1) - -- bgroup "concat/buf-1-threads-1-count-10m" (concatGroup 1 1 0 10000000) - , bgroup "streams100x500k/buf100-threads100" (concatGroup 100 100 0 500000) - - , bench "forkIO/threads10k-5sec" $ - let delay = threadDelay 5000000 - count = 10000 :: Int - list = [1..count] - work i = delay >> return i - in nfIO $ do - ref <- newEmptyMVar - mapM_ (\i -> forkIO $ work i >>= - \j -> putMVar ref j) list - replicateM 10000 (takeMVar ref) - ] From eed0a91254dd9d4f4878bccb5b380013203f5f27 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Thu, 27 Nov 2025 21:33:39 +0530 Subject: [PATCH 02/24] Remove Prelude.Ahead benchmark --- .../Benchmark/Data/Stream/ConcurrentCommon.hs | 1 + benchmark/Streamly/Benchmark/Prelude/Ahead.hs | 135 ------------------ 2 files changed, 1 insertion(+), 135 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Ahead.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs index f48c2f2e2d..a3604bb907 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs @@ -200,6 +200,7 @@ allBenchmarks moduleName wide modifier value = , o_1_space_concatFoldable value modifier , o_1_space_concatMap "" value modifier , o_1_space_concatMap "-maxThreads-1" value (modifier . Async.maxThreads 1) + , o_1_space_concatMap "-maxBuffer-1 1/10" (value `div` 10) (modifier . Async.maxBuffer 1) , o_1_space_concatMap "-rate-Nothing" value (modifier . Async.rate Nothing) , o_1_space_joining value modifier ] ++ if wide then [] else o_1_space_outerProduct value modifier diff --git a/benchmark/Streamly/Benchmark/Prelude/Ahead.hs b/benchmark/Streamly/Benchmark/Prelude/Ahead.hs deleted file mode 100644 index a6413f504d..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Ahead.hs +++ /dev/null @@ -1,135 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Prelude hiding (mapM) - -import Streamly.Prelude (fromAhead, fromSerial, ahead, maxBuffer, maxThreads) -import qualified Streamly.Prelude as S - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.Ahead" - -------------------------------------------------------------------------------- --- Benchmark groups -------------------------------------------------------------------------------- - --- unfoldr and fromFoldable are always serial and therefore the same for --- all stream types. They can be removed to reduce the number of benchmarks. -o_1_space_generation :: Int -> [Benchmark] -o_1_space_generation value = - [ bgroup "generation" - [ benchIOSrc fromAhead "unfoldr" (sourceUnfoldr value) - , benchIOSrc fromAhead "unfoldrM" (sourceUnfoldrM value) - , benchIOSrc fromAhead "fromFoldable" (sourceFromFoldable value) - , benchIOSrc fromAhead "fromFoldableM" (sourceFromFoldableM value) - , benchIOSrc fromAhead "unfoldrM maxThreads 1" - (maxThreads 1 . sourceUnfoldrM value) - , benchIOSrc fromAhead "unfoldrM maxBuffer 1 (x/10 ops)" - (maxBuffer 1 . sourceUnfoldrM (value `div` 10)) - ] - ] - -o_1_space_mapping :: Int -> [Benchmark] -o_1_space_mapping value = - [ bgroup "mapping" - [ benchIOSink value "map" $ mapN fromAhead 1 - , benchIOSink value "fmap" $ fmapN fromAhead 1 - , benchIOSink value "mapM" $ mapM fromAhead 1 . fromSerial - ] - ] - -o_1_space_concatFoldable :: Int -> [Benchmark] -o_1_space_concatFoldable value = - [ bgroup - "concat-foldable" - [ benchIOSrc fromAhead "foldMapWith (<>) (List)" - (sourceFoldMapWith value) - , benchIOSrc fromAhead "foldMapWith (<>) (Stream)" - (sourceFoldMapWithStream value) - , benchIOSrc fromAhead "foldMapWithM (<>) (List)" - (sourceFoldMapWithM value) - , benchIOSrc fromSerial "S.concatFoldableWith (<>) (List)" - (concatFoldableWith value) - , benchIOSrc fromSerial "S.concatForFoldableWith (<>) (List)" - (concatForFoldableWith value) - , benchIOSrc fromAhead "foldMapM (List)" (sourceFoldMapM value) - ] - ] - -o_1_space_concatMap :: Int -> [Benchmark] -o_1_space_concatMap value = - value2 `seq` - [ bgroup "concat" - -- This is for comparison with foldMapWith - [ benchIOSrc fromSerial "concatMapWithId (n of 1) (fromFoldable)" - (S.concatMapWith ahead id . sourceConcatMapId value) - - , benchIO "concatMapWith (n of 1)" - (concatStreamsWith ahead value 1) - , benchIO "concatMapWith (sqrt x of sqrt x)" - (concatStreamsWith ahead value2 value2) - , benchIO "concatMapWith (1 of n)" - (concatStreamsWith ahead 1 value) - ] - ] - - where - - value2 = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monadic outer product -------------------------------------------------------------------------------- - -o_1_space_outerProduct :: Int -> [Benchmark] -o_1_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp value fromAhead - , benchIO "toNull" $ toNullM value fromAhead - , benchIO "toNull3" $ toNullM3 value fromAhead - , benchIO "filterAllOut" $ filterAllOutM value fromAhead - , benchIO "filterAllIn" $ filterAllInM value fromAhead - , benchIO "filterSome" $ filterSome value fromAhead - , benchIO "breakAfterSome" $ breakAfterSome value fromAhead - - ] - ] - -o_n_space_outerProduct :: Int -> [Benchmark] -o_n_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toList" $ toListM value fromAhead - , benchIO "toListSome" $ toListSome value fromAhead - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks value = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_generation value - , o_1_space_mapping value - , o_1_space_concatFoldable value - , o_1_space_concatMap value - , o_1_space_outerProduct value - ] - , bgroup (o_n_space_prefix moduleName) (o_n_space_outerProduct value) - ] From 536cdc4847e33b0e0008b0cca9f1046a2ec5102f Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Thu, 27 Nov 2025 21:37:02 +0530 Subject: [PATCH 03/24] Remove Prelude.Async benchmark --- benchmark/Streamly/Benchmark/Prelude/Async.hs | 204 ------------------ 1 file changed, 204 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Async.hs diff --git a/benchmark/Streamly/Benchmark/Prelude/Async.hs b/benchmark/Streamly/Benchmark/Prelude/Async.hs deleted file mode 100644 index 9e9a333082..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Async.hs +++ /dev/null @@ -1,204 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Prelude hiding (mapM) - -import Streamly.Prelude (fromAsync, async, maxBuffer, maxThreads, fromSerial) -import qualified Streamly.Prelude as S -import qualified Streamly.Internal.Data.Stream.IsStream.Transform as Transform - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.Async" - -------------------------------------------------------------------------------- --- Generation -------------------------------------------------------------------------------- - -o_1_space_generation :: Int -> [Benchmark] -o_1_space_generation value = - -- These basically test the performance of consMAsync - [ bgroup "generation" - [ benchIOSrc fromAsync "unfoldr" (sourceUnfoldr value) - , benchIOSrc fromAsync "unfoldrM" (sourceUnfoldrM value) - , benchIOSrc fromAsync "fromListM" (sourceFromListM value) - , benchIOSrc fromAsync "fromFoldable (List)" (sourceFromFoldable value) - , benchIOSrc fromAsync "fromFoldableM (List)" (sourceFromFoldableM value) - , benchIOSrc fromAsync "unfoldrM maxThreads 1" - (maxThreads 1 . sourceUnfoldrM value) - , benchIOSrc fromAsync "unfoldrM maxBuffer 1 (x/10 ops)" - (maxBuffer 1 . sourceUnfoldrM (value `div` 10)) - ] - ] - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -{-# INLINE foldrSShared #-} -foldrSShared :: Int -> Int -> IO () -foldrSShared count n = - S.drain - $ fromAsync - $ Transform.foldrSShared (\x xs -> S.consM (return x) xs) S.nil - $ fromSerial - $ sourceUnfoldrM count n - -o_1_space_mapping :: Int -> [Benchmark] -o_1_space_mapping value = - [ bgroup "mapping" - [ benchIOSink value "map" $ mapN fromAsync 1 - , benchIOSink value "fmap" $ fmapN fromAsync 1 - , benchIOSrc1 "foldrSShared" (foldrSShared value) - -- This basically tests the performance of consMAsync - , benchIOSink value "mapM" $ mapM fromAsync 1 . fromSerial - ] - ] - -------------------------------------------------------------------------------- --- Size conserving transformations (reordering, buffering, etc.) -------------------------------------------------------------------------------- - -o_n_heap_buffering :: Int -> [Benchmark] -o_n_heap_buffering value = - [bgroup "buffered" [benchIOSink value "mkAsync" (mkAsync fromAsync)]] - -------------------------------------------------------------------------------- --- Joining -------------------------------------------------------------------------------- - -{-# INLINE async2 #-} -async2 :: Int -> Int -> IO () -async2 count n = - S.drain $ - (sourceUnfoldrM count n) `async` (sourceUnfoldrM count (n + 1)) - -{-# INLINE async4 #-} -async4 :: Int -> Int -> IO () -async4 count n = - S.drain $ - (sourceUnfoldrM count (n + 0)) - `async` (sourceUnfoldrM count (n + 1)) - `async` (sourceUnfoldrM count (n + 2)) - `async` (sourceUnfoldrM count (n + 3)) - -{-# INLINE async2n2 #-} -async2n2 :: Int -> Int -> IO () -async2n2 count n = - S.drain $ - ((sourceUnfoldrM count (n + 0)) - `async` (sourceUnfoldrM count (n + 1))) - `async` ((sourceUnfoldrM count (n + 2)) - `async` (sourceUnfoldrM count (n + 3))) - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc1 "async (2 of n/2)" (async2 (value `div` 2)) - , benchIOSrc1 "async (4 of n/4)" (async4 (value `div` 4)) - , benchIOSrc1 "async (2 of (2 of n/4)" (async2n2 (value `div` 4)) - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - --- These basically test the performance of folding streams with `async` -o_1_space_concatFoldable :: Int -> [Benchmark] -o_1_space_concatFoldable value = - [ bgroup "concat-foldable" - [ benchIOSrc fromAsync "foldMapWith (<>) (List)" - (sourceFoldMapWith value) - , benchIOSrc fromAsync "foldMapWith (<>) (Stream)" - (sourceFoldMapWithStream value) - , benchIOSrc fromAsync "foldMapWithM (<>) (List)" - (sourceFoldMapWithM value) - , benchIOSrc fromAsync "S.concatFoldableWith (<>) (List)" - (concatFoldableWith value) - , benchIOSrc fromAsync "S.concatForFoldableWith (<>) (List)" - (concatForFoldableWith value) - , benchIOSrc fromAsync "foldMapM (List)" (sourceFoldMapM value) - ] - ] - --- These basically test the performance of concating streams with `async` -o_1_space_concatMap :: Int -> [Benchmark] -o_1_space_concatMap value = - value2 `seq` - [ bgroup "concat" - -- This is for comparison with foldMapWith - [ benchIOSrc fromSerial "concatMapWithId (n of 1) (fromFoldable)" - (S.concatMapWith async id . sourceConcatMapId value) - - , benchIO "concatMapWith (n of 1)" - (concatStreamsWith async value 1) - , benchIO "concatMapWith (sqrt x of sqrt x)" - (concatStreamsWith async value2 value2) - , benchIO "concatMapWith (1 of n)" - (concatStreamsWith async 1 value) - ] - ] - - where - - value2 = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monadic outer product -------------------------------------------------------------------------------- - -o_1_space_outerProduct :: Int -> [Benchmark] -o_1_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp value fromAsync - , benchIO "toNull" $ toNullM value fromAsync - , benchIO "toNull3" $ toNullM3 value fromAsync - , benchIO "filterAllOut" $ filterAllOutM value fromAsync - , benchIO "filterAllIn" $ filterAllInM value fromAsync - , benchIO "filterSome" $ filterSome value fromAsync - , benchIO "breakAfterSome" $ breakAfterSome value fromAsync - - ] - ] - -o_n_space_outerProduct :: Int -> [Benchmark] -o_n_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toList" $ toListM value fromAsync - , benchIO "toListSome" $ toListSome value fromAsync - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - - where - - allBenchmarks value = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_generation value - , o_1_space_mapping value - , o_1_space_concatFoldable value - , o_1_space_concatMap value - , o_1_space_outerProduct value - , o_1_space_joining value - ] - , bgroup (o_n_heap_prefix moduleName) (o_n_heap_buffering value) - , bgroup (o_n_space_prefix moduleName) (o_n_space_outerProduct value) - ] From 4dcbe6eb795201bbf06d1ee5fb6e2d94028ad137 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 11:42:38 +0530 Subject: [PATCH 04/24] Remove Prelude.Parallel benchmark --- .../Benchmark/Data/Stream/ConcurrentCommon.hs | 31 +++ .../Streamly/Benchmark/Prelude/Parallel.hs | 240 ------------------ 2 files changed, 31 insertions(+), 240 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Parallel.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs index a3604bb907..4d7e3f5e54 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs @@ -18,6 +18,7 @@ import Streamly.Internal.Data.Stream.Prelude (MonadAsync, Config) import qualified Data.List as List import qualified Streamly.Data.Fold as Fold +import qualified Streamly.Data.Fold.Prelude as Fold import qualified Streamly.Data.Stream as Stream import qualified Streamly.Internal.Data.Stream.Prelude as Async @@ -57,6 +58,8 @@ o_n_heap_buffering value f = [ bgroup "buffered" [ benchIOSink value "mkAsync" (Stream.fold Fold.drain . Async.parBuffered f) + , benchIOSink value "fmap" + (Stream.fold Fold.drain . fmap (+1) . Async.parBuffered f) ] ] @@ -79,11 +82,39 @@ concatAsync2 f count n = $ Stream.fromList [sourceUnfoldrM count n, sourceUnfoldrM count (n + 1)] +{-# INLINE parMergeByM #-} +parMergeByM :: (Config -> Config) -> Int -> Int -> IO () +parMergeByM f count n = + Stream.fold Fold.drain + $ Async.parMergeByM f + (\a b -> return (a `compare` b)) + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +{-# INLINE parMergeBy #-} +parMergeBy :: (Config -> Config) -> Int -> Int -> IO () +parMergeBy f count n = + Stream.fold Fold.drain + $ Async.parMergeBy f + compare + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +{-# INLINE parTap #-} +parTap :: (Fold.Config -> Fold.Config) -> Int -> Int -> IO () +parTap f count n = + Stream.fold Fold.drain + $ Stream.tap (Fold.parBuffered f Fold.sum) (sourceUnfoldrM count n) + o_1_space_joining :: Int -> (Config -> Config) -> [Benchmark] o_1_space_joining value f = [ bgroup "joining" [ benchIOSrc1 "async (2 of n/2)" (async2 f (value `div` 2)) , benchIOSrc1 "concat async (2 of n/2)" (concatAsync2 f (value `div` 2)) + , benchIOSrc1 "parMergeByM (2 of n/2)" (parMergeByM f (value `div` 2)) + , benchIOSrc1 "parMergeBy (2 of n/2)" (parMergeBy f (value `div` 2)) + -- XXX use configurable modifier, put this in concurrent fold benchmarks + , benchIOSrc1 "parTap" (parTap id value) ] ] diff --git a/benchmark/Streamly/Benchmark/Prelude/Parallel.hs b/benchmark/Streamly/Benchmark/Prelude/Parallel.hs deleted file mode 100644 index a4cef5084c..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Parallel.hs +++ /dev/null @@ -1,240 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -{-# LANGUAGE FlexibleContexts #-} - -import Prelude hiding (mapM) - -import Data.Function ((&)) -import Streamly.Prelude - ( SerialT, fromParallel, parallel, fromSerial, maxBuffer, maxThreads) - -import qualified Streamly.Prelude as S -import qualified Streamly.Internal.Data.Fold as FL -import qualified Streamly.Internal.Data.Stream.IsStream as Internal - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.Parallel" - -------------------------------------------------------------------------------- --- Merging -------------------------------------------------------------------------------- - -{-# INLINE mergeAsyncByM #-} -mergeAsyncByM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int -mergeAsyncByM count n = - S.mergeAsyncByM - (\a b -> return (a `compare` b)) - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -{-# INLINE mergeAsyncBy #-} -mergeAsyncBy :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int -mergeAsyncBy count n = - S.mergeAsyncBy - compare - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -------------------------------------------------------------------------------- --- Application/fold -------------------------------------------------------------------------------- - -{-# INLINE parAppMap #-} -parAppMap :: S.MonadAsync m => SerialT m Int -> m () -parAppMap src = S.drain $ S.map (+1) S.|$ src - -{-# INLINE parAppSum #-} -parAppSum :: S.MonadAsync m => SerialT m Int -> m () -parAppSum src = (S.sum S.|$. src) >>= \x -> seq x (return ()) - -{-# INLINE (|&) #-} -(|&) :: S.MonadAsync m => SerialT m Int -> m () -(|&) src = src S.|& S.map (+ 1) & S.drain - -{-# INLINE (|&.) #-} -(|&.) :: S.MonadAsync m => SerialT m Int -> m () -(|&.) src = (src S.|&. S.sum) >>= \x -> seq x (return ()) - -------------------------------------------------------------------------------- --- Tapping -------------------------------------------------------------------------------- - -{-# INLINE tapAsyncS #-} -tapAsyncS :: S.MonadAsync m => Int -> SerialT m Int -> m () -tapAsyncS n = composeN n $ Internal.tapAsyncK S.sum - -{-# INLINE tapAsync #-} -tapAsync :: S.MonadAsync m => Int -> SerialT m Int -> m () -tapAsync n = composeN n $ Internal.tapAsync FL.sum - -o_1_space_merge_app_tap :: Int -> [Benchmark] -o_1_space_merge_app_tap value = - [ bgroup "merge-app-tap" - [ benchIOSrc fromSerial "mergeAsyncBy (2,x/2)" - (mergeAsyncBy (value `div` 2)) - , benchIOSrc fromSerial "mergeAsyncByM (2,x/2)" - (mergeAsyncByM (value `div` 2)) - -- Parallel stages in a pipeline - , benchIOSink value "parAppMap" parAppMap - , benchIOSink value "parAppSum" parAppSum - , benchIOSink value "(|&)" (|&) - , benchIOSink value "(|&.)" (|&.) - , benchIOSink value "tapAsync" (tapAsync 1) - , benchIOSink value "tapAsyncS" (tapAsyncS 1) - ] - ] - -------------------------------------------------------------------------------- --- Generation -------------------------------------------------------------------------------- - -o_n_heap_generation :: Int -> [Benchmark] -o_n_heap_generation value = - [ bgroup - "generation" - [ benchIOSrc fromParallel "unfoldr" (sourceUnfoldr value) - , benchIOSrc fromParallel "unfoldrM" (sourceUnfoldrM value) - , benchIOSrc fromParallel "fromFoldable" (sourceFromFoldable value) - , benchIOSrc fromParallel "fromFoldableM" (sourceFromFoldableM value) - , benchIOSrc fromParallel "unfoldrM maxThreads 1" - (maxThreads 1 . sourceUnfoldrM value) - , benchIOSrc fromParallel "unfoldrM maxBuffer 1 (x/10 ops)" - (maxBuffer 1 . sourceUnfoldrM (value `div` 10)) - ] - ] - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -o_n_heap_mapping :: Int -> [Benchmark] -o_n_heap_mapping value = - [ bgroup "mapping" - [ benchIOSink value "map" $ mapN fromParallel 1 - , benchIOSink value "fmap" $ fmapN fromParallel 1 - , benchIOSink value "mapM" $ mapM fromParallel 1 . fromSerial - ] - ] - - -------------------------------------------------------------------------------- --- Joining -------------------------------------------------------------------------------- - -{-# INLINE parallel2 #-} -parallel2 :: Int -> Int -> IO () -parallel2 count n = - S.drain $ - (sourceUnfoldrM count n) `parallel` (sourceUnfoldrM count (n + 1)) - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc1 "parallel (2 of n/2)" (parallel2 (value `div` 2)) - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -o_n_heap_concatFoldable :: Int -> [Benchmark] -o_n_heap_concatFoldable value = - [ bgroup - "concat-foldable" - [ benchIOSrc fromParallel "foldMapWith (<>) (List)" - (sourceFoldMapWith value) - , benchIOSrc fromParallel "foldMapWith (<>) (Stream)" - (sourceFoldMapWithStream value) - , benchIOSrc fromParallel "foldMapWithM (<>) (List)" - (sourceFoldMapWithM value) - , benchIOSrc fromSerial "S.concatFoldableWith (<>) (List)" - (concatFoldableWith value) - , benchIOSrc fromSerial "S.concatForFoldableWith (<>) (List)" - (concatForFoldableWith value) - , benchIOSrc fromParallel "foldMapM (List)" (sourceFoldMapM value) - ] - ] - -o_n_heap_concat :: Int -> [Benchmark] -o_n_heap_concat value = - value2 `seq` - [ bgroup "concat" - -- This is for comparison with foldMapWith - [ benchIOSrc fromSerial "concatMapWithId (n of 1) (fromFoldable)" - (S.concatMapWith parallel id . sourceConcatMapId value) - - , benchIO "concatMapWith (n of 1)" - (concatStreamsWith parallel value 1) - , benchIO "concatMapWith (sqrt x of sqrt x)" - (concatStreamsWith parallel value2 value2) - , benchIO "concatMapWith (1 of n)" - (concatStreamsWith parallel 1 value) - ] - ] - - where - - value2 = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monadic outer product -------------------------------------------------------------------------------- - -o_n_heap_outerProduct :: Int -> [Benchmark] -o_n_heap_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp value fromParallel - , benchIO "toNull" $ toNullM value fromParallel - , benchIO "toNull3" $ toNullM3 value fromParallel - , benchIO "filterAllOut" $ filterAllOutM value fromParallel - , benchIO "filterAllIn" $ filterAllInM value fromParallel - , benchIO "filterSome" $ filterSome value fromParallel - , benchIO "breakAfterSome" $ breakAfterSome value fromParallel - ] - ] - -o_n_space_outerProduct :: Int -> [Benchmark] -o_n_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toList" $ toListM value fromParallel - -- XXX disabled due to a bug for now - -- , benchIO "toListSome" $ toListSome value fromParallel - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks value = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_merge_app_tap value - , o_1_space_joining value - ] - , bgroup (o_n_heap_prefix moduleName) $ concat - [ o_n_heap_generation value - , o_n_heap_mapping value - , o_n_heap_concatFoldable value - , o_n_heap_concat value - , o_n_heap_outerProduct value - ] - , bgroup (o_n_space_prefix moduleName) (o_n_space_outerProduct value) - ] From d48deaf669e58123a9b3f07c0e52abecdbf0726e Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 11:54:56 +0530 Subject: [PATCH 05/24] Remove Prelude.Rate --- benchmark/Streamly/Benchmark/Prelude/Rate.hs | 110 ------------------- 1 file changed, 110 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Rate.hs diff --git a/benchmark/Streamly/Benchmark/Prelude/Rate.hs b/benchmark/Streamly/Benchmark/Prelude/Rate.hs deleted file mode 100644 index 6f08540586..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Rate.hs +++ /dev/null @@ -1,110 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} -{-# LANGUAGE FlexibleContexts #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Streamly.Prelude (fromAsync, fromAhead, maxThreads, IsStream, MonadAsync) -import qualified Streamly.Prelude as S - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.Rate" - -------------------------------------------------------------------------------- --- Average Rate -------------------------------------------------------------------------------- - -{-# INLINE rateNothing #-} -rateNothing :: (MonadAsync m, IsStream t) => Int -> Int -> t m Int -rateNothing value = S.rate Nothing . sourceUnfoldrM value - -{-# INLINE avgRate #-} -avgRate :: (MonadAsync m, IsStream t) => Int -> Double -> Int -> t m Int -avgRate value rate_ = S.avgRate rate_ . sourceUnfoldrM value - -{-# INLINE avgRateThreads1 #-} -avgRateThreads1 :: (MonadAsync m, IsStream t) => Int -> Double -> Int -> t m Int -avgRateThreads1 value rate_ = - maxThreads 1 . S.avgRate rate_ . sourceUnfoldrM value - -{-# INLINE minRate #-} -minRate :: (MonadAsync m, IsStream t) => Int -> Double -> Int -> t m Int -minRate value rate_ = S.minRate rate_ . sourceUnfoldrM value - -{-# INLINE maxRate #-} -maxRate :: (MonadAsync m, IsStream t) => Int -> Double -> Int -> t m Int -maxRate value rate_ = S.minRate rate_ . sourceUnfoldrM value - -{-# INLINE constRate #-} -constRate :: (MonadAsync m, IsStream t) => Int -> Double -> Int -> t m Int -constRate value rate_ = S.constRate rate_ . sourceUnfoldrM value - --- XXX arbitrarily large rate should be the same as rate Nothing -o_1_space_async :: Int -> [Benchmark] -o_1_space_async value = - [ bgroup - "asyncly" - [ bgroup - "avgRate" - -- benchIO "unfoldr" $ toNull fromAsync - -- benchIOSrc fromAsync "unfoldrM" (sourceUnfoldrM value) - [ benchIOSrc fromAsync "Nothing" $ rateNothing value - , benchIOSrc fromAsync "1M" $ avgRate value 1000000 - , benchIOSrc fromAsync "3M" $ avgRate value 3000000 - , benchIOSrc fromAsync "10M/maxThreads1" - $ avgRateThreads1 value 10000000 - , benchIOSrc fromAsync "10M" $ avgRate value 10000000 - , benchIOSrc fromAsync "20M" $ avgRate value 20000000 - ] - , bgroup - "minRate" - [ benchIOSrc fromAsync "1M" $ minRate value 1000000 - , benchIOSrc fromAsync "10M" $ minRate value 10000000 - , benchIOSrc fromAsync "20M" $ minRate value 20000000 - ] - , bgroup - "maxRate" - [ -- benchIOSrc fromAsync "10K" $ maxRate value 10000 - benchIOSrc fromAsync "10M" $ maxRate value 10000000 - ] - , bgroup - "constRate" - [ -- benchIOSrc fromAsync "10K" $ constRate value 10000 - benchIOSrc fromAsync "1M" $ constRate value 1000000 - , benchIOSrc fromAsync "10M" $ constRate value 10000000 - ] - ] - ] - -o_1_space_ahead :: Int -> [Benchmark] -o_1_space_ahead value = - [ bgroup - "aheadly" - [ benchIOSrc fromAhead "avgRate/1M" $ avgRate value 1000000 - , benchIOSrc fromAhead "minRate/1M" $ minRate value 1000000 - , benchIOSrc fromAhead "maxRate/1M" $ maxRate value 1000000 - , benchIOSrc fromAsync "constRate/1M" $ constRate value 1000000 - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks value = - [ bgroup (o_1_space_prefix moduleName) - $ concat [o_1_space_async value, o_1_space_ahead value]] From 39ec4d149cf217c61b7597fe689dc552df9883e2 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 11:57:53 +0530 Subject: [PATCH 06/24] Remove Prelude.WAsync --- .../Streamly/Benchmark/Prelude/WAsync.hs | 186 ------------------ 1 file changed, 186 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/WAsync.hs diff --git a/benchmark/Streamly/Benchmark/Prelude/WAsync.hs b/benchmark/Streamly/Benchmark/Prelude/WAsync.hs deleted file mode 100644 index b01a0bff87..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/WAsync.hs +++ /dev/null @@ -1,186 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -import Prelude hiding (mapM) - -import Streamly.Prelude (fromWAsync, fromSerial, wAsync, maxBuffer, maxThreads) -import qualified Streamly.Prelude as S - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.WAsync" - -------------------------------------------------------------------------------- --- Generation -------------------------------------------------------------------------------- - -o_1_space_generation :: Int -> [Benchmark] -o_1_space_generation value = - [ bgroup "generation" - [ benchIOSrc fromWAsync "unfoldr" (sourceUnfoldr value) - , benchIOSrc fromWAsync "unfoldrM" (sourceUnfoldrM value) - , benchIOSrc fromWAsync "fromFoldable" (sourceFromFoldable value) - , benchIOSrc fromWAsync "fromFoldableM" (sourceFromFoldableM value) - , benchIOSrc fromWAsync "unfoldrM maxThreads 1" - (maxThreads 1 . sourceUnfoldrM value) - , benchIOSrc fromWAsync "unfoldrM maxBuffer 1 (x/10 ops)" - (maxBuffer 1 . sourceUnfoldrM (value `div` 10)) - ] - ] - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -o_1_space_mapping :: Int -> [Benchmark] -o_1_space_mapping value = - [ bgroup "mapping" - [ benchIOSink value "map" $ mapN fromWAsync 1 - , benchIOSink value "fmap" $ fmapN fromWAsync 1 - , benchIOSink value "mapM" $ mapM fromWAsync 1 . fromSerial - ] - ] - -------------------------------------------------------------------------------- --- Joining -------------------------------------------------------------------------------- - -{-# INLINE wAsync2 #-} -wAsync2 :: Int -> Int -> IO () -wAsync2 count n = - S.drain $ - (sourceUnfoldrM count n) `wAsync` (sourceUnfoldrM count (n + 1)) - -{-# INLINE wAsync4 #-} -wAsync4 :: Int -> Int -> IO () -wAsync4 count n = - S.drain $ - (sourceUnfoldrM count (n + 0)) - `wAsync` (sourceUnfoldrM count (n + 1)) - `wAsync` (sourceUnfoldrM count (n + 2)) - `wAsync` (sourceUnfoldrM count (n + 3)) - -{-# INLINE wAsync2n2 #-} -wAsync2n2 :: Int -> Int -> IO () -wAsync2n2 count n = - S.drain $ - ((sourceUnfoldrM count (n + 0)) - `wAsync` (sourceUnfoldrM count (n + 1))) - `wAsync` ((sourceUnfoldrM count (n + 2)) - `wAsync` (sourceUnfoldrM count (n + 3))) - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc1 "wAsync (2 of n/2)" (wAsync2 (value `div` 2)) - , benchIOSrc1 "wAsync (4 of n/4)" (wAsync4 (value `div` 4)) - , benchIOSrc1 "wAsync (2 of (2 of n/4)" (wAsync2n2 (value `div` 4)) - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -o_1_space_concatFoldable :: Int -> [Benchmark] -o_1_space_concatFoldable value = - [ bgroup "concat-foldable" - [ benchIOSrc fromWAsync "foldMapWith (<>) (List)" - (sourceFoldMapWith value) - , benchIOSrc fromWAsync "foldMapWith (<>) (Stream)" - (sourceFoldMapWithStream value) - , benchIOSrc fromWAsync "foldMapWithM (<>) (List)" - (sourceFoldMapWithM value) - , benchIOSrc fromSerial "S.concatFoldableWith (<>) (List)" - (concatFoldableWith value) - , benchIOSrc fromSerial "S.concatForFoldableWith (<>) (List)" - (concatForFoldableWith value) - , benchIOSrc fromWAsync "foldMapM (List)" (sourceFoldMapM value) - ] - ] - --- When we merge streams using wAsync the size of the queue increases --- slowly because of the binary composition adding just one more item --- to the work queue only after every scheduling pass through the --- work queue. --- --- We should see the memory consumption increasing slowly if these --- benchmarks are left to run on infinite number of streams of infinite --- sizes. -o_1_space_concatMap :: Int -> [Benchmark] -o_1_space_concatMap value = - value2 `seq` - [ bgroup "concat" - -- This is for comparison with foldMapWith - [ benchIOSrc fromSerial "concatMapWithId (n of 1) (fromFoldable)" - (S.concatMapWith wAsync id . sourceConcatMapId value) - - , benchIO "concatMapWith (n of 1)" - (concatStreamsWith wAsync value 1) - , benchIO "concatMapWith (sqrt x of sqrt x)" - (concatStreamsWith wAsync value2 value2) - , benchIO "concatMapWith (1 of n)" - (concatStreamsWith wAsync 1 value) - ] - ] - - where - - value2 = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monadic outer product -------------------------------------------------------------------------------- - -o_n_heap_outerProduct :: Int -> [Benchmark] -o_n_heap_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp value fromWAsync - , benchIO "toNull" $ toNullM value fromWAsync - , benchIO "toNull3" $ toNullM3 value fromWAsync - , benchIO "filterAllOut" $ filterAllOutM value fromWAsync - , benchIO "filterAllIn" $ filterAllInM value fromWAsync - , benchIO "filterSome" $ filterSome value fromWAsync - , benchIO "breakAfterSome" $ breakAfterSome value fromWAsync - - ] - ] - -o_n_space_outerProduct :: Int -> [Benchmark] -o_n_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toList" $ toListM value fromWAsync - , benchIO "toListSome" $ toListSome value fromWAsync - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks value = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_generation value - , o_1_space_mapping value - , o_1_space_joining value - , o_1_space_concatFoldable value - , o_1_space_concatMap value - ] - , bgroup (o_n_heap_prefix moduleName) (o_n_heap_outerProduct value) - , bgroup (o_n_space_prefix moduleName) (o_n_space_outerProduct value) - ] From 412805978c006f3cb7c36adec7654d94896ab15a Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 13:27:05 +0530 Subject: [PATCH 07/24] Remove Prelude.WSerial benchmark Add StreamK.interleave benchmark equivalent to wSerial2 Add Stream.interleave benchmark to Stream/Expand.hs --- .../Streamly/Benchmark/Data/Stream/Expand.hs | 101 ++++- benchmark/Streamly/Benchmark/Data/StreamK.hs | 172 +++++++- .../Streamly/Benchmark/Prelude/WSerial.hs | 369 ------------------ 3 files changed, 257 insertions(+), 385 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/WSerial.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index ca79466758..6ba7591774 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -70,11 +70,84 @@ serial4 count n = (sourceUnfoldrM count (n + 2)) (sourceUnfoldrM count (n + 3))) +{-# INLINE interleave2 #-} +interleave2 :: Int -> Int -> IO () +interleave2 count n = + drain $ + S.interleave + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'interleave2 +inspect $ 'interleave2 `hasNoType` ''SPEC +inspect $ 'interleave2 `hasNoType` ''S.InterleaveState +#endif + +{-# INLINE roundRobin2 #-} +roundRobin2 :: Int -> Int -> IO () +roundRobin2 value n = + S.drain $ + S.roundRobin + (sourceUnfoldrM (value `div` 2) n) + (sourceUnfoldrM (value `div` 2) (n + 1)) + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'roundRobin2 +inspect $ 'roundRobin2 `hasNoType` ''SPEC +inspect $ 'roundRobin2 `hasNoType` ''S.InterleaveState +#endif + +{-# INLINE sourceUnfoldrMUF #-} +-- unfold input is (count, value) +sourceUnfoldrMUF :: Monad m => Int -> UF.Unfold m (Int, Int) Int +sourceUnfoldrMUF count = UF.unfoldrM step + where + step (cnt, start) = + return $ + if cnt > start + count + then Nothing + else Just (cnt, (cnt + 1, start)) + +{-# INLINE bfsUnfoldEach #-} +bfsUnfoldEach :: Int -> Int -> Int -> IO () +bfsUnfoldEach outer inner n = + S.drain $ S.bfsUnfoldEach + -- (UF.lmap return (UF.replicateM inner)) + (UF.lmap (\x -> (x,x)) (sourceUnfoldrMUF inner)) + (sourceUnfoldrM outer n) + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'bfsUnfoldEach +-- inspect $ 'bfsUnfoldEach `hasNoType` ''SPEC +-- inspect $ 'bfsUnfoldEach `hasNoType` +-- ''S.ConcatUnfoldInterleaveState +#endif + +{-# INLINE unfoldSched #-} +unfoldSched :: Int -> Int -> Int -> IO () +unfoldSched outer inner n = + S.drain $ S.unfoldSched + -- (UF.lmap return (UF.replicateM inner)) + (UF.lmap (\x -> (x,x)) (sourceUnfoldrMUF inner)) + (sourceUnfoldrM outer n) + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'unfoldSched +-- inspect $ 'unfoldSched `hasNoType` ''SPEC +-- inspect $ 'unfoldSched `hasNoType` +-- ''D.ConcatUnfoldInterleaveState +#endif + o_1_space_joining :: Int -> [Benchmark] o_1_space_joining value = [ bgroup "joining" [ benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2)) , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4)) + , benchIOSrc1 "interleave (2,x/2)" (interleave2 (value `div` 2)) + , benchIOSrc1 "roundRobin (2,x/2)" (roundRobin2 (value `div` 2)) + , benchIOSrc1 "bfsUnfoldEach (2,x/2)" (bfsUnfoldEach 2 (value `div` 2)) + , benchIOSrc1 "unfoldSched (2,x/2)" (unfoldSched 2 (value `div` 2)) ] ] @@ -249,6 +322,31 @@ o_1_space_concat value = sqrtVal `seq` sqrtVal = round $ sqrt (fromIntegral value :: Double) +o_n_heap_concat :: Int -> [Benchmark] +o_n_heap_concat value = sqrtVal `seq` + [ bgroup "concat" + [ + benchIOSrc1 + "bfsUnfoldEach (n of 1)" + (bfsUnfoldEach value 1) + , benchIOSrc1 + "bfsUnfoldEach (sqrtVal of sqrtVal)" + (bfsUnfoldEach sqrtVal sqrtVal) + + , benchIOSrc1 + "unfoldSched (n of 1)" + (unfoldSched value 1) + , benchIOSrc1 + "unfoldSched (sqrtVal of sqrtVal)" + (unfoldSched sqrtVal sqrtVal) + + ] + ] + + where + + sqrtVal = round $ sqrt (fromIntegral value :: Double) + ------------------------------------------------------------------------------- -- Applicative ------------------------------------------------------------------------------- @@ -689,9 +787,10 @@ benchmarks moduleName size = -- multi-stream o_n_space_monad size ] - {- , bgroup (o_n_heap_prefix moduleName) $ + {- -- multi-stream o_n_heap_buffering size -} + (o_n_heap_concat size) ] diff --git a/benchmark/Streamly/Benchmark/Data/StreamK.hs b/benchmark/Streamly/Benchmark/Data/StreamK.hs index c38ca4300a..99235f662f 100644 --- a/benchmark/Streamly/Benchmark/Data/StreamK.hs +++ b/benchmark/Streamly/Benchmark/Data/StreamK.hs @@ -26,12 +26,14 @@ import Control.Applicative (liftA2) #endif import Control.Monad (when) import Data.Maybe (isJust) +import Streamly.Internal.Data.Stream (Stream) import Streamly.Internal.Data.StreamK (StreamK) import System.Random (randomRIO) import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark) import qualified Data.List as List import qualified Prelude as P +import qualified Streamly.Internal.Data.Stream as Stream import qualified Streamly.Internal.Data.StreamK as StreamK import Prelude hiding @@ -331,6 +333,73 @@ sortByK f = StreamK.mergeMapWith (StreamK.mergeBy f) StreamK.fromPure sortBy :: Monad m => StreamK m Int -> m () sortBy = drain . sortByK compare +------------------------------------------------------------------------------- +-- Joining +------------------------------------------------------------------------------- + +{-# INLINE interleave2 #-} +interleave2 :: Int -> Int -> IO () +interleave2 value n = + StreamK.drain $ StreamK.interleave + (unfoldrM (value `div` 2) n) + (unfoldrM (value `div` 2) (n + 1)) + +{-# INLINE concatMapWith #-} +concatMapWith + :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int) + -> Int + -> Int + -> Int + -> IO () +concatMapWith op outer inner n = + StreamK.drain $ StreamK.concatMapWith op + (unfoldrM inner) + (unfoldrM outer n) + +{-# INLINE concatMapWithD #-} +concatMapWithD + :: (Stream IO Int -> Stream IO Int -> Stream IO Int) + -> Int + -> Int + -> Int + -> IO () +concatMapWithD op outer inner n = + StreamK.drain $ StreamK.concatMapWith op1 + (unfoldrM inner) + (unfoldrM outer n) + + where + + op1 s1 s2 = StreamK.fromStream $ op (StreamK.toStream s1) (StreamK.toStream s2) + +{-# INLINE mergeMapWith #-} +mergeMapWith + :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int) + -> Int + -> Int + -> Int + -> IO () +mergeMapWith op outer inner n = + StreamK.drain $ StreamK.mergeMapWith op + (unfoldrM inner) + (unfoldrM outer n) + +{-# INLINE mergeMapWithD #-} +mergeMapWithD + :: (Stream IO Int -> Stream IO Int -> Stream IO Int) + -> Int + -> Int + -> Int + -> IO () +mergeMapWithD op outer inner n = + StreamK.drain $ StreamK.mergeMapWith op1 + (unfoldrM inner) + (unfoldrM outer n) + + where + + op1 s1 s2 = StreamK.fromStream $ op (StreamK.toStream s1) (StreamK.toStream s2) + ------------------------------------------------------------------------------- -- Mixed Composition ------------------------------------------------------------------------------- @@ -424,13 +493,6 @@ sourceConcatMapId :: Monad m sourceConcatMapId val n = StreamK.fromFoldable $ fmap (StreamK.fromEffect . return) [n..n+val] -{-# INLINE concatMapBySerial #-} -concatMapBySerial :: Int -> Int -> Int -> IO () -concatMapBySerial outer inner n = - StreamK.drain $ StreamK.concatMapWith StreamK.append - (unfoldrM inner) - (unfoldrM outer n) - ------------------------------------------------------------------------------- -- Nested Composition ------------------------------------------------------------------------------- @@ -747,6 +809,36 @@ o_1_space_transformationX4 streamLen = -- , benchFold "concatMap" (concatMap 4) (unfoldrM streamLen16) ] +o_1_space_joining :: Int -> Benchmark +o_1_space_joining streamLen = + bgroup "joining" + [ bgroup "(2 of n/2)" + [ benchIOSrc1 "interleave" (interleave2 streamLen) + + -- join 2 streams using concatMapWith + , benchIOSrc1 + "concatMapWith interleave" + (concatMapWith StreamK.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "concatMapWith D.interleave" + (concatMapWithD Stream.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "concatMapWith D.roundRobin" + (concatMapWithD Stream.roundRobin 2 (streamLen `div` 2)) + + -- join 2 streams using mergeMapWith + , benchIOSrc1 + "mergeMapWith interleave" + (mergeMapWith StreamK.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWith D.interleave" + (mergeMapWithD Stream.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWith D.roundRobin" + (mergeMapWithD Stream.roundRobin 2 (streamLen `div` 2)) + ] + ] + o_1_space_concat :: Int -> Benchmark o_1_space_concat streamLen = bgroup "concat" @@ -774,13 +866,60 @@ o_1_space_concat streamLen = . sourceConcatMapId streamLen) , benchIOSrc1 "concatMapWith append outer=Max inner=1" - (concatMapBySerial streamLen 1) + (concatMapWith StreamK.append streamLen 1) , benchIOSrc1 "concatMapWith append outer=inner=(sqrt Max)" - (concatMapBySerial streamLen2 streamLen2) + (concatMapWith StreamK.append streamLen2 streamLen2) , benchIOSrc1 "concatMapWith append outer=1 inner=Max" - (concatMapBySerial 1 streamLen) + (concatMapWith StreamK.append 1 streamLen) + + -- interleave with concatMapWith is O(1) + , benchIOSrc1 "concatMapWith interleave outer=Max inner=1" + (concatMapWith StreamK.interleave streamLen 1) + , benchIOSrc1 "concatMapWith interleave outer=inner=(sqrt Max)" + (concatMapWith StreamK.interleave streamLen2 streamLen2) + , benchIOSrc1 "concatMapWith interleave outer=1 inner=Max" + (concatMapWith StreamK.interleave 1 streamLen) + ] + + where + + streamLen2 = round (P.fromIntegral streamLen**(1/2::P.Double)) -- double nested loop + +o_n_space_concat :: Int -> Benchmark +o_n_space_concat streamLen = + bgroup "concat" + [ + -- concatMapWith using StreamD versions of interleave operations are + -- all quadratic, we just measure the sqrtVal benchmark for comparison. + benchIOSrc1 "concatMapWithD D.interleave outer=inner=(sqrt Max)" + (concatMapWithD Stream.interleave streamLen2 streamLen2) + , benchIOSrc1 "concatMapWithD D.roundRobin outer=inner=(sqrt Max)" + (concatMapWithD Stream.roundRobin streamLen2 streamLen2) ] + where + + streamLen2 = round (P.fromIntegral streamLen**(1/2::P.Double)) -- double nested loop + +o_n_heap_concat :: Int -> Benchmark +o_n_heap_concat streamLen = + bgroup "concat" + [ + benchIOSrc1 "mergeMapWith interleave outer=Max inner=1" + (mergeMapWith StreamK.interleave streamLen 1) + , benchIOSrc1 "mergeMapWith interleave outer=inner=(sqrt Max)" + (mergeMapWith StreamK.interleave streamLen2 streamLen2) + , benchIOSrc1 "mergeMapWith interleave outer=1 inner=Max" + (mergeMapWith StreamK.interleave 1 streamLen) + + , benchIOSrc1 "mergeMapWithD D.interleave outer=inner=(sqrt Max)" + (mergeMapWithD Stream.interleave streamLen2 streamLen2) + , benchIOSrc1 "mergeMapWithD D.roundRobin outer=inner=(sqrt Max)" + (mergeMapWithD Stream.roundRobin streamLen2 streamLen2) + ] + + where + streamLen2 = round (P.fromIntegral streamLen**(1/2::P.Double)) -- double nested loop o_1_space_filtering :: Int -> Benchmark @@ -863,6 +1002,11 @@ o_1_space_mixedX4 streamLen = , benchFold "filter-map" (filterMap streamLen 4) (unfoldrM streamLen) ] +{- HLINT ignore "Use <&>" -} +{-# INLINE benchList #-} +benchList :: P.String -> ([Int] -> [Int]) -> (Int -> [Int]) -> Benchmark +benchList name run f = bench name $ nfIO $ randomRIO (1,1) >>= return . run . f + o_1_space_list :: Int -> Benchmark o_1_space_list streamLen = bgroup "list" @@ -898,6 +1042,7 @@ o_1_space streamLen = , o_1_space_filtering streamLen , o_1_space_filteringX4 streamLen , o_1_space_zipping streamLen + , o_1_space_joining streamLen , o_1_space_mixed streamLen , o_1_space_mixedX2 streamLen , o_1_space_mixedX4 streamLen @@ -913,6 +1058,7 @@ o_n_heap streamLen = , bgroup "concat" [ benchFold "sortBy" sortBy (unfoldrM streamLen) ] + , o_n_heap_concat streamLen ] {-# INLINE benchK #-} @@ -957,13 +1103,9 @@ o_n_space streamLen = [ bgroup "elimination" [ benchFold "toList" toList (unfoldrM streamLen) ] + , o_n_space_concat streamLen ] -{- HLINT ignore "Use <&>" -} -{-# INLINE benchList #-} -benchList :: P.String -> ([Int] -> [Int]) -> (Int -> [Int]) -> Benchmark -benchList name run f = bench name $ nfIO $ randomRIO (1,1) >>= return . run . f - main :: IO () main = do runWithCLIOpts defaultStreamSize allBenchmarks diff --git a/benchmark/Streamly/Benchmark/Prelude/WSerial.hs b/benchmark/Streamly/Benchmark/Prelude/WSerial.hs deleted file mode 100644 index 09de0a3e93..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/WSerial.hs +++ /dev/null @@ -1,369 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RankNTypes #-} - -#ifdef __HADDOCK_VERSION__ -#undef INSPECTION -#endif - -#ifdef INSPECTION -{-# LANGUAGE TemplateHaskell #-} -{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-} -#endif - -import Streamly.Prelude (wSerial, fromWSerial) -import qualified Streamly.Prelude as S -import qualified Streamly.Internal.Data.Stream.IsStream as Internal -import qualified Streamly.Internal.Data.Unfold as UF - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -#ifdef INSPECTION -import GHC.Types (SPEC(..)) -import Test.Inspection - -import qualified Streamly.Internal.Data.Stream as D -#endif - -moduleName :: String -moduleName = "Prelude.WSerial" - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -o_1_space_mapping :: Int -> [Benchmark] -o_1_space_mapping value = - [ bgroup "mapping" - [ benchIOSink value "fmap" $ fmapN fromWSerial 1 ] - ] - -------------------------------------------------------------------------------- --- Interleaving -------------------------------------------------------------------------------- - -{-# INLINE wSerial2 #-} -wSerial2 :: Int -> Int -> IO () -wSerial2 value n = - S.drain $ wSerial - (sourceUnfoldrM (value `div` 2) n) - (sourceUnfoldrM (value `div` 2) (n + 1)) - -{-# INLINE interleave2 #-} -interleave2 :: Int -> Int -> IO () -interleave2 value n = - S.drain $ - Internal.interleave - (sourceUnfoldrM (value `div` 2) n) - (sourceUnfoldrM (value `div` 2) (n + 1)) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'interleave2 -inspect $ 'interleave2 `hasNoType` ''SPEC -inspect $ 'interleave2 `hasNoType` ''D.InterleaveState -#endif - -{-# INLINE roundRobin2 #-} -roundRobin2 :: Int -> Int -> IO () -roundRobin2 value n = - S.drain $ - Internal.roundrobin - (sourceUnfoldrM (value `div` 2) n) - (sourceUnfoldrM (value `div` 2) (n + 1)) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'roundRobin2 -inspect $ 'roundRobin2 `hasNoType` ''SPEC -inspect $ 'roundRobin2 `hasNoType` ''D.InterleaveState -#endif - -{-# INLINE sourceUnfoldrMUF #-} --- (count, value) -sourceUnfoldrMUF :: Monad m => Int -> UF.Unfold m (Int, Int) Int -sourceUnfoldrMUF count = UF.unfoldrM step - where - step (cnt, start) = - return $ - if cnt > start + count - then Nothing - else Just (cnt, (cnt + 1, start)) - -{-# INLINE unfoldManyInterleave #-} -unfoldManyInterleave :: Int -> Int -> Int -> IO () -unfoldManyInterleave outer inner n = - S.drain $ Internal.unfoldManyInterleave - -- (UF.lmap return (UF.replicateM inner)) - (UF.lmap (\x -> (x,x)) (sourceUnfoldrMUF inner)) - (sourceUnfoldrM outer n) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'unfoldManyInterleave --- inspect $ 'unfoldManyInterleave `hasNoType` ''SPEC --- inspect $ 'unfoldManyInterleave `hasNoType` --- ''D.ConcatUnfoldInterleaveState -#endif - -{-# INLINE unfoldManyRoundRobin #-} -unfoldManyRoundRobin :: Int -> Int -> Int -> IO () -unfoldManyRoundRobin outer inner n = - S.drain $ Internal.unfoldManyRoundRobin - -- (UF.lmap return (UF.replicateM inner)) - (UF.lmap (\x -> (x,x)) (sourceUnfoldrMUF inner)) - (sourceUnfoldrM outer n) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'unfoldManyRoundRobin --- inspect $ 'unfoldManyRoundRobin `hasNoType` ''SPEC --- inspect $ 'unfoldManyRoundRobin `hasNoType` --- ''D.ConcatUnfoldInterleaveState -#endif - -{-# INLINE concatPairsWithWSerial #-} -concatPairsWithWSerial :: Int -> Int -> Int -> IO () -concatPairsWithWSerial = concatPairsWith Internal.wSerial - -{-# INLINE concatPairsWithRoundrobin #-} -concatPairsWithRoundrobin :: Int -> Int -> Int -> IO () -concatPairsWithRoundrobin = concatPairsWith Internal.roundrobin - -{-# INLINE concatMapWithWSerial #-} -concatMapWithWSerial :: Int -> Int -> Int -> IO () -concatMapWithWSerial = concatStreamsWith wSerial - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'concatMapWithWSerial -inspect $ 'concatMapWithWSerial `hasNoType` ''SPEC -#endif - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining (2 of n/2)" - [ benchIOSrc1 "wSerial" (wSerial2 value) - , benchIOSrc1 "interleave" (interleave2 value) - , benchIOSrc1 "roundRobin" (roundRobin2 value) - , benchIOSrc1 - "concatMapWithWSerial" - (concatMapWithWSerial 2 (value `div` 2)) - , benchIOSrc1 - "concatMapWithInterleave" - (concatStreamsWith Internal.interleave 2 (value `div` 2)) - , benchIOSrc1 - "concatMapWithRoundrobin" - (concatStreamsWith Internal.roundrobin 2 (value `div` 2)) - , benchIOSrc1 - "unfoldManyInterleave" - (unfoldManyInterleave 2 (value `div` 2)) - , benchIOSrc1 - "concatPairsWithWSerial" - (concatPairsWithWSerial 2 (value `div` 2)) - , benchIOSrc1 - "concatPairsWithRoundrobin" - (concatPairsWithRoundrobin 2 (value `div` 2)) - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -o_1_space_concat :: Int -> [Benchmark] -o_1_space_concat value = - [ bgroup "concatMapWith" - [ benchIOSrc1 - "concatMapWithWSerial (n of 1)" - (concatStreamsWith wSerial value 1) - , benchIOSrc1 - "concatMapWithWSerial (sqrtVal of sqrtVal)" - (concatStreamsWith wSerial sqrtVal sqrtVal) - ] - ] - - where - - sqrtVal = round $ sqrt (fromIntegral value :: Double) - -o_n_space_concat :: Int -> [Benchmark] -o_n_space_concat value = - [ bgroup "concatMapWith" - [ - -- concatMapWith using StreamD versions of interleave operations are - -- all quadratic, we just measure the sqrtVal benchmark for comparison. - benchIOSrc1 - "concatMapWithInterleave (sqrtVal of 1)" - (concatStreamsWith Internal.interleave sqrtVal 1) - , benchIOSrc1 - "concatMapWithInterleave (sqrtVal of sqrtVal)" - (concatStreamsWith Internal.interleave sqrtVal sqrtVal) - , benchIOSrc1 - "concatMapWithRoundrobin (sqrtVal of sqrtVal)" - (concatStreamsWith Internal.roundrobin sqrtVal sqrtVal) - ] - ] - - where - - sqrtVal = round $ sqrt (fromIntegral value :: Double) - -{-# INLINE concatPairsWithInterleave #-} -concatPairsWithInterleave :: Int -> Int -> Int -> IO () -concatPairsWithInterleave = concatPairsWith Internal.interleave - -{-# INLINE concatPairsWithInterleaveSuffix #-} -concatPairsWithInterleaveSuffix :: Int -> Int -> Int -> IO () -concatPairsWithInterleaveSuffix = concatPairsWith Internal.interleaveSuffix - -{-# INLINE concatPairsWithInterleaveInfix #-} -concatPairsWithInterleaveInfix :: Int -> Int -> Int -> IO () -concatPairsWithInterleaveInfix = concatPairsWith Internal.interleaveInfix - -{-# INLINE concatPairsWithInterleaveMin #-} -concatPairsWithInterleaveMin :: Int -> Int -> Int -> IO () -concatPairsWithInterleaveMin = concatPairsWith Internal.interleaveMin - -o_n_heap_concat :: Int -> [Benchmark] -o_n_heap_concat value = - [ bgroup "concatPairsWith" - [ - benchIOSrc1 - "unfoldManyInterleave (n of 1)" - (unfoldManyInterleave value 1) - , benchIOSrc1 - "unfoldManyInterleave (sqrtVal of sqrtVal)" - (unfoldManyInterleave sqrtVal sqrtVal) - - , benchIOSrc1 - "unfoldManyRoundRobin (n of 1)" - (unfoldManyRoundRobin value 1) - , benchIOSrc1 - "unfoldManyRoundRobin (sqrtVal of sqrtVal)" - (unfoldManyRoundRobin sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithWSerial (n of 1)" - (concatPairsWithWSerial value 1) - , benchIOSrc1 - "concatPairsWithWSerial (sqrtVal of sqrtVal)" - (concatPairsWithWSerial sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithInterleave (n of 1)" - (concatPairsWithInterleave value 1) - , benchIOSrc1 - "concatPairsWithInterleave (sqrtVal of sqrtVal)" - (concatPairsWithInterleave sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithInterleaveSuffix (n of 1)" - (concatPairsWithInterleaveSuffix value 1) - , benchIOSrc1 - "concatPairsWithInterleaveSuffix (sqrtVal of sqrtVal)" - (concatPairsWithInterleaveSuffix sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithInterleaveInfix (n of 1)" - (concatPairsWithInterleaveInfix value 1) - , benchIOSrc1 - "concatPairsWithInterleaveInfix (sqrtVal of sqrtVal)" - (concatPairsWithInterleaveInfix sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithInterleaveMin (n of 1)" - (concatPairsWithInterleaveMin value 1) - , benchIOSrc1 - "concatPairsWithInterleaveMin (sqrtVal of sqrtVal)" - (concatPairsWithInterleaveMin sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithRoundrobin (n of 1)" - (concatPairsWithRoundrobin value 1) - , benchIOSrc1 - "concatPairsWithRoundrobin (sqrtVal of sqrtVal)" - (concatPairsWithRoundrobin sqrtVal sqrtVal) - ] - ] - - where - - sqrtVal = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monad -------------------------------------------------------------------------------- - -o_1_space_outerProduct :: Int -> [Benchmark] -o_1_space_outerProduct value = - [ bgroup "outer-product" - [ benchIO - "drain applicative (+) (sqrtVal of sqrtVal)" - (toNullAp value fromWSerial) - , benchIO - "drain monad (+) (sqrtVal of sqrtVal)" - (toNullM value fromWSerial) - , benchIO - "drain monad (+) (cbrtVal of cbrtVal of cbrtVal)" - (toNullM3 value fromWSerial) - , benchIO - "filterAllOut monad (+) (sqrtVal of sqrtVal)" - (filterAllOutM value fromWSerial) - , benchIO - "filterAllIn monad (+) (sqrtVal of sqrtVal)" - (filterAllInM value fromWSerial) - , benchIO - "filterSome monad (+) (sqrtVal of sqrtVal)" - (filterSome value fromWSerial) - , benchIO - "breakAfterSome monad (+) (sqrtVal of sqrtVal)" - (breakAfterSome value fromWSerial) - ] - ] - -o_n_space_outerProduct :: Int -> [Benchmark] -o_n_space_outerProduct value = - [ bgroup - "outer-product" - [ benchIO - "toList monad (+) (sqrtVal of sqrtVal)" - (toListM value fromWSerial) - , benchIO - "toListSome monad (+) (sqrtVal of sqrtVal)" - (toListSome value fromWSerial) - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - --- In addition to gauge options, the number of elements in the stream can be --- passed using the --stream-size option. --- -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - - where - - allBenchmarks size = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_mapping size - , o_1_space_joining size - , o_1_space_concat size - , o_1_space_outerProduct size - ] - , bgroup (o_n_heap_prefix moduleName) (o_n_heap_concat size) - , bgroup (o_n_space_prefix moduleName) $ - o_n_space_outerProduct size ++ o_n_space_concat size - ] From 95c7782dceac0a06b5617fa45c1dd3c4192d1253 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 19:39:37 +0530 Subject: [PATCH 08/24] Remove Prelude.Merge benchmark --- .../Streamly/Benchmark/Data/Stream/Expand.hs | 85 ++++- benchmark/Streamly/Benchmark/Data/StreamK.hs | 177 +++++++++-- benchmark/Streamly/Benchmark/Prelude/Merge.hs | 298 ------------------ 3 files changed, 223 insertions(+), 337 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/Merge.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index 6ba7591774..55e8df83db 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -98,6 +98,64 @@ inspect $ 'roundRobin2 `hasNoType` ''SPEC inspect $ 'roundRobin2 `hasNoType` ''S.InterleaveState #endif +------------------------------------------------------------------------------- +-- Merging +------------------------------------------------------------------------------- + +{-# INLINE mergeWith #-} +mergeWith :: + ( (Int -> Int -> Ordering) + -> Stream IO Int + -> Stream IO Int + -> Stream IO Int + ) + -> (Int -> Int -> Ordering) + -> Int -> Int -> IO () +mergeWith g cmp count n = + Stream.drain + $ g + cmp + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +{-# INLINE mergeWithM #-} +mergeWithM :: + ( (Int -> Int -> IO Ordering) + -> Stream IO Int + -> Stream IO Int + -> Stream IO Int + ) + -> (Int -> Int -> Ordering) + -> Int -> Int -> IO () +mergeWithM g cmp count n = + Stream.drain + $ g + (\a b -> return $ cmp a b) + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +{-# INLINE mergeBy #-} +mergeBy :: (Int -> Int -> Ordering) -> Int -> Int -> IO () +mergeBy = mergeWith Stream.mergeBy + +{-# INLINE mergeByM #-} +mergeByM :: (Int -> Int -> Ordering) -> Int -> Int -> IO () +mergeByM = mergeWithM Stream.mergeByM + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'mergeBy +inspect $ 'mergeBy `hasNoType` ''SPEC +inspect $ 'mergeBy `hasNoType` ''S.Step + +inspect $ hasNoTypeClasses 'mergeByM +inspect $ 'mergeByM `hasNoType` ''SPEC +inspect $ 'mergeByM `hasNoType` ''S.Step +#endif + +------------------------------------------------------------------------------- +-- joining 2 streams using n-ary ops +------------------------------------------------------------------------------- + {-# INLINE sourceUnfoldrMUF #-} -- unfold input is (count, value) sourceUnfoldrMUF :: Monad m => Int -> UF.Unfold m (Int, Int) Int @@ -141,13 +199,28 @@ inspect $ hasNoTypeClasses 'unfoldSched o_1_space_joining :: Int -> [Benchmark] o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2)) + [ bgroup "joining (2 of n/2)" + [ benchIOSrc1 "serial" (serial2 (value `div` 2)) , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4)) - , benchIOSrc1 "interleave (2,x/2)" (interleave2 (value `div` 2)) - , benchIOSrc1 "roundRobin (2,x/2)" (roundRobin2 (value `div` 2)) - , benchIOSrc1 "bfsUnfoldEach (2,x/2)" (bfsUnfoldEach 2 (value `div` 2)) - , benchIOSrc1 "unfoldSched (2,x/2)" (unfoldSched 2 (value `div` 2)) + , benchIOSrc1 "interleave" (interleave2 (value `div` 2)) + , benchIOSrc1 "roundRobin" (roundRobin2 (value `div` 2)) + , benchIOSrc1 + "mergeBy compare" + (mergeBy compare (value `div` 2)) + , benchIOSrc1 + "mergeByM compare" + (mergeByM compare (value `div` 2)) + , benchIOSrc1 + "mergeBy (flip compare)" + (mergeBy (flip compare) (value `div` 2)) + , benchIOSrc1 + "mergeByM (flip compare)" + (mergeByM (flip compare) (value `div` 2)) + + -- join 2 streams using n-ary ops + , benchIOSrc1 "bfsUnfoldEach" (bfsUnfoldEach 2 (value `div` 2)) + , benchIOSrc1 "unfoldSched" (unfoldSched 2 (value `div` 2)) + , benchIOSrc1 "concatMap" (concatMap 2 (value `div` 2)) ] ] diff --git a/benchmark/Streamly/Benchmark/Data/StreamK.hs b/benchmark/Streamly/Benchmark/Data/StreamK.hs index 99235f662f..891617bc47 100644 --- a/benchmark/Streamly/Benchmark/Data/StreamK.hs +++ b/benchmark/Streamly/Benchmark/Data/StreamK.hs @@ -29,7 +29,7 @@ import Data.Maybe (isJust) import Streamly.Internal.Data.Stream (Stream) import Streamly.Internal.Data.StreamK (StreamK) import System.Random (randomRIO) -import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark) +import Test.Tasty.Bench (bench, nf, nfIO, bgroup, Benchmark) import qualified Data.List as List import qualified Prelude as P @@ -326,12 +326,12 @@ zipWithM :: Monad m => StreamK m Int -> m () zipWithM src = drain $ StreamK.zipWithM (curry return) src src {-# INLINE sortByK #-} -sortByK :: (a -> a -> Ordering) -> StreamK m a -> StreamK m a +sortByK :: (Int -> Int -> Ordering) -> StreamK m Int -> StreamK m Int sortByK f = StreamK.mergeMapWith (StreamK.mergeBy f) StreamK.fromPure {-# INLINE sortBy #-} -sortBy :: Monad m => StreamK m Int -> m () -sortBy = drain . sortByK compare +sortBy :: Monad m => (Int -> Int -> Ordering) -> StreamK m Int -> m () +sortBy f = drain . sortByK f ------------------------------------------------------------------------------- -- Joining @@ -400,6 +400,58 @@ mergeMapWithD op outer inner n = op1 s1 s2 = StreamK.fromStream $ op (StreamK.toStream s1) (StreamK.toStream s2) +------------------------------------------------------------------------------- +-- Merging +------------------------------------------------------------------------------- + +{-# INLINE mergeWith #-} +mergeWith :: + ( (Int -> Int -> Ordering) + -> StreamK IO Int + -> StreamK IO Int + -> StreamK IO Int + ) + -> (Int -> Int -> Ordering) + -> Int -> Int -> IO () +mergeWith g cmp count n = + StreamK.drain + $ g + cmp + (unfoldrM count n) + (unfoldrM count (n + 1)) + +{-# INLINE mergeWithM #-} +mergeWithM :: + ( (Int -> Int -> IO Ordering) + -> StreamK IO Int + -> StreamK IO Int + -> StreamK IO Int + ) + -> (Int -> Int -> Ordering) + -> Int -> Int -> IO () +mergeWithM g cmp count n = + StreamK.drain + $ g + (\a b -> return $ cmp a b) + (unfoldrM count n) + (unfoldrM count (n + 1)) + +{-# INLINE mergeBy #-} +mergeBy :: (Int -> Int -> Ordering) -> Int -> Int -> IO () +mergeBy = mergeWith StreamK.mergeBy + +{-# INLINE mergeByM #-} +mergeByM :: (Int -> Int -> Ordering) -> Int -> Int -> IO () +mergeByM = mergeWithM StreamK.mergeByM + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'mergeBy +inspect $ 'mergeBy `hasNoType` ''SPEC + +inspect $ hasNoTypeClasses 'mergeByM +inspect $ 'mergeByM `hasNoType` ''SPEC +#endif + ------------------------------------------------------------------------------- -- Mixed Composition ------------------------------------------------------------------------------- @@ -811,32 +863,56 @@ o_1_space_transformationX4 streamLen = o_1_space_joining :: Int -> Benchmark o_1_space_joining streamLen = - bgroup "joining" - [ bgroup "(2 of n/2)" - [ benchIOSrc1 "interleave" (interleave2 streamLen) - - -- join 2 streams using concatMapWith - , benchIOSrc1 - "concatMapWith interleave" - (concatMapWith StreamK.interleave 2 (streamLen `div` 2)) - , benchIOSrc1 - "concatMapWith D.interleave" - (concatMapWithD Stream.interleave 2 (streamLen `div` 2)) - , benchIOSrc1 - "concatMapWith D.roundRobin" - (concatMapWithD Stream.roundRobin 2 (streamLen `div` 2)) - - -- join 2 streams using mergeMapWith - , benchIOSrc1 - "mergeMapWith interleave" - (mergeMapWith StreamK.interleave 2 (streamLen `div` 2)) - , benchIOSrc1 - "mergeMapWith D.interleave" - (mergeMapWithD Stream.interleave 2 (streamLen `div` 2)) - , benchIOSrc1 - "mergeMapWith D.roundRobin" - (mergeMapWithD Stream.roundRobin 2 (streamLen `div` 2)) - ] + bgroup "joining (2 of n/2)" + [ benchIOSrc1 "interleave" (interleave2 streamLen) + + , benchIOSrc1 + "mergeBy compare" + (mergeBy compare (streamLen `div` 2)) + , benchIOSrc1 + "mergeByM compare" + (mergeByM compare (streamLen `div` 2)) + , benchIOSrc1 + "mergeBy (flip compare)" + (mergeBy (flip compare) (streamLen `div` 2)) + , benchIOSrc1 + "mergeByM (flip compare)" + (mergeByM (flip compare) (streamLen `div` 2)) + + -- join 2 streams using concatMapWith + , benchIOSrc1 + "concatMapWith interleave" + (concatMapWith StreamK.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "concatMapWith D.interleave" + (concatMapWithD Stream.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "concatMapWith D.roundRobin" + (concatMapWithD Stream.roundRobin 2 (streamLen `div` 2)) + + -- join 2 streams using mergeMapWith + , benchIOSrc1 + "mergeMapWith interleave" + (mergeMapWith StreamK.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWith D.interleave" + (mergeMapWithD Stream.interleave 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWith D.roundRobin" + (mergeMapWithD Stream.roundRobin 2 (streamLen `div` 2)) + + , benchIOSrc1 + "mergeMapWith (mergeBy compare)" + (mergeMapWith (StreamK.mergeBy compare) 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWith (mergeBy (flip compare))" + (mergeMapWith (StreamK.mergeBy (flip compare)) 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWithD (D.mergeBy compare)" + (mergeMapWithD (Stream.mergeBy compare) 2 (streamLen `div` 2)) + , benchIOSrc1 + "mergeMapWithD (D.mergeBy (flip compare))" + (mergeMapWithD (Stream.mergeBy (flip compare)) 2 (streamLen `div` 2)) ] o_1_space_concat :: Int -> Benchmark @@ -916,12 +992,49 @@ o_n_heap_concat streamLen = (mergeMapWithD Stream.interleave streamLen2 streamLen2) , benchIOSrc1 "mergeMapWithD D.roundRobin outer=inner=(sqrt Max)" (mergeMapWithD Stream.roundRobin streamLen2 streamLen2) + + , benchIOSrc1 "mergeMapWith (mergeBy compare) outer=Max inner=1" + (mergeMapWith (StreamK.mergeBy compare) streamLen 1) + , benchIOSrc1 "mergeMapWith (mergeBy compare) outer=inner=(sqrt Max)" + (mergeMapWith (StreamK.mergeBy compare) streamLen2 streamLen2) + , benchIOSrc1 "mergeMapWith (mergeBy compare) outer=1 inner=Max" + (mergeMapWith (StreamK.mergeBy compare) 1 streamLen) + + , benchIOSrc1 "mergeMapWith (mergeBy (flip compare)) outer=Max inner=1" + (mergeMapWith (StreamK.mergeBy (flip compare)) streamLen 1) + , benchIOSrc1 "mergeMapWith (mergeBy (flip compare)) outer=inner=(sqrt Max)" + (mergeMapWith (StreamK.mergeBy (flip compare)) streamLen2 streamLen2) + , benchIOSrc1 "mergeMapWith (mergeBy (flip compare)) outer=1 inner=Max" + (mergeMapWith (StreamK.mergeBy (flip compare)) 1 streamLen) ] where streamLen2 = round (P.fromIntegral streamLen**(1/2::P.Double)) -- double nested loop +o_n_heap_sorting :: Int -> Benchmark +o_n_heap_sorting streamLen = + bgroup "sorting" + [ benchFold "sortBy compare" + (sortBy compare) + (unfoldrM streamLen) + , benchFold "sortBy (flip compare)" + (sortBy (flip compare)) + (unfoldrM streamLen) + , benchFold "sortBy compare randomized" + (sortBy compare . fmap (\x -> if even x then x + 2 else x)) + (unfoldrM streamLen) + , bench "List.sortBy compare" + $ nf (\x -> List.sortBy compare [1..x]) streamLen + , bench "List.sortBy (flip compare)" + $ nf (\x -> List.sortBy (flip compare) [1..x]) streamLen + , bench "sortByLists compare randomized" + $ nf (\x -> List.sortBy compare + (List.map (\n -> if even n then n + 2 else n) [1..x]) + ) + streamLen + ] + o_1_space_filtering :: Int -> Benchmark o_1_space_filtering streamLen = bgroup "filtering" @@ -1055,10 +1168,8 @@ o_n_heap streamLen = [ bgroup "transformation" [ benchFold "foldlS" (foldlS 1) (unfoldrM streamLen) ] - , bgroup "concat" - [ benchFold "sortBy" sortBy (unfoldrM streamLen) - ] , o_n_heap_concat streamLen + , o_n_heap_sorting streamLen ] {-# INLINE benchK #-} diff --git a/benchmark/Streamly/Benchmark/Prelude/Merge.hs b/benchmark/Streamly/Benchmark/Prelude/Merge.hs deleted file mode 100644 index 42c8f01702..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/Merge.hs +++ /dev/null @@ -1,298 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RankNTypes #-} - -#ifdef __HADDOCK_VERSION__ -#undef INSPECTION -#endif - -#ifdef INSPECTION -{-# LANGUAGE TemplateHaskell #-} -{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-} -#endif - -import Streamly.Internal.Data.Stream.IsStream (SerialT) -import qualified Data.List as List -import qualified Streamly.Internal.Data.Stream.IsStream as Stream --- import qualified Streamly.Internal.Data.Unfold as Unfold - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -#ifdef INSPECTION -import GHC.Types (SPEC(..)) -import Test.Inspection - -import qualified Streamly.Internal.Data.Stream as D -#endif - -moduleName :: String -moduleName = "Prelude.Merge" - -------------------------------------------------------------------------------- --- Merging -------------------------------------------------------------------------------- - -{-# INLINE mergeWith #-} -mergeWith :: - ( (Int -> Int -> Ordering) - -> SerialT IO Int - -> SerialT IO Int - -> SerialT IO Int - ) - -> (Int -> Int -> Ordering) - -> Int -> Int -> IO () -mergeWith g cmp count n = - Stream.drain - $ g - cmp - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -{-# INLINE mergeWithM #-} -mergeWithM :: - ( (Int -> Int -> IO Ordering) - -> SerialT IO Int - -> SerialT IO Int - -> SerialT IO Int - ) - -> (Int -> Int -> Ordering) - -> Int -> Int -> IO () -mergeWithM g cmp count n = - Stream.drain - $ g - (\a b -> return $ cmp a b) - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -{-# INLINE mergeBy #-} -mergeBy :: (Int -> Int -> Ordering) -> Int -> Int -> IO () -mergeBy = mergeWith Stream.mergeBy - -{-# INLINE mergeByM #-} -mergeByM :: (Int -> Int -> Ordering) -> Int -> Int -> IO () -mergeByM = mergeWithM Stream.mergeByM - -{-# INLINE mergeByMFused #-} -mergeByMFused :: (Int -> Int -> Ordering) -> Int -> Int -> IO () -mergeByMFused = mergeWithM Stream.mergeByMFused - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'mergeBy -inspect $ 'mergeBy `hasNoType` ''SPEC -inspect $ 'mergeBy `hasNoType` ''D.Step - -inspect $ hasNoTypeClasses 'mergeByM -inspect $ 'mergeByM `hasNoType` ''SPEC -inspect $ 'mergeByM `hasNoType` ''D.Step - -{-# INLINE _mergeByMFusedCheck #-} -_mergeByMFusedCheck :: IO () -_mergeByMFusedCheck = mergeWithM Stream.mergeByMFused compare 0 0 - -inspect $ hasNoTypeClasses '_mergeByMFusedCheck -inspect $ '_mergeByMFusedCheck `hasNoType` ''SPEC -inspect $ '_mergeByMFusedCheck `hasNoType` ''D.Step -#endif - -{-# INLINE concatPairsWithMergeBy #-} -concatPairsWithMergeBy :: (Int -> Int -> Ordering) -> Int -> Int -> Int -> IO () -concatPairsWithMergeBy cmp = concatPairsWith (Stream.mergeBy cmp) - -{-# INLINE concatPairsWithMergeByFused #-} -concatPairsWithMergeByFused :: - (Int -> Int -> Ordering) -> Int -> Int -> Int -> IO () -concatPairsWithMergeByFused cmp = - concatPairsWith (Stream.mergeByMFused (\x y -> return $ cmp x y)) - -------------------------------------------------------------------------------- --- Interleaving -------------------------------------------------------------------------------- - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining (2 of n/2)" - [ benchIOSrc1 - "mergeBy compare" - (mergeBy compare (value `div` 2)) - , benchIOSrc1 - "mergeByM compare" - (mergeByM compare (value `div` 2)) - , benchIOSrc1 - "mergeByMFused compare" - (mergeByMFused compare (value `div` 2)) - - , benchIOSrc1 - "mergeBy (flip compare)" - (mergeBy (flip compare) (value `div` 2)) - , benchIOSrc1 - "mergeByM (flip compare)" - (mergeByM (flip compare) (value `div` 2)) - , benchIOSrc1 - "mergeByMFused (flip compare)" - (mergeByMFused (flip compare) (value `div` 2)) - - , benchIOSrc1 - "concatPairsWithMergeBy compare" - (concatPairsWithMergeBy compare 2 (value `div` 2)) - , benchIOSrc1 - "concatPairsWithMergeBy (flip compare)" - (concatPairsWithMergeBy (flip compare) 2 (value `div` 2)) - - , benchIOSrc1 - "concatPairsWithMergeByFused compare" - (concatPairsWithMergeByFused compare 2 (value `div` 2)) - , benchIOSrc1 - "concatPairsWithMergeByFused (flip compare)" - (concatPairsWithMergeByFused (flip compare) 2 (value `div` 2)) - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -{- -{-# INLINE sourceUnfoldrMUF #-} --- (count, value) -sourceUnfoldrMUF :: Monad m => Int -> UF.Unfold m (Int, Int) Int -sourceUnfoldrMUF count = UF.unfoldrM step - where - step (cnt, start) = - return $ - if cnt > start + count - then Nothing - else Just (cnt, (cnt + 1, start)) - -{-# INLINE unfoldManyMergeBy #-} -unfoldManyMergeBy :: Int -> Int -> Int -> IO () -unfoldManyMergeBy outer inner n = - S.drain $ (Internal.unfoldManyMergeBy compare) - -- (UF.lmap return (UF.replicateM inner)) - (UF.lmap (\x -> (x,x)) (sourceUnfoldrMUF inner)) - (sourceUnfoldrM outer n) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'unfoldManyMergeBy --- inspect $ 'unfoldManyMergeBy `hasNoType` ''SPEC --- inspect $ 'unfoldManyMergeBy `hasNoType` --- ''D.ConcatUnfoldMergeState -#endif --} - -{-# INLINE sortBy #-} -sortBy :: (Int -> Int -> Ordering) -> SerialT IO Int -> IO () -sortBy cmp = Stream.drain . Stream.sortBy cmp - -{- --- For fair comparison with concatPairs, removed sorted segmentation -{-# INLINE listSortBy #-} -listSortBy :: (a -> a -> Ordering) -> [a] -> [a] -listSortBy cmp = mergeAll . sequences - where - sequences = fmap (: []) - - mergeAll [x] = x - mergeAll xs = mergeAll (mergePairs xs) - - mergePairs (a:b:xs) = let !x = merge a b - in x : mergePairs xs - mergePairs xs = xs - - merge as@(a:as') bs@(b:bs') - | a `cmp` b == GT = b:merge as bs' - | otherwise = a:merge as' bs - merge [] bs = bs - merge as [] = as --} - -o_n_heap_concat :: Int -> [Benchmark] -o_n_heap_concat value = - [ bgroup "concatPairsWith" - [ benchIOSrc1 - "concatPairsWithMergeBy compare (n of 1)" - (concatPairsWithMergeBy compare value 1) - , benchIOSrc1 - "concatPairsWithMergeBy compare (sqrtVal of sqrtVal)" - (concatPairsWithMergeBy compare sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithMergeBy (flip compare) (n of 1)" - (concatPairsWithMergeBy (flip compare) value 1) - , benchIOSrc1 - "concatPairsWithMergeBy (flip compare) (sqrtVal of sqrtVal)" - (concatPairsWithMergeBy (flip compare) sqrtVal sqrtVal) - - , benchIOSrc1 - "concatPairsWithMergeByFused compare (n of 1)" - (concatPairsWithMergeByFused compare value 1) - , benchIOSrc1 - "concatPairsWithMergeByFused compare (sqrtVal of sqrtVal)" - (concatPairsWithMergeByFused compare sqrtVal sqrtVal) - ] - -- TODO: change sourceUnfoldrM to generate alternating bigger and lower - -- numbers to simulate a random input for a worst case sort benchmark. We - -- can use 0 and value as two ints in the state and alternate each in the - -- output streams, incrementing the lower number of decrementing the higher - -- number. - , bgroup "sorting" - [ benchIOSink value "sortBy compare" (sortBy compare) - , benchIOSink value "sortBy (flip compare)" (sortBy (flip compare)) - , benchIOSink value "sortBy compare randomized" - (sortBy compare . Stream.map (\x -> if even x then x + 2 else x)) - {- - , bench "sortByLists compare" - $ nf (\x -> listSortBy compare [1..x]) value - , bench "sortByLists (flip compare)" - $ nf (\x -> listSortBy (flip compare) [1..x]) value - , bench "sortByLists compare randomized" - $ nf (\x -> listSortBy compare - (map (\n -> if even n then n + 2 else n) [1..x]) - ) - value - -} - , bench "sortByLists compare" - $ nf (\x -> List.sortBy compare [1..x]) value - , bench "sortByLists (flip compare)" - $ nf (\x -> List.sortBy (flip compare) [1..x]) value - , bench "sortByLists compare randomized" - $ nf (\x -> List.sortBy compare - (map (\n -> if even n then n + 2 else n) [1..x]) - ) - value - ] - ] - - where - - sqrtVal = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - --- In addition to gauge options, the number of elements in the stream can be --- passed using the --stream-size option. --- -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks size = - [ bgroup (o_1_space_prefix moduleName) (o_1_space_joining size) - , bgroup (o_n_heap_prefix moduleName) (o_n_heap_concat size) - ] From 082bc579dfa3711c7abca5993186e7af67a3fe20 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 22:29:02 +0530 Subject: [PATCH 09/24] Remove Prelude.ZipAsync benchmark --- .../Benchmark/Data/Stream/ConcurrentCommon.hs | 65 ++++++++++--- .../Streamly/Benchmark/Prelude/ZipAsync.hs | 97 ------------------- 2 files changed, 53 insertions(+), 109 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/ZipAsync.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs index 4d7e3f5e54..c41867e06f 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs @@ -1,4 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE UndecidableInstances #-} + -- | -- Module : Main -- Copyright : (c) 2018 Composewell Technologies @@ -21,10 +24,12 @@ import qualified Streamly.Data.Fold as Fold import qualified Streamly.Data.Fold.Prelude as Fold import qualified Streamly.Data.Stream as Stream import qualified Streamly.Internal.Data.Stream.Prelude as Async +import qualified Streamly.Internal.Data.Stream.Prelude as Stream import Test.Tasty.Bench import Prelude hiding (mapM) import Streamly.Benchmark.Common +import Streamly.Data.Stream.MkType -- XXX Write inspection tests to make sure no dictionaries are being passed -- around to find specialization issues. Could be really bad for perf. @@ -100,6 +105,24 @@ parMergeBy f count n = (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1)) +{-# INLINE parZipWithM #-} +parZipWithM :: (Config -> Config) -> Int -> Int -> IO () +parZipWithM f count n = + Stream.fold Fold.drain + $ Async.parZipWithM f + (curry return) + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + +{-# INLINE parZipWith #-} +parZipWith :: (Config -> Config) -> Int -> Int -> IO () +parZipWith f count n = + Stream.fold Fold.drain + $ Async.parZipWith f + (,) + (sourceUnfoldrM count n) + (sourceUnfoldrM count (n + 1)) + {-# INLINE parTap #-} parTap :: (Fold.Config -> Fold.Config) -> Int -> Int -> IO () parTap f count n = @@ -108,14 +131,16 @@ parTap f count n = o_1_space_joining :: Int -> (Config -> Config) -> [Benchmark] o_1_space_joining value f = - [ bgroup "joining" - [ benchIOSrc1 "async (2 of n/2)" (async2 f (value `div` 2)) - , benchIOSrc1 "concat async (2 of n/2)" (concatAsync2 f (value `div` 2)) - , benchIOSrc1 "parMergeByM (2 of n/2)" (parMergeByM f (value `div` 2)) - , benchIOSrc1 "parMergeBy (2 of n/2)" (parMergeBy f (value `div` 2)) - -- XXX use configurable modifier, put this in concurrent fold benchmarks - , benchIOSrc1 "parTap" (parTap id value) + [ bgroup "joining (2 of n/2)" + [ benchIOSrc1 "parTwo" (async2 f (value `div` 2)) + , benchIOSrc1 "parConcat" (concatAsync2 f (value `div` 2)) + , benchIOSrc1 "parMergeByM" (parMergeByM f (value `div` 2)) + , benchIOSrc1 "parMergeBy" (parMergeBy f (value `div` 2)) + , benchIOSrc1 "parZipWithM" (parZipWithM f (value `div` 2)) + , benchIOSrc1 "parZipWith" (parZipWith f (value `div` 2)) ] + -- XXX use configurable modifier, put this in concurrent fold benchmarks + , benchIOSrc1 "tap (Fold.parBuffered id Fold.sum)" (parTap id value) ] ------------------------------------------------------------------------------- @@ -201,9 +226,9 @@ o_1_space_concatMap label value f = -- Monadic outer product ------------------------------------------------------------------------------- -{-# INLINE toNullAp #-} -toNullAp :: (Config -> Config) -> Int -> Int -> IO () -toNullAp f linearCount start = +{-# INLINE drainApply #-} +drainApply :: (Config -> Config) -> Int -> Int -> IO () +drainApply f linearCount start = Stream.fold Fold.drain $ Async.parCrossApply f (fmap (+) (sourceUnfoldrM nestedCount2 start)) @@ -213,10 +238,26 @@ toNullAp f linearCount start = nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) +-- XXX Move to a Zip specific module so that it is not added to all concurrent +-- stream types. +parCrossApply :: MonadAsync m => Stream m (a -> b) -> Stream m a -> Stream m b +parCrossApply = Stream.parCrossApply id + +$(mkZipType "ParZip" "parCrossApply" True) + +{-# INLINE zipApplicative #-} +zipApplicative + :: MonadAsync m => Int -> Int -> m () +zipApplicative count start = + Stream.fold Fold.drain $ unParZip $ + (+) <$> mkParZip (sourceUnfoldrM count start) + <*> mkParZip (sourceUnfoldrM count (start + 1)) + o_1_space_outerProduct :: Int -> (Config -> Config) -> [Benchmark] o_1_space_outerProduct value f = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp f value + [ bgroup "outer-product" + [ benchIO "parCrossApply" $ drainApply f value + , benchIO "ZipApplicative" $ zipApplicative value ] ] diff --git a/benchmark/Streamly/Benchmark/Prelude/ZipAsync.hs b/benchmark/Streamly/Benchmark/Prelude/ZipAsync.hs deleted file mode 100644 index 6567b8ec98..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/ZipAsync.hs +++ /dev/null @@ -1,97 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -{-# LANGUAGE FlexibleContexts #-} - -import Streamly.Prelude (fromSerial) -import qualified Streamly.Prelude as S - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude - -import Test.Tasty.Bench - -moduleName :: String -moduleName = "Prelude.ZipAsync" - -------------------------------------------------------------------------------- --- Zipping -------------------------------------------------------------------------------- - -{-# INLINE zipAsyncWith #-} -zipAsyncWith :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int) -zipAsyncWith count n = - S.zipAsyncWith (,) (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1)) - -{-# INLINE zipAsyncWithM #-} -zipAsyncWithM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int) -zipAsyncWithM count n = - S.zipAsyncWithM - (curry return) - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -{-# INLINE zipAsyncAp #-} -zipAsyncAp :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m (Int, Int) -zipAsyncAp count n = - S.fromZipAsync $ - (,) <$> sourceUnfoldrM count n <*> sourceUnfoldrM count (n + 1) - -fromZipAsyncTraverse :: String -> Int -> Benchmark -fromZipAsyncTraverse name count = - bench name - $ nfIO - $ S.drain $ S.fromZipAsync $ traverse S.fromPure [0 :: Int .. count] - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc fromSerial "zipAsyncWith (2,x/2)" (zipAsyncWith - (value `div` 2)) - , benchIOSrc fromSerial "zipAsyncWithM (2,x/2)" (zipAsyncWithM - (value `div` 2)) - , benchIOSrc fromSerial "zipAsyncAp (2,x/2)" (zipAsyncAp (value `div` 2)) - , benchIOSink value "fmap zipAsyncly" $ fmapN S.fromZipAsync 1 - ] - ] - -o_n_heap_joining :: Int -> [Benchmark] -o_n_heap_joining value = - [ bgroup "joining" - [ fromZipAsyncTraverse "ZipAsync Applicative (x/100)" (value `div` 100) - ] - ] - -------------------------------------------------------------------------------- --- Monad outer product -------------------------------------------------------------------------------- - -o_1_space_outerProduct :: Int -> [Benchmark] -o_1_space_outerProduct value = - [ bgroup "monad-outer-product" - [ benchIO "toNullAp" $ toNullAp value S.fromZipAsync - ] - ] - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks size = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_joining size - , o_1_space_outerProduct size - ] - , bgroup (o_n_heap_prefix moduleName) $ o_n_heap_joining size - ] From 1fe2d753a37bba151aca6629d9e615228bf43085 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 23:16:41 +0530 Subject: [PATCH 10/24] Remove Prelude.ZipSerial benchmark --- .../Streamly/Benchmark/Data/Stream/Expand.hs | 29 ++- benchmark/Streamly/Benchmark/Data/StreamK.hs | 30 ++- .../Streamly/Benchmark/Prelude/ZipSerial.hs | 187 ------------------ 3 files changed, 50 insertions(+), 196 deletions(-) delete mode 100644 benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index 55e8df83db..fc07a4370e 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -40,7 +40,7 @@ import qualified Streamly.Internal.Data.StreamK as StreamK import Test.Tasty.Bench import Stream.Common import Streamly.Benchmark.Common -import Prelude hiding (concatMap) +import Prelude hiding (concatMap, zipWith) ------------------------------------------------------------------------------- -- Multi-Stream @@ -152,6 +152,30 @@ inspect $ 'mergeByM `hasNoType` ''SPEC inspect $ 'mergeByM `hasNoType` ''S.Step #endif +------------------------------------------------------------------------------- +-- Zipping +------------------------------------------------------------------------------- + +{-# INLINE zipWith #-} +zipWith :: Monad m => Stream m Int -> m () +zipWith src = drain $ S.zipWith (,) src src + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'zipWith +inspect $ 'zipWith `hasNoType` ''SPEC +inspect $ 'zipWith `hasNoType` ''S.Step +#endif + +{-# INLINE zipWithM #-} +zipWithM :: Monad m => Stream m Int -> m () +zipWithM src = drain $ S.zipWithM (curry return) src src + +#ifdef INSPECTION +inspect $ hasNoTypeClasses 'zipWithM +inspect $ 'zipWithM `hasNoType` ''SPEC +inspect $ 'zipWithM `hasNoType` ''S.Step +#endif + ------------------------------------------------------------------------------- -- joining 2 streams using n-ary ops ------------------------------------------------------------------------------- @@ -217,6 +241,9 @@ o_1_space_joining value = "mergeByM (flip compare)" (mergeByM (flip compare) (value `div` 2)) + , benchFold "zipWith" zipWith (sourceUnfoldrM value) + , benchFold "zipWithM" zipWithM (sourceUnfoldrM value) + -- join 2 streams using n-ary ops , benchIOSrc1 "bfsUnfoldEach" (bfsUnfoldEach 2 (value `div` 2)) , benchIOSrc1 "unfoldSched" (unfoldSched 2 (value `div` 2)) diff --git a/benchmark/Streamly/Benchmark/Data/StreamK.hs b/benchmark/Streamly/Benchmark/Data/StreamK.hs index 891617bc47..09fa1a8176 100644 --- a/benchmark/Streamly/Benchmark/Data/StreamK.hs +++ b/benchmark/Streamly/Benchmark/Data/StreamK.hs @@ -325,6 +325,10 @@ zipWith src = drain $ StreamK.zipWith (,) src src zipWithM :: Monad m => StreamK m Int -> m () zipWithM src = drain $ StreamK.zipWithM (curry return) src src +------------------------------------------------------------------------------- +-- Sorting +------------------------------------------------------------------------------- + {-# INLINE sortByK #-} sortByK :: (Int -> Int -> Ordering) -> StreamK m Int -> StreamK m Int sortByK f = StreamK.mergeMapWith (StreamK.mergeBy f) StreamK.fromPure @@ -879,6 +883,9 @@ o_1_space_joining streamLen = "mergeByM (flip compare)" (mergeByM (flip compare) (streamLen `div` 2)) + , benchFold "zipWith" zipWith (unfoldrM streamLen) + , benchFold "zipWithM" zipWithM (unfoldrM streamLen) + -- join 2 streams using concatMapWith , benchIOSrc1 "concatMapWith interleave" @@ -913,6 +920,9 @@ o_1_space_joining streamLen = , benchIOSrc1 "mergeMapWithD (D.mergeBy (flip compare))" (mergeMapWithD (Stream.mergeBy (flip compare)) 2 (streamLen `div` 2)) + + , benchIOSrc1 "mergeMapWith (zipWith (+))" + (mergeMapWith (StreamK.zipWith (+)) 2 (streamLen `div` 2)) ] o_1_space_concat :: Int -> Benchmark @@ -1006,6 +1016,18 @@ o_n_heap_concat streamLen = (mergeMapWith (StreamK.mergeBy (flip compare)) streamLen2 streamLen2) , benchIOSrc1 "mergeMapWith (mergeBy (flip compare)) outer=1 inner=Max" (mergeMapWith (StreamK.mergeBy (flip compare)) 1 streamLen) + + {- -- This fails with stack overflow. + benchIOSrc1 "concatMapWithZip (n of 1)" + (concatMapWithZip value 1) + -- Not correct because of nil stream at end issue. + , benchIOSrc1 "concatMapWithZip (sqrtVal of sqrtVal)" + (concatMapWithZip sqrtVal sqrtVal) + -} + , benchIOSrc1 "mergeMapWith (zipWith (+)) outer=Max inner=1" + (mergeMapWith (StreamK.zipWith (+)) streamLen 1) + , benchIOSrc1 "mergeMapWith (zipWith (+)) outer=inner=(sqrt Max)" + (mergeMapWith (StreamK.zipWith (+)) streamLen2 streamLen2) ] where @@ -1063,13 +1085,6 @@ o_1_space_filteringX4 streamLen = , benchFold "dropWhile-false" (dropWhileFalse 4) (unfoldrM streamLen) ] -o_1_space_zipping :: Int -> Benchmark -o_1_space_zipping streamLen = - bgroup "zipping" - [ benchFold "zipWith" zipWith (unfoldrM streamLen) - , benchFold "zipWithM" zipWithM (unfoldrM streamLen) - ] - o_1_space_mixed :: Int -> Benchmark o_1_space_mixed streamLen = bgroup "mixed" @@ -1154,7 +1169,6 @@ o_1_space streamLen = , o_1_space_concat streamLen , o_1_space_filtering streamLen , o_1_space_filteringX4 streamLen - , o_1_space_zipping streamLen , o_1_space_joining streamLen , o_1_space_mixed streamLen , o_1_space_mixedX2 streamLen diff --git a/benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs b/benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs deleted file mode 100644 index f17dcca3ca..0000000000 --- a/benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs +++ /dev/null @@ -1,187 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | --- Module : Main --- Copyright : (c) 2018 Composewell Technologies --- --- License : BSD3 --- Maintainer : streamly@composewell.com - -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RankNTypes #-} - -#ifdef __HADDOCK_VERSION__ -#undef INSPECTION -#endif - -#ifdef INSPECTION -{-# LANGUAGE TemplateHaskell #-} -{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-} -#endif - -import Prelude hiding (zipWith) - -import Streamly.Prelude (MonadAsync) -import qualified Streamly.Prelude as S - -import Streamly.Benchmark.Common -import Streamly.Benchmark.Prelude hiding (sourceUnfoldrM) - -import Test.Tasty.Bench - -#ifdef INSPECTION -import GHC.Types (SPEC(..)) -import Test.Inspection - -import qualified Streamly.Internal.Data.Stream as D -#endif - -moduleName :: String -moduleName = "Prelude.ZipSerial" - -------------------------------------------------------------------------------- --- Zipping -------------------------------------------------------------------------------- - --- XXX somehow copying this definition here instead of importing it performs --- better. Need to investigate why. -{-# INLINE sourceUnfoldrM #-} -sourceUnfoldrM :: (S.IsStream t, MonadAsync m) => Int -> Int -> t m Int -sourceUnfoldrM count start = S.unfoldrM step start - where - step cnt = - if cnt > start + count - then return Nothing - else return (Just (cnt, cnt + 1)) - -{-# INLINE zipWith #-} -zipWith :: Int -> Int -> IO () -zipWith count n = - S.drain $ - S.zipWith - (,) - (S.fromSerial $ sourceUnfoldrM count n) - (S.fromSerial $ sourceUnfoldrM count (n + 1)) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'zipWith -inspect $ 'zipWith `hasNoType` ''SPEC -inspect $ 'zipWith `hasNoType` ''D.Step -#endif - -{-# INLINE zipWithM #-} -zipWithM :: Int -> Int -> IO () -zipWithM count n = - S.drain $ - S.zipWithM - (curry return) - (sourceUnfoldrM count n) - (sourceUnfoldrM count (n + 1)) - -#ifdef INSPECTION -inspect $ hasNoTypeClasses 'zipWithM -inspect $ 'zipWithM `hasNoType` ''SPEC -inspect $ 'zipWithM `hasNoType` ''D.Step -#endif - -{- -{-# INLINE concatMapWithZip #-} -concatMapWithZip :: Int -> Int -> Int -> IO () -concatMapWithZip = concatStreamsWith (S.zipWith (+)) --} - -{-# INLINE concatPairsWithZip #-} -concatPairsWithZip :: Int -> Int -> Int -> IO () -concatPairsWithZip = concatPairsWith (S.zipWith (+)) - -o_1_space_joining :: Int -> [Benchmark] -o_1_space_joining value = - [ bgroup "joining" - [ benchIOSrc1 "zip (2 of n/2)" (zipWith (value `div` 2)) - , benchIOSrc1 "zipM (2 of n/2)" (zipWithM (value `div` 2)) - {- - -- Not correct because of nil stream at end issue. - , benchIOSrc1 "concatMapWithZip (+) (2 of n/2)" - (concatMapWithZip 2 (value `div` 2)) - -} - ] - ] - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -o_1_space_mapping :: Int -> [Benchmark] -o_1_space_mapping value = - [ bgroup "mapping" - [ benchIOSink value "fmap" $ fmapN S.fromZipSerial 1 - ] - ] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -o_n_heap_concat :: Int -> [Benchmark] -o_n_heap_concat value = - [ bgroup "concatPairsWith" - [ {- -- This fails with stack overflow. - benchIOSrc1 "concatMapWithZip (n of 1)" - (concatMapWithZip value 1) - -- Not correct because of nil stream at end issue. - , benchIOSrc1 "concatMapWithZip (sqrtVal of sqrtVal)" - (concatMapWithZip sqrtVal sqrtVal) - -} - benchIOSrc1 "concatPairsWithZip (n of 1)" - (concatPairsWithZip value 1) - , benchIOSrc1 "concatPairsWithZip (sqrtVal of sqrtVal)" - (concatPairsWithZip sqrtVal sqrtVal) - , benchIOSrc1 "concatPairsWithZip (+) (2 of n/2)" - (concatPairsWithZip 2 (value `div` 2)) - ] - ] - - where - - sqrtVal = round $ sqrt (fromIntegral value :: Double) - -------------------------------------------------------------------------------- --- Monad outer product -------------------------------------------------------------------------------- - -{- --- Not correct because of nil stream at end issue. -o_1_space_outerProduct :: Int -> [Benchmark] -o_1_space_outerProduct value = - [ bgroup "monad-outer-product" - -- XXX needs fixing - [ benchIO "toNullAp" $ toNullAp value S.zipSerially - ] - ] --} - -------------------------------------------------------------------------------- --- Main -------------------------------------------------------------------------------- - --- In addition to gauge options, the number of elements in the stream can be --- passed using the --stream-size option. --- -main :: IO () -main = runWithCLIOpts defaultStreamSize allBenchmarks - - where - - allBenchmarks size = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_joining size - , o_1_space_mapping size - -- XXX need to fix, timing in ns - -- , o_1_space_outerProduct size - ] - , bgroup (o_n_heap_prefix moduleName) $ concat - [ o_n_heap_concat size - ] - ] From 167fa172dc1613660137b275389742a4f0ae5fff Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sat, 29 Nov 2025 15:05:41 +0530 Subject: [PATCH 11/24] Add monadic benchmarks for concurrent streams --- .../Benchmark/Data/Stream/Concurrent.hs | 12 +- .../Benchmark/Data/Stream/ConcurrentCommon.hs | 236 +++++++++++++++--- .../Benchmark/Data/Stream/ConcurrentEager.hs | 11 +- .../Data/Stream/ConcurrentInterleaved.hs | 11 +- .../Data/Stream/ConcurrentOrdered.hs | 11 +- 5 files changed, 223 insertions(+), 58 deletions(-) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs b/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs index 456714c682..8e5a20f540 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs @@ -1,12 +1,11 @@ -{-# LANGUAGE FlexibleContexts #-} --- | +-- -- Module : Main -- Copyright : (c) 2018 Composewell Technologies -- -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon (allBenchmarks) +import Stream.ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) moduleName :: String @@ -17,4 +16,9 @@ moduleName = "Data.Stream.Concurrent" ------------------------------------------------------------------------------- main :: IO () -main = runWithCLIOpts defaultStreamSize (allBenchmarks moduleName False id) +main = + runWithCLIOpts + defaultStreamSize + (allBenchmarks + mkParallel + unParallel moduleName False id) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs index c41867e06f..16c496d578 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs @@ -11,6 +11,14 @@ module Stream.ConcurrentCommon ( allBenchmarks + , mkParallel + , unParallel + , mkFairParallel + , unFairParallel + , mkEagerParallel + , unEagerParallel + , mkOrderedParallel + , unOrderedParallel ) where @@ -58,12 +66,12 @@ o_1_space_mapping value f = -- Size conserving transformations (reordering, buffering, etc.) ------------------------------------------------------------------------------- -o_n_heap_buffering :: Int -> (Config -> Config) -> [Benchmark] -o_n_heap_buffering value f = +o_n_heap_benchmarks :: Int -> (Config -> Config) -> [Benchmark] +o_n_heap_benchmarks value f = [ bgroup "buffered" - [ benchIOSink value "mkAsync" + [ benchIOSink value "parBuffered" (Stream.fold Fold.drain . Async.parBuffered f) - , benchIOSink value "fmap" + , benchIOSink value "fmap parBuffered" (Stream.fold Fold.drain . fmap (+1) . Async.parBuffered f) ] ] @@ -123,6 +131,18 @@ parZipWith f count n = (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1)) +parZipApply :: MonadAsync m => Stream m (a -> b) -> Stream m a -> Stream m b +parZipApply = Stream.parZipWith id id + +$(mkZipType "ParZip" "parZipApply" True) + +{-# INLINE zipApplicative #-} +zipApplicative :: Int -> Int -> IO () +zipApplicative count start = + Stream.fold Fold.drain $ unParZip $ + (+) <$> mkParZip (sourceUnfoldrM count start) + <*> mkParZip (sourceUnfoldrM count (start + 1)) + {-# INLINE parTap #-} parTap :: (Fold.Config -> Fold.Config) -> Int -> Int -> IO () parTap f count n = @@ -138,6 +158,7 @@ o_1_space_joining value f = , benchIOSrc1 "parMergeBy" (parMergeBy f (value `div` 2)) , benchIOSrc1 "parZipWithM" (parZipWithM f (value `div` 2)) , benchIOSrc1 "parZipWith" (parZipWith f (value `div` 2)) + , benchIO "parZipApplicative" $ zipApplicative value ] -- XXX use configurable modifier, put this in concurrent fold benchmarks , benchIOSrc1 "tap (Fold.parBuffered id Fold.sum)" (parTap id value) @@ -209,7 +230,7 @@ o_1_space_concatMap label value f = [ bgroup ("concat" ++ label) [ benchIO "parConcatMap (n of 1)" (concatMapStreamsWith f value 1) - , benchIO "parConcatMap (sqrt x of sqrt x)" + , benchIO "parConcatMap (sqrt n of sqrt n)" (concatMapStreamsWith f value2 value2) , benchIO "parConcatMap (1 of n)" (concatMapStreamsWith f 1 value) @@ -222,13 +243,25 @@ o_1_space_concatMap label value f = value2 = round $ sqrt (fromIntegral value :: Double) +o_1_space_benchmarks :: Int -> (Config -> Config) -> [Benchmark] +o_1_space_benchmarks value modifier = + concat + [ o_1_space_mapping value modifier + , o_1_space_joining value modifier + , o_1_space_concatFoldable value modifier + , o_1_space_concatMap "" value modifier + , o_1_space_concatMap "-maxThreads-1" value (modifier . Async.maxThreads 1) + , o_1_space_concatMap "-maxBuffer-1 1/10" (value `div` 10) (modifier . Async.maxBuffer 1) + , o_1_space_concatMap "-rate-Nothing" value (modifier . Async.rate Nothing) + ] + ------------------------------------------------------------------------------- --- Monadic outer product +-- Apply ------------------------------------------------------------------------------- -{-# INLINE drainApply #-} -drainApply :: (Config -> Config) -> Int -> Int -> IO () -drainApply f linearCount start = +{-# INLINE parCrossApply #-} +parCrossApply :: (Config -> Config) -> Int -> Int -> IO () +parCrossApply f linearCount start = Stream.fold Fold.drain $ Async.parCrossApply f (fmap (+) (sourceUnfoldrM nestedCount2 start)) @@ -238,26 +271,155 @@ drainApply f linearCount start = nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) --- XXX Move to a Zip specific module so that it is not added to all concurrent --- stream types. -parCrossApply :: MonadAsync m => Stream m (a -> b) -> Stream m a -> Stream m b -parCrossApply = Stream.parCrossApply id +------------------------------------------------------------------------------- +-- Monad Types +------------------------------------------------------------------------------- + +parallelBind :: MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b +parallelBind = flip (Stream.parConcatMap id) +$(mkCrossType "Parallel" "parallelBind" True) + +fairParallelBind :: MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b +fairParallelBind = flip (Stream.parConcatMap (Stream.interleaved True)) +$(mkCrossType "FairParallel" "fairParallelBind" True) + +eagerParallelBind :: MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b +eagerParallelBind = flip (Stream.parConcatMap (Stream.eager True)) +$(mkCrossType "EagerParallel" "eagerParallelBind" True) + +orderedBind :: MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b +orderedBind = flip (Stream.parConcatMap (Stream.ordered True)) +$(mkCrossType "OrderedParallel" "orderedBind" True) + +------------------------------------------------------------------------------- +-- Monadic benchmarks +------------------------------------------------------------------------------- + +{-# INLINE applicative #-} +applicative :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +applicative mk un linearCount start = + Stream.fold Fold.drain $ un $ + (+) <$> mk (sourceUnfoldrM nestedCount2 start) + <*> mk (sourceUnfoldrM nestedCount2 (start + 1)) + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + -$(mkZipType "ParZip" "parCrossApply" True) +{-# INLINE monad2 #-} +monad2 :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monad2 mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + return $ x + y -{-# INLINE zipApplicative #-} -zipApplicative - :: MonadAsync m => Int -> Int -> m () -zipApplicative count start = - Stream.fold Fold.drain $ unParZip $ - (+) <$> mkParZip (sourceUnfoldrM count start) - <*> mkParZip (sourceUnfoldrM count (start + 1)) + where -o_1_space_outerProduct :: Int -> (Config -> Config) -> [Benchmark] -o_1_space_outerProduct value f = - [ bgroup "outer-product" - [ benchIO "parCrossApply" $ drainApply f value - , benchIO "ZipApplicative" $ zipApplicative value + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + +{-# INLINE monadTakeSome #-} +monadTakeSome :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monadTakeSome mk un linearCount start = + Stream.fold Fold.drain $ Stream.take 1000 $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + return $ x + y + + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + +{-# INLINE monad3 #-} +monad3 :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monad3 mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount3 start + y <- mk $ sourceUnfoldrM nestedCount3 start + z <- mk $ sourceUnfoldrM nestedCount3 start + return $ x + y + z + + where + + nestedCount3 = round (fromIntegral linearCount**(1/3::Double)) + +{-# INLINE monadFilterAllOut #-} +monadFilterAllOut :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monadFilterAllOut mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + let s = x + y + if s < 0 + then return s + else mk Stream.nil + + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + +{-# INLINE monadFilterAllIn #-} +monadFilterAllIn :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monadFilterAllIn mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + let s = x + y + if s > 0 + then return s + else mk Stream.nil + + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + +{-# INLINE monadFilterSome #-} +monadFilterSome :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monadFilterSome mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + let s = x + y + if odd s + then return s + else mk Stream.nil + + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) + +{- +{-# INLINE monadBreak #-} +monadBreak :: Monad (t IO) => (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> Int -> IO () +monadBreak mk un linearCount start = + Stream.fold Fold.drain $ un $ do + x <- mk $ sourceUnfoldrM nestedCount2 start + y <- mk $ sourceUnfoldrM nestedCount2 start + let s = x + y + if s > nestedCount2 + then error "break" + else return s + + where + + nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) +-} + +crossBenchmarks :: Monad (t IO) => + (Stream IO Int -> t IO Int) + -> (t IO Int -> Stream IO Int) + -> Int -> (Stream.Config -> Stream.Config) -> [Benchmark] +crossBenchmarks mk un len f = + [ bgroup "cross-product" + [ benchIO "parCrossApply" $ parCrossApply f len + , benchIO "monadAp" $ applicative mk un len + , benchIO "monad2Levels" $ monad2 mk un len + , benchIO "monad3Levels" $ monad3 mk un len + , benchIO "monad2FilterAllOut" $ monadFilterAllOut mk un len + , benchIO "monad2FilterAllIn" $ monadFilterAllIn mk un len + , benchIO "monad2FilterSome" $ monadFilterSome mk un len + , benchIO "monad2TakeSome" $ monadTakeSome mk un len + -- , benchIO "monad2Break" $ monadBreak mk un len ] ] @@ -265,19 +427,15 @@ o_1_space_outerProduct value f = -- Benchmark sets ------------------------------------------------------------------------------- -allBenchmarks :: String -> Bool -> (Config -> Config) -> Int -> [Benchmark] -allBenchmarks moduleName wide modifier value = +allBenchmarks :: Monad (t IO) => + (Stream IO Int -> t IO Int) + -> (t IO Int -> Stream IO Int) + -> String -> Bool -> (Config -> Config) -> Int -> [Benchmark] +allBenchmarks mk un moduleName wide modifier value = [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_mapping value modifier - , o_1_space_concatFoldable value modifier - , o_1_space_concatMap "" value modifier - , o_1_space_concatMap "-maxThreads-1" value (modifier . Async.maxThreads 1) - , o_1_space_concatMap "-maxBuffer-1 1/10" (value `div` 10) (modifier . Async.maxBuffer 1) - , o_1_space_concatMap "-rate-Nothing" value (modifier . Async.rate Nothing) - , o_1_space_joining value modifier - ] ++ if wide then [] else o_1_space_outerProduct value modifier + [ o_1_space_benchmarks value modifier + ] ++ if wide then [] else crossBenchmarks mk un value modifier , bgroup (o_n_heap_prefix moduleName) $ concat - [ if wide then o_1_space_outerProduct value modifier else [] - , o_n_heap_buffering value modifier - ] + [ o_n_heap_benchmarks value modifier + ] ++ if wide then crossBenchmarks mk un value modifier else [] ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs index 0371044512..e40e1de08e 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs @@ -1,15 +1,14 @@ -{-# LANGUAGE FlexibleContexts #-} --- | +-- -- Module : Main -- Copyright : (c) 2018 Composewell Technologies -- -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon (allBenchmarks) +import Stream.ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) -import qualified Streamly.Internal.Data.Stream.Prelude as Async +import qualified Streamly.Internal.Data.Stream.Prelude as Stream moduleName :: String moduleName = "Data.Stream.ConcurrentEager" @@ -22,4 +21,6 @@ main :: IO () main = runWithCLIOpts defaultStreamSize - (allBenchmarks moduleName True (Async.eager True)) + (allBenchmarks + mkEagerParallel + unEagerParallel moduleName True (Stream.eager True)) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs index ab174c155a..8b5946f9f5 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs @@ -1,15 +1,14 @@ -{-# LANGUAGE FlexibleContexts #-} --- | +-- -- Module : Main -- Copyright : (c) 2022 Composewell Technologies -- -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon (allBenchmarks) +import Stream.ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) -import qualified Streamly.Internal.Data.Stream.Prelude as Async +import qualified Streamly.Internal.Data.Stream.Prelude as Stream moduleName :: String moduleName = "Data.Stream.ConcurrentInterleaved" @@ -22,4 +21,6 @@ main :: IO () main = runWithCLIOpts defaultStreamSize - (allBenchmarks moduleName True (Async.interleaved True)) + (allBenchmarks + mkFairParallel + unFairParallel moduleName True (Stream.interleaved True)) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs index fefb22446b..7b8e5da176 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs @@ -1,15 +1,14 @@ -{-# LANGUAGE FlexibleContexts #-} --- | +-- -- Module : Main -- Copyright : (c) 2018 Composewell Technologies -- -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon (allBenchmarks) +import Stream.ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) -import qualified Streamly.Internal.Data.Stream.Prelude as Async +import qualified Streamly.Data.Stream.Prelude as Stream moduleName :: String moduleName = "Data.Stream.ConcurrentOrdered" @@ -22,4 +21,6 @@ main :: IO () main = runWithCLIOpts defaultStreamSize - (allBenchmarks moduleName False (Async.ordered True)) + (allBenchmarks + mkOrderedParallel + unOrderedParallel moduleName False (Stream.ordered True)) From 728431880187c72546986553492f7423b6d4885d Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sat, 29 Nov 2025 17:11:29 +0530 Subject: [PATCH 12/24] Cleanup, fix benchmarks for Data.Stream Fix compilation with use-streamly-core flag --- benchmark/Streamly/Benchmark/Data/Stream.hs | 4 -- .../Streamly/Benchmark/Data/Stream/Common.hs | 5 ++ .../Benchmark/Data/Stream/ConcurrentCommon.hs | 49 ++++++++++++------- .../Benchmark/Data/Stream/Eliminate.hs | 2 +- .../Streamly/Benchmark/Data/Stream/Expand.hs | 12 ++--- .../Benchmark/Data/Stream/Generate.hs | 18 +++---- .../Benchmark/Data/Stream/Transform.hs | 16 ++++-- benchmark/Streamly/Benchmark/Data/StreamK.hs | 1 + 8 files changed, 65 insertions(+), 42 deletions(-) diff --git a/benchmark/Streamly/Benchmark/Data/Stream.hs b/benchmark/Streamly/Benchmark/Data/Stream.hs index f97469dd29..4606af2b1e 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream.hs @@ -26,9 +26,7 @@ import qualified Stream.Expand as NestedStream import qualified Stream.Generate as Generation import qualified Stream.Lift as Lift import qualified Stream.Reduce as NestedFold -#ifndef USE_PRELUDE import qualified Stream.Split as Split -#endif import qualified Stream.Transform as Transformation import Streamly.Benchmark.Common @@ -66,9 +64,7 @@ main = do #ifndef USE_STREAMLY_CORE , Exceptions.benchmarks moduleName env size #endif -#ifndef USE_PRELUDE , Split.benchmarks moduleName env -#endif , Transformation.benchmarks moduleName size , NestedFold.benchmarks moduleName size , Lift.benchmarks moduleName size diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Common.hs b/benchmark/Streamly/Benchmark/Data/Stream/Common.hs index 4f40a35702..6ae127ca4b 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Common.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Common.hs @@ -31,6 +31,7 @@ module Stream.Common , sourceUnfoldrAction , sourceConcatMapId , sourceFromFoldable + , sourceFromFoldableM -- Benchmark stream elimination , benchIOSink @@ -165,6 +166,10 @@ sourceUnfoldrAction value n = Stream.unfoldr step n sourceFromFoldable :: Monad m => Int -> Int -> Stream m Int sourceFromFoldable value n = Stream.fromFoldable [n..n+value] +{-# INLINE sourceFromFoldableM #-} +sourceFromFoldableM :: Monad m => Int -> Int -> Stream m Int +sourceFromFoldableM value n = Stream.fromFoldableM (fmap return [n..n+value]) + {-# INLINE benchIOSink #-} benchIOSink :: (NFData b) diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs index 16c496d578..d562e7d845 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs @@ -406,23 +406,38 @@ monadBreak mk un linearCount start = -} crossBenchmarks :: Monad (t IO) => - (Stream IO Int -> t IO Int) + Bool + -> (Stream IO Int -> t IO Int) -> (t IO Int -> Stream IO Int) -> Int -> (Stream.Config -> Stream.Config) -> [Benchmark] -crossBenchmarks mk un len f = - [ bgroup "cross-product" - [ benchIO "parCrossApply" $ parCrossApply f len - , benchIO "monadAp" $ applicative mk un len - , benchIO "monad2Levels" $ monad2 mk un len - , benchIO "monad3Levels" $ monad3 mk un len - , benchIO "monad2FilterAllOut" $ monadFilterAllOut mk un len - , benchIO "monad2FilterAllIn" $ monadFilterAllIn mk un len - , benchIO "monad2FilterSome" $ monadFilterSome mk un len - , benchIO "monad2TakeSome" $ monadTakeSome mk un len +crossBenchmarks wide mk un len f = + [ bgroup "cross-product" ( + [ benchIO "monad2FilterAllOut" $ monadFilterAllOut mk un len + + -- High heap requirement for eager/wide streams + , benchIO (suf "parCrossApply") $ parCrossApply f len2 + , benchIO (suf "monadAp") $ applicative mk un len2 + , benchIO (suf "monad2Levels") $ monad2 mk un len2 + , benchIO (suf "monad3Levels") $ monad3 mk un len2 + , benchIO (suf "monad2FilterAllIn") $ monadFilterAllIn mk un len2 + , benchIO (suf "monad2FilterSome") $ monadFilterSome mk un len2 -- , benchIO "monad2Break" $ monadBreak mk un len ] + ++ + -- XXX this takes too much heap in Eager case, because "take" does + -- not reduce eagerness. Pass "eager" arg to remove this only for eager + -- and not for "wide" case. + [benchIO "monad2TakeSome" $ monadTakeSome mk un len | not wide] + ) ] + where + + -- For wide cases use smaller stream size for cross benchmarks, to + -- reduce the heap requirements. + suf x = x ++ if wide then " n/4" else " n/2" + len2 = len `div` if wide then 4 else 2 + ------------------------------------------------------------------------------- -- Benchmark sets ------------------------------------------------------------------------------- @@ -432,10 +447,10 @@ allBenchmarks :: Monad (t IO) => -> (t IO Int -> Stream IO Int) -> String -> Bool -> (Config -> Config) -> Int -> [Benchmark] allBenchmarks mk un moduleName wide modifier value = - [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_benchmarks value modifier - ] ++ if wide then [] else crossBenchmarks mk un value modifier - , bgroup (o_n_heap_prefix moduleName) $ concat - [ o_n_heap_benchmarks value modifier - ] ++ if wide then crossBenchmarks mk un value modifier else [] + [ bgroup (o_1_space_prefix moduleName) $ + o_1_space_benchmarks value modifier + ++ if wide then [] else crossBenchmarks wide mk un value modifier + , bgroup (o_n_heap_prefix moduleName) $ + o_n_heap_benchmarks value modifier + ++ if wide then crossBenchmarks wide mk un value modifier else [] ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs b/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs index 6f1e659116..3d35ab96df 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs @@ -685,7 +685,7 @@ benchmarks moduleName size = o_n_heap_elimination_buffered size ++ o_n_heap_elimination_foldl size ++ o_n_heap_elimination_toList size - ++ o_n_space_elimination_toList size , bgroup (o_n_space_prefix moduleName) $ o_n_space_elimination_foldr size + ++ o_n_space_elimination_toList size ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index fc07a4370e..d669bc242d 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -145,11 +145,11 @@ mergeByM = mergeWithM Stream.mergeByM #ifdef INSPECTION inspect $ hasNoTypeClasses 'mergeBy inspect $ 'mergeBy `hasNoType` ''SPEC -inspect $ 'mergeBy `hasNoType` ''S.Step +-- inspect $ 'mergeBy `hasNoType` ''S.Step inspect $ hasNoTypeClasses 'mergeByM inspect $ 'mergeByM `hasNoType` ''SPEC -inspect $ 'mergeByM `hasNoType` ''S.Step +-- inspect $ 'mergeByM `hasNoType` ''S.Step #endif ------------------------------------------------------------------------------- @@ -161,9 +161,9 @@ zipWith :: Monad m => Stream m Int -> m () zipWith src = drain $ S.zipWith (,) src src #ifdef INSPECTION -inspect $ hasNoTypeClasses 'zipWith +-- inspect $ hasNoTypeClasses 'zipWith inspect $ 'zipWith `hasNoType` ''SPEC -inspect $ 'zipWith `hasNoType` ''S.Step +-- inspect $ 'zipWith `hasNoType` ''S.Step #endif {-# INLINE zipWithM #-} @@ -171,9 +171,9 @@ zipWithM :: Monad m => Stream m Int -> m () zipWithM src = drain $ S.zipWithM (curry return) src src #ifdef INSPECTION -inspect $ hasNoTypeClasses 'zipWithM +-- inspect $ hasNoTypeClasses 'zipWithM inspect $ 'zipWithM `hasNoType` ''SPEC -inspect $ 'zipWithM `hasNoType` ''S.Step +-- inspect $ 'zipWithM `hasNoType` ''S.Step #endif ------------------------------------------------------------------------------- diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs b/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs index 0f2779d555..4ba9fc1784 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Generate.hs @@ -157,13 +157,9 @@ fromIndices value n = Stream.take value $ Stream.fromIndices (+ n) fromIndicesM :: Monad m => Int -> Int -> Stream m Int fromIndicesM value n = Stream.take value $ Stream.fromIndicesM (return <$> (+ n)) -{-# INLINE absTimes #-} -absTimes :: MonadIO m => Int -> Int -> Stream m AbsTime -absTimes value _ = Stream.take value Stream.absTimes - -{-# INLINE sourceFromFoldableM #-} -sourceFromFoldableM :: Monad m => Int -> Int -> Stream m Int -sourceFromFoldableM value n = Stream.fromFoldableM (fmap return [n..n+value]) +{-# INLINE _absTimes #-} +_absTimes :: MonadIO m => Int -> Int -> Stream m AbsTime +_absTimes value _ = Stream.take value Stream.absTimes o_1_space_generation :: Int -> [Benchmark] o_1_space_generation value = @@ -194,10 +190,12 @@ o_1_space_generation value = , benchIOSrc "fromIndices" (fromIndices value) , benchIOSrc "fromIndicesM" (fromIndicesM value) - -- These essentially test cons and consM + -- fromFoldable essentially tests cons and consM which does not scale + -- for the Stream type. -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16) - , benchIOSrc "fromFoldableM" (sourceFromFoldableM value) - , benchIOSrc "absTimes" $ absTimes value + -- , benchIOSrc "fromFoldableM 16" (sourceFromFoldableM 16) + -- XXX tasty-bench hangs benchmarking this + -- , benchIOSrc "absTimes" $ _absTimes value ] ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs index 19e0e3590a..e16e9902b1 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs @@ -98,6 +98,7 @@ sequence = Common.drain . Stream.sequence tap :: MonadIO m => Int -> Stream m Int -> m () tap n = composeN n $ Stream.tap FL.sum +#ifndef USE_STREAMLY_CORE {-# INLINE pollCounts #-} pollCounts :: Int -> Stream IO Int -> IO () pollCounts n = @@ -106,10 +107,11 @@ pollCounts n = where f = Stream.drain . Stream.rollingMap2 (-) . Stream.delayPost 1 +#endif -{-# INLINE timestamped #-} -timestamped :: MonadIO m => Stream m Int -> m () -timestamped = Stream.drain . Stream.timestamped +{-# INLINE _timestamped #-} +_timestamped :: MonadIO m => Stream m Int -> m () +_timestamped = Stream.drain . Stream.timestamped {- {-# INLINE foldrT #-} foldrT :: MonadIO m => Int -> Stream m Int -> m () @@ -140,8 +142,11 @@ o_1_space_mapping value = sequence (sourceUnfoldrAction value n) , benchIOSink value "mapM" (mapM 1) , benchIOSink value "tap" (tap 1) +#ifndef USE_STREAMLY_CORE , benchIOSink value "parTapCount 1 second" (pollCounts 1) - , benchIOSink value "timestamped" timestamped +#endif + -- XXX tasty-bench hangs benchmarking this + -- , benchIOSink value "timestamped" _timestamped -- Scanning , benchIOSink value "scanl'" (scanl' 1) , benchIOSink value "scanl1'" (scanl1' 1) @@ -354,10 +359,13 @@ dropWhileMTrue value n = composeN n $ Stream.dropWhileM (return . (<= (value + 1 dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m () dropWhileFalse value n = composeN n $ Stream.dropWhile (> (value + 1)) +#ifndef USE_STREAMLY_CORE -- XXX Decide on the time interval {-# INLINE _intervalsOfSum #-} _intervalsOfSum :: Stream.MonadAsync m => Double -> Int -> Stream m Int -> m () _intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum) +#endif + {-# INLINE findIndices #-} findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m () findIndices value n = composeN n $ Stream.findIndices (== (value + 1)) diff --git a/benchmark/Streamly/Benchmark/Data/StreamK.hs b/benchmark/Streamly/Benchmark/Data/StreamK.hs index 09fa1a8176..a268cf39eb 100644 --- a/benchmark/Streamly/Benchmark/Data/StreamK.hs +++ b/benchmark/Streamly/Benchmark/Data/StreamK.hs @@ -42,6 +42,7 @@ import Prelude hiding ) import Streamly.Benchmark.Common #ifdef INSPECTION +import GHC.Types (SPEC(..)) import Test.Inspection #endif From cc7bb7396ea2e248fd5d92df91446e787922598e Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 00:03:27 +0530 Subject: [PATCH 13/24] Remove library used for Streamly.Prelude benchmarks --- benchmark/lib/Streamly/Benchmark/Prelude.hs | 598 -------------------- benchmark/streamly-benchmarks.cabal | 8 - 2 files changed, 606 deletions(-) delete mode 100644 benchmark/lib/Streamly/Benchmark/Prelude.hs diff --git a/benchmark/lib/Streamly/Benchmark/Prelude.hs b/benchmark/lib/Streamly/Benchmark/Prelude.hs deleted file mode 100644 index 2a119342d8..0000000000 --- a/benchmark/lib/Streamly/Benchmark/Prelude.hs +++ /dev/null @@ -1,598 +0,0 @@ - --- | --- Module : Streamly.Benchmark.Prelude --- Copyright : (c) 2018 Composewell Technologies --- --- License : MIT --- Maintainer : streamly@composewell.com - -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RankNTypes #-} - -module Streamly.Benchmark.Prelude - ( absTimes - , apDiscardFst - , apDiscardSnd - , apLiftA2 - , benchIO - , benchIOSink - , benchIOSrc - , breakAfterSome - , composeN - , concatFoldableWith - , concatForFoldableWith - , concatPairsWith - , concatStreamsWith - , filterAllInM - , filterAllOutM - , filterSome - , fmapN - , mapM - , mapN - , mkAsync - , monadThen - , runToList - , sourceConcatMapId - , sourceFoldMapM - , sourceFoldMapWith - , sourceFoldMapWithM - , sourceFoldMapWithStream - , sourceFracFromThenTo - , sourceFracFromTo - , sourceFromFoldable - , sourceFromFoldableM - , sourceFromList - , sourceFromListM - , sourceIntegerFromStep - , sourceIntFromThenTo - , sourceIntFromTo - , sourceUnfoldr - , sourceUnfoldrAction - , sourceUnfoldrM - , sourceUnfoldrMSerial - , toListM - , toListSome - , toNull - , toNullAp - , toNullM - , toNullM3 - , transformComposeMapM - , transformMapM - , transformTeeMapM - -- , transformZipMapM - ) -where - -import Control.Applicative (liftA2) -import Control.DeepSeq (NFData(..)) -import Control.Exception (try) -import Data.Functor.Identity (Identity) -import GHC.Exception (ErrorCall) -import Prelude hiding (mapM) -import System.Random (randomRIO) - -import qualified Data.Foldable as F -import qualified Data.List as List -import qualified Streamly.Prelude as S -import qualified Streamly.Internal.Data.Stream.IsStream as Internal -import qualified Streamly.Internal.Data.Stream.IsStream as IsStream -import qualified Streamly.Internal.Data.Pipe as Pipe -import qualified Streamly.Internal.Data.Stream.Serial as Serial - -import Test.Tasty.Bench -import Streamly.Internal.Data.Time.Units - --- Common polymorphic stream APIs used across multiple stream modules - -------------------------------------------------------------------------------- --- Generation -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- enumerate -------------------------------------------------------------------------------- - -{-# INLINE sourceIntFromTo #-} -sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -sourceIntFromTo value n = S.enumerateFromTo n (n + value) - -{-# INLINE sourceIntFromThenTo #-} -sourceIntFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -sourceIntFromThenTo value n = S.enumerateFromThenTo n (n + 1) (n + value) - -{-# INLINE sourceFracFromTo #-} -sourceFracFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double -sourceFracFromTo value n = - S.enumerateFromTo (fromIntegral n) (fromIntegral (n + value)) - -{-# INLINE sourceFracFromThenTo #-} -sourceFracFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Double -sourceFracFromThenTo value n = S.enumerateFromThenTo (fromIntegral n) - (fromIntegral n + 1.0001) (fromIntegral (n + value)) - -{-# INLINE sourceIntegerFromStep #-} -sourceIntegerFromStep :: (Monad m, S.IsStream t) => Int -> Int -> t m Integer -sourceIntegerFromStep value n = - S.take value $ S.enumerateFromThen (fromIntegral n) (fromIntegral n + 1) - -------------------------------------------------------------------------------- --- unfold -------------------------------------------------------------------------------- - -{-# INLINE sourceUnfoldr #-} -sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -sourceUnfoldr count start = S.unfoldr step start - where - step cnt = - if cnt > start + count - then Nothing - else Just (cnt, cnt + 1) - -{-# INLINE sourceUnfoldrM #-} -sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int -sourceUnfoldrM count start = S.unfoldrM step start - where - step cnt = - if cnt > start + count - then return Nothing - else return (Just (cnt, cnt + 1)) - -{-# INLINE sourceUnfoldrMSerial #-} -sourceUnfoldrMSerial :: (S.IsStream t, Monad m) => Int -> Int -> t m Int -sourceUnfoldrMSerial count start = - IsStream.fromSerial $ Serial.unfoldrM step start - where - step cnt = - if cnt > start + count - then return Nothing - else return (Just (cnt, cnt + 1)) - -------------------------------------------------------------------------------- --- fromList -------------------------------------------------------------------------------- - -{-# INLINE sourceFromList #-} -sourceFromList :: (Monad m, S.IsStream t) => Int -> Int -> t m Int -sourceFromList value n = S.fromList [n..n+value] - -{-# INLINE sourceFromListM #-} -sourceFromListM :: (S.MonadAsync m, S.IsStream t) => Int -> Int -> t m Int -sourceFromListM value n = S.fromListM (fmap return [n..n+value]) - -------------------------------------------------------------------------------- --- fromFoldable -------------------------------------------------------------------------------- - -{-# INLINE sourceFromFoldable #-} -sourceFromFoldable :: S.IsStream t => Int -> Int -> t m Int -sourceFromFoldable value n = S.fromFoldable [n..n+value] - -{-# INLINE sourceFromFoldableM #-} -sourceFromFoldableM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int -sourceFromFoldableM value n = S.fromFoldableM (fmap return [n..n+value]) - -------------------------------------------------------------------------------- --- Time enumeration -------------------------------------------------------------------------------- - -{-# INLINE absTimes #-} -absTimes :: (S.IsStream t, S.MonadAsync m, Functor (t m)) - => Int -> Int -> t m AbsTime -absTimes value _ = S.take value Internal.absTimes - -------------------------------------------------------------------------------- --- Buffering -------------------------------------------------------------------------------- - -{-# INLINE mkAsync #-} -mkAsync :: (S.MonadAsync m, S.IsStream t) => (t m a -> S.SerialT m a) -> t m a -> m () -mkAsync adapter = S.drain . adapter . S.mkAsync - -------------------------------------------------------------------------------- --- Elimination -------------------------------------------------------------------------------- - -{-# INLINE toNull #-} -toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m () -toNull t = S.drain . t - --- We need a monadic bind here to make sure that the function f does not get --- completely optimized out by the compiler in some cases. - --- | Takes a fold method, and uses it with a default source. -{-# INLINE benchIOSink #-} -benchIOSink - :: (S.IsStream t, NFData b) - => Int -> String -> (t IO Int -> IO b) -> Benchmark -benchIOSink value name f = - bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldrM value - --- | Takes a source, and uses it with a default drain/fold method. -{-# INLINE benchIOSrc #-} -benchIOSrc - :: (t IO a -> S.SerialT IO a) - -> String - -> (Int -> t IO a) - -> Benchmark -benchIOSrc t name f = - bench name $ nfIO $ randomRIO (1,1) >>= toNull t . f - -{-# NOINLINE benchIO #-} -benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark -benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f - -------------------------------------------------------------------------------- --- Mapping -------------------------------------------------------------------------------- - -{-# INLINE sourceUnfoldrAction #-} -sourceUnfoldrAction :: (S.IsStream t, Monad m, Monad m1) - => Int -> Int -> t m (m1 Int) -sourceUnfoldrAction value n = S.fromSerial $ S.unfoldr step n - where - step cnt = - if cnt > n + value - then Nothing - else Just (return cnt, cnt + 1) - -{-# INLINE composeN #-} -composeN :: - (S.IsStream t, Monad m) - => Int - -> (t m Int -> S.SerialT m Int) - -> t m Int - -> m () -composeN n f = - case n of - 1 -> S.drain . f - 2 -> S.drain . f . S.adapt . f - 3 -> S.drain . f . S.adapt . f . S.adapt . f - 4 -> S.drain . f . S.adapt . f . S.adapt . f . S.adapt . f - _ -> undefined - -{-# INLINE fmapN #-} -fmapN :: - (S.IsStream t, S.MonadAsync m, Functor (t m)) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -fmapN t n = composeN n $ t . fmap (+ 1) - -{-# INLINE mapN #-} -mapN :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -mapN t n = composeN n $ t . S.map (+ 1) - -{-# INLINE mapM #-} -mapM :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -mapM t n = composeN n $ t . S.mapM return - -------------------------------------------------------------------------------- --- Pipes -------------------------------------------------------------------------------- - -{-# INLINE transformMapM #-} -transformMapM :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -transformMapM t n = composeN n $ t . Internal.transform (Pipe.mapM return) - -{-# INLINE transformComposeMapM #-} -transformComposeMapM :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -transformComposeMapM t n = - composeN n $ - t . - Internal.transform - (Pipe.mapM (\x -> return (x + 1)) `Pipe.compose` - Pipe.mapM (\x -> return (x + 2))) - -{-# INLINE transformTeeMapM #-} -transformTeeMapM :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -transformTeeMapM t n = - composeN n $ - t . - Internal.transform - (Pipe.mapM (\x -> return (x + 1)) `Pipe.teeMerge` - Pipe.mapM (\x -> return (x + 2))) - -{- -{-# INLINE transformZipMapM #-} -transformZipMapM :: - (S.IsStream t, S.MonadAsync m) - => (t m Int -> S.SerialT m Int) - -> Int - -> t m Int - -> m () -transformZipMapM t n = - composeN n $ - t . - Internal.transform - (Pipe.zipWith - (+) - (Pipe.mapM (\x -> return (x + 1))) - (Pipe.mapM (\x -> return (x + 2)))) --} - -------------------------------------------------------------------------------- --- Streams of streams -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- Concat foldable -------------------------------------------------------------------------------- - -{-# INLINE sourceFoldMapWith #-} -sourceFoldMapWith :: (S.IsStream t, Semigroup (t m Int)) - => Int -> Int -> t m Int -sourceFoldMapWith value n = S.concatMapFoldableWith (<>) S.fromPure [n..n+value] - -{-# INLINE concatForFoldableWith #-} -concatForFoldableWith :: (S.IsStream t, Semigroup (t m Int)) - => Int -> Int -> t m Int -concatForFoldableWith value n = - S.concatForFoldableWith (<>) [n..n+value] S.fromPure - -{-# INLINE concatFoldableWith #-} -concatFoldableWith :: (S.IsStream t, Semigroup (t m Int)) - => Int -> Int -> t m Int -concatFoldableWith value n = - let step x = - if x <= n + value - then Just (S.fromPure x, x + 1) - else Nothing - list = List.unfoldr step n - in S.concatFoldableWith (<>) list - -{-# INLINE sourceFoldMapWithStream #-} -sourceFoldMapWithStream :: (S.IsStream t, Semigroup (t m Int)) - => Int -> Int -> t m Int -sourceFoldMapWithStream value n = S.concatMapFoldableWith (<>) S.fromPure - $ (S.enumerateFromTo n (n + value) :: S.SerialT Identity Int) - -{-# INLINE sourceFoldMapWithM #-} -sourceFoldMapWithM :: (S.IsStream t, Monad m, Semigroup (t m Int)) - => Int -> Int -> t m Int -sourceFoldMapWithM value n = - S.concatMapFoldableWith (<>) (S.fromEffect . return) [n..n+value] - -{-# INLINE sourceFoldMapM #-} -sourceFoldMapM :: (S.IsStream t, Monad m, Monoid (t m Int)) - => Int -> Int -> t m Int -sourceFoldMapM value n = F.foldMap (S.fromEffect . return) [n..n+value] - -------------------------------------------------------------------------------- --- Concat -------------------------------------------------------------------------------- - -{-# INLINE sourceConcatMapId #-} -sourceConcatMapId :: (S.IsStream t, Monad m) - => Int -> Int -> t m (t m Int) -sourceConcatMapId value n = - S.fromFoldable $ fmap (S.fromEffect . return) [n..n+value] - --- concatMapWith - -{-# INLINE concatStreamsWith #-} -concatStreamsWith - :: (S.SerialT IO Int -> S.SerialT IO Int -> S.SerialT IO Int) - -> Int - -> Int - -> Int - -> IO () -concatStreamsWith op outer inner n = - S.drain $ S.concatMapWith op - (S.fromSerial . sourceUnfoldrM inner) - (S.fromSerial $ sourceUnfoldrM outer n) - -{-# INLINE concatPairsWith #-} -concatPairsWith - :: (S.SerialT IO Int -> S.SerialT IO Int -> S.SerialT IO Int) - -> Int - -> Int - -> Int - -> IO () -concatPairsWith op outer inner n = - S.drain $ Internal.concatPairsWith op - (S.fromSerial . sourceUnfoldrM inner) - (S.fromSerial $ sourceUnfoldrM outer n) - -------------------------------------------------------------------------------- --- Monadic outer product -------------------------------------------------------------------------------- - -{-# INLINE runToList #-} -runToList :: Monad m => S.SerialT m a -> m [a] -runToList = S.toList - -{-# INLINE apDiscardFst #-} -apDiscardFst - :: (S.IsStream t, S.MonadAsync m, Applicative (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -apDiscardFst linearCount t start = S.drain . t $ - S.fromSerial (sourceUnfoldrM nestedCount2 start) - *> S.fromSerial (sourceUnfoldrM nestedCount2 start) - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE apDiscardSnd #-} -apDiscardSnd - :: (S.IsStream t, S.MonadAsync m, Applicative (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -apDiscardSnd linearCount t start = S.drain . t $ - S.fromSerial (sourceUnfoldrM nestedCount2 start) - <* S.fromSerial (sourceUnfoldrM nestedCount2 start) - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE apLiftA2 #-} -apLiftA2 - :: (S.IsStream t, S.MonadAsync m, Applicative (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -apLiftA2 linearCount t start = S.drain . t $ - liftA2 (+) (S.fromSerial (sourceUnfoldrM nestedCount2 start)) - (S.fromSerial (sourceUnfoldrM nestedCount2 start)) - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE toNullAp #-} -toNullAp - :: (S.IsStream t, S.MonadAsync m, Applicative (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -toNullAp linearCount t start = S.drain . t $ - (+) <$> S.fromSerial (sourceUnfoldrM nestedCount2 start) - <*> S.fromSerial (sourceUnfoldrM nestedCount2 start) - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE monadThen #-} -monadThen - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -monadThen linearCount t start = S.drain . t $ do - (S.fromSerial $ sourceUnfoldrM nestedCount2 start) >> - (S.fromSerial $ sourceUnfoldrM nestedCount2 start) - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE toNullM #-} -toNullM - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -toNullM linearCount t start = S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - return $ x + y - - where - - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE toNullM3 #-} -toNullM3 - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -toNullM3 linearCount t start = S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount3 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount3 start - z <- S.fromSerial $ sourceUnfoldrM nestedCount3 start - return $ x + y + z - where - nestedCount3 = round (fromIntegral linearCount**(1/3::Double)) - -{-# INLINE toListM #-} -toListM - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m [Int] -toListM linearCount t start = runToList . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - return $ x + y - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - --- Taking a specified number of elements is very expensive in logict so we have --- a test to measure the same. -{-# INLINE toListSome #-} -toListSome - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m [Int] -toListSome linearCount t start = - runToList . t $ S.take 10000 $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - return $ x + y - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE filterAllOutM #-} -filterAllOutM - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -filterAllOutM linearCount t start = S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - let s = x + y - if s < 0 - then return s - else S.nil - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE filterAllInM #-} -filterAllInM - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -filterAllInM linearCount t start = S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - let s = x + y - if s > 0 - then return s - else S.nil - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE filterSome #-} -filterSome - :: (S.IsStream t, S.MonadAsync m, Monad (t m)) - => Int -> (t m Int -> S.SerialT m Int) -> Int -> m () -filterSome linearCount t start = S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - let s = x + y - if s > 1100000 - then return s - else S.nil - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) - -{-# INLINE breakAfterSome #-} -breakAfterSome - :: (S.IsStream t, Monad (t IO)) - => Int -> (t IO Int -> S.SerialT IO Int) -> Int -> IO () -breakAfterSome linearCount t start = do - (_ :: Either ErrorCall ()) <- try $ S.drain . t $ do - x <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - y <- S.fromSerial $ sourceUnfoldrM nestedCount2 start - let s = x + y - if s > 1100000 - then error "break" - else return s - return () - where - nestedCount2 = round (fromIntegral linearCount**(1/2::Double)) diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index 5b67b444c2..6cddcf44ed 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -59,11 +59,6 @@ flag use-streamly-core manual: True default: False -flag use-prelude - description: Use Prelude instead of Data.Stream for serial benchmarks - manual: True - default: False - ------------------------------------------------------------------------------- -- Common stanzas ------------------------------------------------------------------------------- @@ -223,9 +218,6 @@ library hs-source-dirs: lib exposed-modules: Streamly.Benchmark.Common , Streamly.Benchmark.Common.Handle - if flag(use-prelude) - exposed-modules: Streamly.Benchmark.Prelude - ------------------------------------------------------------------------------- -- Benchmarks From f2c1eb2abc050f4d1977a2909c2ed0c5bb4f8145 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Fri, 28 Nov 2025 23:23:29 +0530 Subject: [PATCH 14/24] Remove the removed benchmark targets from cabal file --- benchmark/streamly-benchmarks.cabal | 132 ---------------------------- 1 file changed, 132 deletions(-) diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index 6cddcf44ed..6149c7baa7 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -660,135 +660,3 @@ benchmark Unicode.Utf8 buildable: False else buildable: True - -------------------------------------------------------------------------------- --- Deprecated -------------------------------------------------------------------------------- - -benchmark Prelude - import: bench-options - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data - main-is: Stream.hs - other-modules: - Stream.Generate - Stream.Eliminate - Stream.Transform - Stream.Reduce - Stream.Expand - Stream.Lift - Stream.Common - Stream.Exceptions - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - if flag(limit-build-mem) - if flag(dev) - ghc-options: +RTS -M3500M -RTS - else - ghc-options: +RTS -M2500M -RTS - -benchmark Prelude.WSerial - import: bench-options - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: WSerial.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - if flag(limit-build-mem) - ghc-options: +RTS -M750M -RTS - -benchmark Prelude.Merge - import: bench-options - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Merge.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.ZipSerial - import: bench-options - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: ZipSerial.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.ZipAsync - import: bench-options - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: ZipAsync.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - if flag(limit-build-mem) - ghc-options: +RTS -M1000M -RTS - -benchmark Prelude.Ahead - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Ahead.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.Async - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Async.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.WAsync - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: WAsync.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.Parallel - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Parallel.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - if flag(limit-build-mem) - ghc-options: +RTS -M2000M -RTS - -benchmark Prelude.Concurrent - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Concurrent.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.Adaptive - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Adaptive.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False - -benchmark Prelude.Rate - import: bench-options-threaded - type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Prelude - main-is: Rate.hs - cpp-options: -DUSE_PRELUDE - if !flag(use-prelude) - buildable: False From a05c01d518633f5f4cdf67eb25c200e68007a186 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 06:27:15 +0530 Subject: [PATCH 15/24] Reduce limit-build-mem for benchmarks to 400MB --- benchmark/streamly-benchmarks.cabal | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index 6149c7baa7..314734e188 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -228,7 +228,7 @@ common bench-options include-dirs: . ghc-options: -rtsopts -with-rtsopts "-t" if flag(limit-build-mem) - ghc-options: +RTS -M512M -RTS + ghc-options: +RTS -M400M -RTS build-depends: streamly-benchmarks == 0.0.0 -- Some benchmarks are threaded some are not @@ -238,7 +238,7 @@ common bench-options-threaded -- trigger only with these options. ghc-options: -threaded -rtsopts -with-rtsopts "-t -N2" if flag(limit-build-mem) - ghc-options: +RTS -M512M -RTS + ghc-options: +RTS -M400M -RTS build-depends: streamly-benchmarks == 0.0.0 ------------------------------------------------------------------------------- @@ -312,8 +312,8 @@ benchmark Data.Fold.Window main-is: Window.hs -- MonoLocalBinds increases the memory requirement from 400MB to 1000MB, -- observed on macOS. - if flag(limit-build-mem) - ghc-options: +RTS -M1000M -RTS + -- if flag(limit-build-mem) + -- ghc-options: +RTS -M1000M -RTS benchmark Data.MutArray import: bench-options From d35ef029c5f6d96aa09b26ec2c941df72b566909 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 00:05:52 +0530 Subject: [PATCH 16/24] Remove obsolete bench-runner options, update Data.Stream options --- benchmark/bench-runner/Main.hs | 167 +++++++++++++-------------------- 1 file changed, 66 insertions(+), 101 deletions(-) diff --git a/benchmark/bench-runner/Main.hs b/benchmark/bench-runner/Main.hs index fe434ae0b3..e36d32a036 100644 --- a/benchmark/bench-runner/Main.hs +++ b/benchmark/bench-runner/Main.hs @@ -25,76 +25,12 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific] | otherwise = "" exeSpecific - | "Prelude.Concurrent" `isSuffixOf` exeName = "-K512K -M384M" + -- | "Data.Stream.ConcurrentEager" `isSuffixOf` exeName = "-K512K -M384M" + -- placeholder to remind usage of exeName + | "abc" `isSuffixOf` exeName = "" | otherwise = "" benchSpecific - -- GHC-9.6 requires 64M, earlier it was 16M - | "Data.Fold/o-n-heap.key-value.toHashMapIO (max buckets) sum" == benchName = - "-M64M" - - -- This is required only for the --long case because we allocate all - -- the arrays upfront. depends on the size of the stream. - | "Data.Parser/o-1-space" `isPrefixOf` benchName = - "-M128M" - - ----------------------------------------------------------------------- - - | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = "-M256M" - | "Prelude.Parallel/o-n-heap.monad-outer-product." - `isPrefixOf` benchName = "-M256M" - | "Prelude.Parallel/o-n-space.monad-outer-product." - `isPrefixOf` benchName = "-K2M -M256M" - | "Prelude.Rate/o-1-space." `isPrefixOf` benchName = "-K128K" - | "Prelude.Rate/o-1-space.asyncly." `isPrefixOf` benchName = "-K128K" - | "Prelude.WSerial/o-n-space." `isPrefixOf` benchName = "-K4M" - | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName = - "-K4M" - | "Prelude.Ahead/o-1-space.monad-outer-product." `isPrefixOf` benchName = - "-K128K -M32M" - | "Prelude.Ahead/o-1-space." `isPrefixOf` benchName = "-K128K" - | "Prelude.Ahead/o-n-space.monad-outer-product." `isPrefixOf` benchName = - "-K4M" - | "Prelude.WAsync/o-n-heap.monad-outer-product.toNull3" == benchName = - "-M64M" - | "Prelude.WAsync/o-n-space.monad-outer-product." `isPrefixOf` benchName = - "-K4M" - - ----------------------------------------------------------------------- - - | "Data.StreamD/o-n-space.elimination.toList" == benchName = - "-K2M" - | "Data.StreamK/o-n-space.elimination.toList" == benchName = - "-K2M" - -- XXX Memory required for these has increased in streamly-core 0.3 - | "Data.StreamK/o-1-space.list.nested" `isPrefixOf` benchName = - "-M640M" - - ----------------------------------------------------------------------- - - | "Data.Stream/o-1-space.grouping.classifySessionsOf" - `isPrefixOf` benchName = "-K512K" - | "Data.Stream/o-n-space.foldr.foldrM/" - `isPrefixOf` benchName = "-K4M" - | "Data.Stream/o-n-space.iterated." - `isPrefixOf` benchName = "-K4M" - - -- GHC-9.6 requires 64M, earlier it was 32M - | "Data.Stream/o-n-heap.buffered.showPrec Haskell lists" == benchName = - "-M64M" - -- GHC-9.6 requires 64M, earlier it was 32M - | "Data.Stream/o-n-heap.buffered.readsPrec pure streams" == benchName = - "-M64M" - - | "Data.Stream.ConcurrentEager/o-n-heap.monad-outer-product.toNullAp" - `isPrefixOf` benchName = "-M1500M" - | "Data.Stream.ConcurrentEager/o-1-space." - `isPrefixOf` benchName = "-M128M" - - | "Data.Stream.ConcurrentOrdered/o-1-space.concat-foldable.foldMapWith" - `isPrefixOf` benchName = "-K128K" - - ---------------------------------------------------------------------- | "Data.Array" `isPrefixOf` benchName && "/o-1-space.generation.read" `isSuffixOf` benchName = "-M32M" @@ -110,6 +46,20 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific] -- chunked stream benchmarks in the stream module. | "Data.Array.Stream/o-1-space" `isPrefixOf` benchName = "-K4M -M512M" + + ---------------------------------------------------------------------- + + -- GHC-9.6 requires 64M, earlier it was 16M + | "Data.Fold/o-n-heap.key-value.toHashMapIO (max buckets) sum" + == benchName = "-M64M" + + ---------------------------------------------------------------------- + + -- This is required only for the --long case because we allocate all + -- the arrays upfront. depends on the size of the stream. + | "Data.Parser/o-1-space" + `isPrefixOf` benchName = "-M128M" + -- XXX Takes up to 160MB heap for --long, we use chunked stream for -- this, so the reason may be related to chunked streams. | "Data.ParserK/o-1-space" @@ -119,12 +69,50 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific] | "Data.ParserK.Chunked.Generic/o-1-space" `isPrefixOf` benchName = "-K4M -M256M" -{- - -- XXX This options does not seem to take effect. "ParserK.Chunked" - -- needs more memory to work with --long option - | "Data.ParserK.Chunked.Generic/o-1-space" - `isPrefixOf` benchName = "-K4M -M256M" --} + ----------------------------------------------------------------------- + + | "Data.Stream/o-1-space.grouping.classifySessionsOf" + `isPrefixOf` benchName = "-K512K" + + -- GHC-9.6 requires 64M, earlier it was 32M + | "Data.Stream/o-n-heap.buffered.showPrec Haskell lists" + == benchName = "-M64M" + -- GHC-9.6 requires 64M, earlier it was 32M + | "Data.Stream/o-n-heap.buffered.readsPrec pure streams" + == benchName = "-M64M" + + | "Data.Stream/o-n-space.foldr.foldrM/" + `isPrefixOf` benchName = "-K4M" + | "Data.Stream/o-n-space.iterated." + `isPrefixOf` benchName = "-K4M" + | "Data.Stream/o-n-space.toList.toList" + `isPrefixOf` benchName = "-K2M" + | "Data.Stream/o-n-space.Monad.toList" + `isPrefixOf` benchName = "-K2M" + + ----------------------------------------------------------------------- + + | "Data.StreamK/o-n-space.elimination.toList" + == benchName = "-K2M" + -- XXX Memory required for these has increased in streamly-core 0.3 + | "Data.StreamK/o-1-space.list.nested" + `isPrefixOf` benchName = "-M500M" + + ---------------------------------------------------------------------- + -- Concurrent streams + ---------------------------------------------------------------------- + + | "Data.Stream.ConcurrentInterleaved/o-n-heap.cross-product.monad3" + `isPrefixOf` benchName = "-M128M" + + | "Data.Stream.ConcurrentEager/o-1-space." + `isPrefixOf` benchName = "-M128M" + + | "Data.Stream.ConcurrentEager/o-n-heap.cross-product" + `isPrefixOf` benchName = "-M500M" + + | "Data.Stream.ConcurrentOrdered/o-1-space.concat-foldable.foldMapWith" + `isPrefixOf` benchName = "-K128K" ----------------------------------------------------------------------- @@ -141,38 +129,15 @@ speedOpts exeName benchName0 = exeSpecific <|> benchSpecific -- slowestOf _ Quicker = Quicker -- slowestOf _ _ = SuperQuick - -- Drop All. + -- Drop the "All." prefix benchName = drop 4 benchName0 exeSpecific - | "Prelude.Concurrent" == exeName = Just SuperQuick - | "Prelude.Rate" == exeName = Just SuperQuick - | "Prelude.Adaptive" == exeName = Just SuperQuick + | "Data.Stream.ConcurrentThreadHeavy" == exeName = Just SuperQuick + | "Data.Stream.Rate" == exeName = Just SuperQuick + | "Data.Stream.Adaptive" == exeName = Just SuperQuick | otherwise = Nothing benchSpecific - | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = - Just SuperQuick - | "Prelude.Parallel/o-n-heap.monad-outer-product." - `isPrefixOf` benchName = Just SuperQuick - | "Prelude.Parallel.o-n-space.monad-outer-product." - `isPrefixOf` benchName = Just SuperQuick - | "Prelude.Parallel/o-n-heap.generation." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Parallel/o-n-heap.mapping." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Parallel/o-n-heap.concat-foldable." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Async/o-1-space.monad-outer-product." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Ahead/o-1-space.monad-outer-product." `isPrefixOf` benchName = - Just Quicker - | "Prelude.Ahead/o-n-space.monad-outer-product." `isPrefixOf` benchName = - Just Quicker - | "Prelude.WAsync/o-n-heap.monad-outer-product." `isPrefixOf` benchName = - Just Quicker - | "Prelude.WAsync/o-n-space.monad-outer-product." `isPrefixOf` benchName = - Just Quicker + | "-maxBuffer-1" `isInfixOf` benchName = Just SuperQuick | "FileSystem.Handle." `isPrefixOf` benchName = Just Quicker | otherwise = Nothing From 203861841c191fd1a0fbe2495b8c87571b1a8149 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sat, 29 Nov 2025 15:15:27 +0530 Subject: [PATCH 17/24] Remove Streamly.Prelude benchmarks from bench-runner targets --- targets/Targets.hs | 79 ---------------------------------------------- 1 file changed, 79 deletions(-) diff --git a/targets/Targets.hs b/targets/Targets.hs index f5eb344cd8..d884da5a8b 100644 --- a/targets/Targets.hs +++ b/targets/Targets.hs @@ -246,83 +246,4 @@ targets = , ("Unicode.Stream", []) , ("Unicode.Utf8", ["noTest"]) , ("version-bounds", ["noBench"]) - - ---- DEPRECATED ---- - - -- test only, no benchmarks - -- , ("Prelude", ["prelude_other_grp", "noBench"]) - -- , ("Prelude.Fold", ["prelude_other_grp", "noBench"]) - -- Enabled only when use-prelude flag is set - -- , ("Prelude.Serial", - -- [ "prelude_serial_grp" - -- , "infinite_grp" - -- , "serial_wserial_cmp" - -- , "noBench" - -- ] - -- ) - -- , ("Prelude.Top", - -- [ "prelude_serial_grp" - -- , "infinite_grp" - -- , "noBench" - -- ] - -- ) - -- , ("Prelude.WSerial", - -- [ "prelude_serial_grp" - -- , "infinite_grp" - -- , "serial_wserial_cmp" - -- ] - -- ) - -- , ("Prelude.Merge", - -- [ "prelude_serial_grp" - -- , "infinite_grp" - -- , "noTest" - -- ] - -- ) - -- , ("Prelude.ZipSerial", - -- [ "prelude_serial_grp" - -- , "infinite_grp" - -- ] - -- ) - -- , ("Prelude.Async", - -- [ "prelude_concurrent_grp" - -- , "infinite_grp" - -- , "concurrent_cmp" - -- , "serial_async_cmp" - -- ] - -- ) - -- , ("Prelude.WAsync", - -- [ "prelude_concurrent_grp" - -- , "infinite_grp" - -- , "concurrent_cmp" - -- ] - -- ) - -- , ("Prelude.Ahead", - -- [ "prelude_concurrent_grp" - -- , "infinite_grp" - -- , "concurrent_cmp" - -- ] - -- ) - -- , ("Prelude.Parallel", - -- [ "prelude_concurrent_grp" - -- , "infinite_grp" - -- , "concurrent_cmp" - -- ] - -- ) - -- , ("Prelude.ZipAsync", - -- [ "prelude_concurrent_grp" - -- , "infinite_grp" - -- ] - -- ) - -- , ("Prelude.Concurrent", [ "prelude_other_grp" ]) - -- , ("Prelude.Rate", - -- [ "prelude_other_grp" - -- , "infinite_grp" - -- , "testDevOnly" - -- ] - -- ) - -- , ("Prelude.Adaptive", - -- [ "prelude_other_grp" - -- , "noTest" - -- ] - -- ) ] From e164e986903725e4f66a15ab512729b87325ae46 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 06:26:23 +0530 Subject: [PATCH 18/24] Create a streamly_core_grp benchmark group --- targets/Targets.hs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/targets/Targets.hs b/targets/Targets.hs index d884da5a8b..c4ecc24d25 100644 --- a/targets/Targets.hs +++ b/targets/Targets.hs @@ -40,11 +40,13 @@ targets = , ("Data.Fold", [ "infinite_grp" , "fold_parser_grp" + , "streamly_core_grp" ] ) , ("Data.Fold.Window", [ "infinite_grp" , "fold_parser_grp" + , "streamly_core_grp" ] ) , ("Data.List", @@ -67,46 +69,54 @@ targets = [ "infinite_grp" , "fold_parser_grp" , "parser_cmp" + , "streamly_core_grp" ] ) , ("Data.ParserK", [ "infinite_grp" , "fold_parser_grp" , "parser_cmp" + , "streamly_core_grp" ] ) , ("Data.ParserK.Chunked", [ "infinite_grp" , "fold_parser_grp" , "parser_cmp" + , "streamly_core_grp" , "noTest" ] ) , ("Data.ParserK.Chunked.Generic", [ "infinite_grp" , "fold_parser_grp" + , "streamly_core_grp" , "parser_cmp" , "noTest" ] ) , ("Data.RingArray", [ "array_grp" + , "streamly_core_grp" ] ) , ("Data.Scanl", [ "infinite_grp" , "fold_parser_grp" + , "streamly_core_grp" , "noTest" ] ) , ("Data.Scanl.Window", [ "infinite_grp" , "fold_parser_grp" + , "streamly_core_grp" , "noTest" ] ) , ("Data.Serialize", [ "mut_bytearray_grp" + , "streamly_core_grp" ] ) , ("Data.Serialize.Derive.TH", @@ -129,6 +139,7 @@ targets = , "serial_stream_grp" , "serial_stream_cmp" , "serial_concurrent_cmp" + , "streamly_core_grp" ] ) , ("Data.Stream.Adaptive", @@ -181,6 +192,7 @@ targets = [ "infinite_grp" , "serial_stream_grp" , "serial_stream_cmp" + , "streamly_core_grp" , "noTest" ] ) @@ -196,6 +208,7 @@ targets = -} , ("Data.Unbox", [ "noTest" + , "streamly_core_grp" ] ) , ("Data.Unbox.Derive.Generic", @@ -203,7 +216,8 @@ targets = ] ) , ("Data.Unbox.Derive.TH", - [] + [ "streamly_core_grp" + ] ) , ("Data.Unbox.TH", [ "noBench" @@ -212,6 +226,7 @@ targets = , ("Data.Unfold", [ "infinite_grp" , "serial_stream_grp" + , "streamly_core_grp" ] ) , ("FileSystem.Event", @@ -242,7 +257,7 @@ targets = , ("Network.Inet.TCP", ["noBench"]) , ("Network.Socket", ["noBench"]) , ("Unicode.Char", ["testDevOnly"]) - , ("Unicode.Parser", []) + , ("Unicode.Parser", ["streamly_core_grp"]) , ("Unicode.Stream", []) , ("Unicode.Utf8", ["noTest"]) , ("version-bounds", ["noBench"]) From dd10117c6cd89cb20ee99de0253c5e0f2b431f0e Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sat, 29 Nov 2025 13:58:30 +0530 Subject: [PATCH 19/24] Add ConcurrentOrdered, ConcurrentEager to hie.yaml --- hie.yaml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/hie.yaml b/hie.yaml index 453f36deb9..353bd0279d 100644 --- a/hie.yaml +++ b/hie.yaml @@ -42,8 +42,12 @@ cradle: component: "bench:Data.Stream.Concurrent" - path: "./benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs" component: "bench:Data.Stream.Concurrent" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs" + component: "bench:Data.Stream.ConcurrentInterleaved" - path: "./benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs" component: "bench:Data.Stream.ConcurrentEager" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs" + component: "bench:Data.Stream.ConcurrentOrdered" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs" component: "bench:Data.Stream" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs" @@ -70,18 +74,6 @@ cradle: component: "bench:FileSystem.Handle" - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs" component: "bench:FileSystem.Handle" - - path: "./benchmark/Streamly/Benchmark/Prelude/Ahead.hs" - component: "bench:Prelude.Ahead" - - path: "./benchmark/Streamly/Benchmark/Prelude/Async.hs" - component: "bench:Prelude.Async" - - path: "./benchmark/Streamly/Benchmark/Prelude/Merge.hs" - component: "bench:Prelude.Merge" - - path: "./benchmark/Streamly/Benchmark/Prelude/Parallel.hs" - component: "bench:Prelude.Parallel" - - path: "./benchmark/Streamly/Benchmark/Prelude/WSerial.hs" - component: "bench:Prelude.WSerial" - - path: "./benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs" - component: "bench:Prelude.ZipSerial" - path: "./benchmark/Streamly/Benchmark/Unicode/Char.hs" component: "bench:Unicode.Char" - path: "./benchmark/Streamly/Benchmark/Unicode/Parser.hs" From 7041f98ee53bb00f1c9affe4ff1bc51f00294367 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 08:26:16 +0530 Subject: [PATCH 20/24] Remove Steramly.Prelude benchmark files from sdist --- streamly.cabal | 1 - 1 file changed, 1 deletion(-) diff --git a/streamly.cabal b/streamly.cabal index f7d5e23e18..043637e536 100644 --- a/streamly.cabal +++ b/streamly.cabal @@ -88,7 +88,6 @@ extra-source-files: benchmark/Streamly/Benchmark/Data/StreamK/*.hs benchmark/Streamly/Benchmark/FileSystem/*.hs benchmark/Streamly/Benchmark/FileSystem/Handle/*.hs - benchmark/Streamly/Benchmark/Prelude/*.hs benchmark/Streamly/Benchmark/Unicode/*.hs benchmark/lib/Streamly/Benchmark/*.hs benchmark/lib/Streamly/Benchmark/Common/*.hs From 891491d67a173c5b30442ff5caab0618c03d8a90 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 08:33:29 +0530 Subject: [PATCH 21/24] Add hls.yaml to packcheck.ignore --- .packcheck.ignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.packcheck.ignore b/.packcheck.ignore index 3bbe9a0789..4a45873f1d 100644 --- a/.packcheck.ignore +++ b/.packcheck.ignore @@ -35,6 +35,7 @@ examples/README.md flake.lock flake.nix hie.yaml +hls.yaml packages.nix sources.nix stack.yaml From 1d20bf149962ed1c5c84ec32bd8e05a69d6e60ea Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 09:22:01 +0530 Subject: [PATCH 22/24] Allow inspection-testing dep in nix flake --- sources.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources.nix b/sources.nix index dd04dd631f..e5451776d6 100644 --- a/sources.nix +++ b/sources.nix @@ -6,7 +6,7 @@ layers = [ streamly = local ./.; streamly-core = local ./core; streamly-benchmarks = localOpts ./benchmark - ["--benchmark --flag fusion-plugin"] + ["--benchmark --flag fusion-plugin --flag inspection"] ["--flags fusion-plugin"]; streamly-tests = localOpts ./test ["--flag fusion-plugin"] From ac4e73cbfcf8d93ae8615da35816e2c9c49d2d45 Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 09:23:19 +0530 Subject: [PATCH 23/24] Update inspection-testing dep bound --- benchmark/streamly-benchmarks.cabal | 2 +- streamly.cabal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index 314734e188..ecf6dd6173 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -203,7 +203,7 @@ common bench-depends fusion-plugin >= 0.2 && < 0.3 if flag(inspection) build-depends: template-haskell >= 2.14 && < 2.24 - , inspection-testing >= 0.4 && < 0.6 + , inspection-testing >= 0.4 && < 0.7 -- Array uses a Storable constraint in dev build making several inspection -- tests fail if flag(dev) && flag(inspection) diff --git a/streamly.cabal b/streamly.cabal index 043637e536..4fd77cf1be 100644 --- a/streamly.cabal +++ b/streamly.cabal @@ -583,7 +583,7 @@ library frameworks: Cocoa if flag(inspection) - build-depends: inspection-testing >= 0.4 && < 0.6 + build-depends: inspection-testing >= 0.4 && < 0.7 -- Array uses a Storable constraint in dev build making several inspection -- tests fail From 44817065f3f828c258816a3a0bebf4d52f40319d Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sun, 30 Nov 2025 14:22:07 +0530 Subject: [PATCH 24/24] Fix hlint in StreamK benchmark --- benchmark/Streamly/Benchmark/Data/StreamK.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmark/Streamly/Benchmark/Data/StreamK.hs b/benchmark/Streamly/Benchmark/Data/StreamK.hs index a268cf39eb..8ed72cb441 100644 --- a/benchmark/Streamly/Benchmark/Data/StreamK.hs +++ b/benchmark/Streamly/Benchmark/Data/StreamK.hs @@ -1035,6 +1035,7 @@ o_n_heap_concat streamLen = streamLen2 = round (P.fromIntegral streamLen**(1/2::P.Double)) -- double nested loop +{- HLINT ignore "Use sort" -} o_n_heap_sorting :: Int -> Benchmark o_n_heap_sorting streamLen = bgroup "sorting"