on master help sign in
Add detailed benchmarks for folds
7d577a4Harendra Kumar
benchmark/Linear.hs+40−5
@@ -26,6 +26,14 @@ benchIOSink
26 => String -> (t IO Int -> IO b) -> Benchmark
26 => String -> (t IO Int -> IO b) -> Benchmark
27benchIOSink name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source
27benchIOSink name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source
28
28
29+-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
30+-- we can't use it as it requires MonadAsync constraint.
31+{-# INLINE benchIdentitySink #-}
32+benchIdentitySink
33+ :: (IsStream t, NFData b)
34+ => String -> (t Identity Int -> Identity b) -> Benchmark
35+benchIdentitySink name f = bench name $ nf (f . Ops.sourceUnfoldr) 1
36+
29-- | Takes a source, and uses it with a default drain/fold method.
37-- | Takes a source, and uses it with a default drain/fold method.
30{-# INLINE benchIOSrc #-}
38{-# INLINE benchIOSrc #-}
31benchIOSrc
39benchIOSrc
@@ -107,11 +115,38 @@ main =
107 , benchIOSink "nullHeadTail" Ops.nullHeadTail
115 , benchIOSink "nullHeadTail" Ops.nullHeadTail
108 , benchIOSink "mapM_" Ops.mapM_
116 , benchIOSink "mapM_" Ops.mapM_
109 , benchIOSink "toList" Ops.toList
117 , benchIOSink "toList" Ops.toList
118+
119+ , bgroup "reduce"
120+ [ bgroup "IO"
110− , benchIOSink "foldr" Ops.foldr
121+ [ benchIOSink "foldr" Ops.foldrReduce
111− , benchIOSink "foldr1" Ops.foldr1
122+ , benchIOSink "foldr1" Ops.foldr1Reduce
123+ , benchIOSink "foldl'" Ops.foldl'Reduce
124+ , benchIOSink "foldl1'" Ops.foldl1'Reduce
125+ , benchIOSink "foldlM'" Ops.foldlM'Reduce
126+ ]
127+ , bgroup "Identity"
128+ [ benchIdentitySink "foldr" Ops.foldrReduce
129+ , benchIdentitySink "foldr1" Ops.foldr1Reduce
130+ , benchIdentitySink "foldl'" Ops.foldl'Reduce
131+ , benchIdentitySink "foldl1'" Ops.foldl1'Reduce
132+ , benchIdentitySink "foldlM'" Ops.foldlM'Reduce
133+ ]
134+ ]
135+
136+ , bgroup "build"
137+ [ bgroup "IO"
138+ [ benchIOSink "foldr" Ops.foldrBuild
112− , benchIOSink "foldrM" Ops.foldrM
139+ , benchIOSink "foldrM" Ops.foldrMBuild
113− , benchIOSink "foldl'" Ops.foldl'
140+ , benchIOSink "foldl'" Ops.foldl'Build
114− , benchIOSink "foldl1'" Ops.foldl1'
141+ , benchIOSink "foldlM'" Ops.foldlM'Build
142+ ]
143+ , bgroup "Identity"
144+ [ benchIdentitySink "foldr" Ops.foldrBuild
145+ , benchIdentitySink "foldrM" Ops.foldrMBuild
146+ , benchIdentitySink "foldl'" Ops.foldl'Build
147+ , benchIdentitySink "foldlM'" Ops.foldlM'Build
148+ ]
149+ ]
115
150
116 , benchIOSink "last" Ops.last
151 , benchIOSink "last" Ops.last
117 , benchIOSink "length" Ops.length
152 , benchIOSink "length" Ops.length
benchmark/LinearOps.hs+31−13
@@ -19,7 +19,8 @@ import Data.Maybe (fromJust)
19import Prelude
19import Prelude
20 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (>=),
20 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (>=),
21 subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
21 subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
22− maxBound, div, IO, compare, Double, fromIntegral, Integer, (<$>), (<*>))
22+ maxBound, div, IO, compare, Double, fromIntegral, Integer, (<$>),
23+ (<*>), flip)
23import qualified Prelude as P
24import qualified Prelude as P
24import qualified Data.Foldable as F
25import qualified Data.Foldable as F
25import qualified GHC.Exts as GHC
26import qualified GHC.Exts as GHC
@@ -170,22 +171,32 @@ toList :: Monad m => Stream m Int -> m [Int]
170{-# INLINE find #-}
171{-# INLINE find #-}
171{-# INLINE findIndex #-}
172{-# INLINE findIndex #-}
172{-# INLINE elemIndex #-}
173{-# INLINE elemIndex #-}
173−{-# INLINE foldl1' #-}
174+{-# INLINE foldl1'Reduce #-}
174−{-# INLINE foldr1 #-}
175+{-# INLINE foldr1Reduce #-}
175−last, minimum, maximum, find, findIndex, elemIndex, foldl1', foldr1
176+last, minimum, maximum, find, findIndex, elemIndex, foldl1'Reduce, foldr1Reduce
176 :: Monad m => Stream m Int -> m (Maybe Int)
177 :: Monad m => Stream m Int -> m (Maybe Int)
177
178
178{-# INLINE minimumBy #-}
179{-# INLINE minimumBy #-}
179{-# INLINE maximumBy #-}
180{-# INLINE maximumBy #-}
180minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
181minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
181
182
182−{-# INLINE foldl' #-}
183+{-# INLINE foldl'Reduce #-}
183−{-# INLINE foldr #-}
184+{-# INLINE foldlM'Reduce #-}
184−{-# INLINE foldrM #-}
185+{-# INLINE foldrReduce #-}
185{-# INLINE length #-}
186{-# INLINE length #-}
186{-# INLINE sum #-}
187{-# INLINE sum #-}
187{-# INLINE product #-}
188{-# INLINE product #-}
189+foldl'Reduce, foldlM'Reduce, foldrReduce, length, sum, product
190+ :: Monad m
191+ => Stream m Int -> m Int
192+
193+{-# INLINE foldl'Build #-}
194+{-# INLINE foldlM'Build #-}
195+{-# INLINE foldrBuild #-}
196+{-# INLINE foldrMBuild #-}
197+foldrBuild, foldrMBuild, foldl'Build, foldlM'Build
198+ :: Monad m
188−foldl', foldr, foldrM, length, sum, product :: Monad m => Stream m Int -> m Int
199+ => Stream m Int -> m [Int]
189
200
190{-# INLINE all #-}
201{-# INLINE all #-}
191{-# INLINE any #-}
202{-# INLINE any #-}
@@ -228,11 +239,18 @@ mapM_ :: Monad m => Stream m Int -> m ()
228mapM_ = S.mapM_ (\_ -> return ())
239mapM_ = S.mapM_ (\_ -> return ())
229
240
230toList = S.toList
241toList = S.toList
242+
243+foldl'Build = S.foldl' (flip (:)) []
231−foldr = S.foldr (+) 0
244+foldrBuild = S.foldr (:) []
232−foldr1 = S.foldr1 (+)
245+foldlM'Build = S.foldlM' (\xs x -> return $ x : xs) []
233−foldrM = S.foldrM (\a xs -> return $ a + xs) 0
246+foldrMBuild = S.foldrM (\x xs -> return $ x : xs) []
247+
248+foldrReduce = S.foldr (+) 0
249+foldr1Reduce = S.foldr1 (+)
234−foldl' = S.foldl' (+) 0
250+foldl'Reduce = S.foldl' (+) 0
235−foldl1' = S.foldl1' (+)
251+foldl1'Reduce = S.foldl1' (+)
252+foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
253+
236last = S.last
254last = S.last
237elem = S.elem maxValue
255elem = S.elem maxValue
238notElem = S.notElem maxValue
256notElem = S.notElem maxValue
src/Streamly/Prelude.hs+5
@@ -809,6 +809,9 @@ foldrM = P.foldrM
809foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
809foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
810foldr = P.foldr
810foldr = P.foldr
811
811
812+-- XXX This seems to be of limited use as it cannot be used to construct
813+-- recursive structures and for reduction foldl1' is better.
814+--
812-- | Lazy right fold for non-empty streams, using first element as the starting
815-- | Lazy right fold for non-empty streams, using first element as the starting
813-- value. Returns 'Nothing' if the stream is empty.
816-- value. Returns 'Nothing' if the stream is empty.
814--
817--
@@ -927,6 +930,7 @@ foldl1' step m = do
927-- | Like 'foldx', but with a monadic step function.
930-- | Like 'foldx', but with a monadic step function.
928--
931--
929-- @since 0.2.0
932-- @since 0.2.0
933+{-# INLINE foldxM #-}
930foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
934foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
931foldxM = K.foldxM
935foldxM = K.foldxM
932
936
@@ -939,6 +943,7 @@ foldlM = foldxM
939-- | Like 'foldl'' but with a monadic step function.
943-- | Like 'foldl'' but with a monadic step function.
940--
944--
941-- @since 0.2.0
945-- @since 0.2.0
946+{-# INLINE foldlM' #-}
942foldlM' :: Monad m => (b -> a -> m b) -> b -> SerialT m a -> m b
947foldlM' :: Monad m => (b -> a -> m b) -> b -> SerialT m a -> m b
943foldlM' step begin m = S.foldlM' step begin $ toStreamS m
948foldlM' step begin m = S.foldlM' step begin $ toStreamS m
944
949