@@ -1,600 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−#if __GLASGOW_HASKELL__ >= 800
3−{-# OPTIONS_GHC -Wno-orphans #-}
4−#endif
5−
6−-- |
7−-- Module : Main
8−-- Copyright : (c) 2018 Harendra Kumar
9−--
10−-- License : BSD3
11−-- Maintainer : streamly@composewell.com
12−
13−import Control.DeepSeq (NFData(..))
14−import Control.Monad (when)
15−import Data.Functor.Identity (Identity, runIdentity)
16−import Data.Monoid (Last(..))
17−import System.Random (randomRIO)
18−
19−import Common (parseCLIOpts)
20−
21−import qualified GHC.Exts as GHC
22−import qualified Streamly.Benchmark.Prelude as Ops
23−
24−import Streamly
25−import qualified Streamly.Data.Fold as FL
26−import qualified Streamly.Memory.Array as A
27−import qualified Streamly.Prelude as S
28−import qualified Streamly.Internal.Data.Sink as Sink
29−
30−import Streamly.Internal.Data.Time.Units
31−import qualified Streamly.Internal.Memory.Array as IA
32−import qualified Streamly.Internal.Data.Fold as IFL
33−import qualified Streamly.Internal.Prelude as IP
34−import qualified Streamly.Internal.Data.Pipe as Pipe
35−
36−import Gauge
37−
38−-------------------------------------------------------------------------------
39−--
40−-------------------------------------------------------------------------------
41−
42−#if !MIN_VERSION_deepseq(1,4,3)
43−instance NFData Ordering where rnf = (`seq` ())
44−#endif
45−
46−-- We need a monadic bind here to make sure that the function f does not get
47−-- completely optimized out by the compiler in some cases.
48−
49−-- | Takes a fold method, and uses it with a default source.
50−{-# INLINE benchIOSink #-}
51−benchIOSink
52− :: (IsStream t, NFData b)
53− => Int -> String -> (t IO Int -> IO b) -> Benchmark
54−benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source value
55−
56−{-# INLINE benchHoistSink #-}
57−benchHoistSink
58− :: (IsStream t, NFData b)
59− => Int -> String -> (t Identity Int -> IO b) -> Benchmark
60−benchHoistSink value name f =
61− bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.sourceUnfoldr value
62−
63−-- XXX once we convert all the functions to use this we can rename this to
64−-- benchIOSink
65−{-# INLINE benchIOSink1 #-}
66−benchIOSink1 :: NFData b => String -> (Int -> IO b) -> Benchmark
67−benchIOSink1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
68−
69−-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
70−-- we can't use it as it requires MonadAsync constraint.
71−{-# INLINE benchIdentitySink #-}
72−benchIdentitySink
73− :: (IsStream t, NFData b)
74− => Int -> String -> (t Identity Int -> Identity b) -> Benchmark
75−benchIdentitySink value name f = bench name $ nf (f . Ops.sourceUnfoldr value) 1
76−
77−-- | Takes a source, and uses it with a default drain/fold method.
78−{-# INLINE benchIOSrc #-}
79−benchIOSrc
80− :: (t IO a -> SerialT IO a)
81− -> String
82− -> (Int -> t IO a)
83− -> Benchmark
84−benchIOSrc t name f =
85− bench name $ nfIO $ randomRIO (1,1) >>= Ops.toNull t . f
86−
87−{-# INLINE benchIOSrc1 #-}
88−benchIOSrc1 :: String -> (Int -> IO ()) -> Benchmark
89−benchIOSrc1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
90−
91−{-# INLINE benchPure #-}
92−benchPure :: NFData b => String -> (Int -> a) -> (a -> b) -> Benchmark
93−benchPure name src f = bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
94−
95−{-# INLINE benchPureSink #-}
96−benchPureSink :: NFData b => Int -> String -> (SerialT Identity Int -> b) -> Benchmark
97−benchPureSink value name f = benchPure name (Ops.sourceUnfoldr value) f
98−
99−-- XXX once we convert all the functions to use this we can rename this to
100−-- benchPureSink
101−{-# INLINE benchPureSink1 #-}
102−benchPureSink1 :: NFData b => String -> (Int -> Identity b) -> Benchmark
103−benchPureSink1 name f =
104− bench name $ nfIO $ randomRIO (1,1) >>= return . runIdentity . f
105−
106−{-# INLINE benchPureSinkIO #-}
107−benchPureSinkIO
108− :: NFData b
109− => Int -> String -> (SerialT Identity Int -> IO b) -> Benchmark
110−benchPureSinkIO value name f =
111− bench name $ nfIO $ randomRIO (1, 1) >>= f . Ops.sourceUnfoldr value
112−
113−{-# INLINE benchPureSrc #-}
114−benchPureSrc :: String -> (Int -> SerialT Identity a) -> Benchmark
115−benchPureSrc name src = benchPure name src (runIdentity . S.drain)
116−
117−mkString :: Int -> String
118−mkString value = "fromList [1" ++ concat (replicate value ",1") ++ "]"
119−
120−mkListString :: Int -> String
121−mkListString value = "[1" ++ concat (replicate value ",1") ++ "]"
122−
123−mkList :: Int -> [Int]
124−mkList value = [1..value]
125−
126−defaultStreamSize :: Int
127−defaultStreamSize = 100000
128−
129−main :: IO ()
130−main = do
131− -- XXX Fix indentation
132− (value, cfg, benches) <- parseCLIOpts defaultStreamSize
133− let bufValue = min value defaultStreamSize
134− when (bufValue /= value) $
135− putStrLn $ "Limiting stream size to "
136− ++ show defaultStreamSize
137− ++ " for non O(1) space operations"
138−
139− bufValue `seq` value `seq` runMode (mode cfg) cfg benches
140− -- Operations that can work on infinite streams using constant/O(1) space.
141− [ bgroup "serially"
142− [ bgroup "pure"
143− [ benchPureSink value "id" id
144− , benchPureSink1 "eqBy" (Ops.eqByPure value)
145− , benchPureSink value "==" Ops.eqInstance
146− , benchPureSink value "/=" Ops.eqInstanceNotEq
147− , benchPureSink1 "cmpBy" (Ops.cmpByPure value)
148− , benchPureSink value "<" Ops.ordInstance
149− , benchPureSink value "min" Ops.ordInstanceMin
150− , benchPureSrc "IsList.fromList" (Ops.sourceIsList value)
151− -- length is used to check for foldr/build fusion
152− , benchPureSink value "length . IsList.toList" (length . GHC.toList)
153− , benchPureSrc "IsString.fromString" (Ops.sourceIsString value)
154− , benchPureSink value "showsPrec pure streams" Ops.showInstance
155− , benchPureSink value "foldl'" Ops.pureFoldl'
156− ]
157− , bgroup "foldable"
158− [ -- Foldable instance
159− -- type class operations
160− bench "foldl'" $ nf (Ops.foldableFoldl' value) 1
161− , bench "foldrElem" $ nf (Ops.foldableFoldrElem value) 1
162− -- , bench "null" $ nf (Ops.foldableNull value) 1
163− , bench "elem" $ nf (Ops.foldableElem value) 1
164− , bench "length" $ nf (Ops.foldableLength value) 1
165− , bench "sum" $ nf (Ops.foldableSum value) 1
166− , bench "product" $ nf (Ops.foldableProduct value) 1
167− , bench "minimum" $ nf (Ops.foldableMin value) 1
168− , bench "maximum" $ nf (Ops.foldableMax value) 1
169− , bench "length . toList" $
170− nf (length . Ops.foldableToList value) 1
171−
172− -- folds
173− , bench "notElem" $ nf (Ops.foldableNotElem value) 1
174− , bench "find" $ nf (Ops.foldableFind value) 1
175− , bench "all" $ nf (Ops.foldableAll value) 1
176− , bench "any" $ nf (Ops.foldableAny value) 1
177− , bench "and" $ nf (Ops.foldableAnd value) 1
178− , bench "or" $ nf (Ops.foldableOr value) 1
179−
180− -- Note: minimumBy/maximumBy do not work in constant memory they are in
181− -- the O(n) group of benchmarks down below in this file.
182−
183− -- Applicative and Traversable operations
184− -- TBD: traverse_
185− , benchIOSink1 "mapM_" (Ops.foldableMapM_ value)
186− -- TBD: for_
187− -- TBD: forM_
188− , benchIOSink1 "sequence_" (Ops.foldableSequence_ value)
189− -- TBD: sequenceA_
190− -- TBD: asum
191− -- , benchIOSink1 "msum" (Ops.foldableMsum value)
192− ]
193− , bgroup "generation"
194− [ -- Most basic, barely stream continuations running
195− benchIOSrc serially "unfoldr" (Ops.sourceUnfoldr value)
196− , benchIOSrc serially "unfoldrM" (Ops.sourceUnfoldrM value)
197− , benchIOSrc serially "intFromTo" (Ops.sourceIntFromTo value)
198− , benchIOSrc serially "intFromThenTo" (Ops.sourceIntFromThenTo value)
199− , benchIOSrc serially "integerFromStep" (Ops.sourceIntegerFromStep value)
200− , benchIOSrc serially "fracFromThenTo" (Ops.sourceFracFromThenTo value)
201− , benchIOSrc serially "fracFromTo" (Ops.sourceFracFromTo value)
202− , benchIOSrc serially "fromList" (Ops.sourceFromList value)
203− , benchIOSrc serially "fromListM" (Ops.sourceFromListM value)
204− -- These are essentially cons and consM
205− , benchIOSrc serially "fromFoldable" (Ops.sourceFromFoldable value)
206− , benchIOSrc serially "fromFoldableM" (Ops.sourceFromFoldableM value)
207− , benchIOSrc serially "currentTime/0.00001s"
208− $ Ops.currentTime value 0.00001
209− ]
210− , bgroup "elimination"
211− [ bgroup "reduce"
212− [ bgroup "IO"
213− [
214− benchIOSink value "foldl'" Ops.foldl'Reduce
215− , benchIOSink value "foldl1'" Ops.foldl1'Reduce
216− , benchIOSink value "foldlM'" Ops.foldlM'Reduce
217− ]
218− , bgroup "Identity"
219− [
220− benchIdentitySink value "foldl'" Ops.foldl'Reduce
221− , benchIdentitySink value "foldl1'" Ops.foldl1'Reduce
222− , benchIdentitySink value "foldlM'" Ops.foldlM'Reduce
223− ]
224− ]
225−
226− , bgroup "build"
227− [ bgroup "IO"
228− [ benchIOSink value "foldrMElem" (Ops.foldrMElem value)
229− ]
230− , bgroup "Identity"
231− [ benchIdentitySink value "foldrMElem" (Ops.foldrMElem value)
232− , benchIdentitySink value "foldrMToStreamLength"
233− (S.length . runIdentity . Ops.foldrMToStream)
234− , benchPureSink value "foldrMToListLength"
235− (length . runIdentity . Ops.foldrMBuild)
236− ]
237− ]
238− , benchIOSink value "uncons" Ops.uncons
239− , benchIOSink value "toNull" $ Ops.toNull serially
240− , benchIOSink value "mapM_" Ops.mapM_
241−
242− , benchIOSink value "init" Ops.init
243−
244− -- this is too low and causes all benchmarks reported in ns
245− -- , benchIOSink value "head" Ops.head
246− , benchIOSink value "last" Ops.last
247− -- , benchIOSink value "lookup" Ops.lookup
248− , benchIOSink value "find" (Ops.find value)
249− , benchIOSink value "findIndex" (Ops.findIndex value)
250− , benchIOSink value "elemIndex" (Ops.elemIndex value)
251−
252− -- this is too low and causes all benchmarks reported in ns
253− -- , benchIOSink value "null" Ops.null
254− , benchIOSink value "elem" (Ops.elem value)
255− , benchIOSink value "notElem" (Ops.notElem value)
256− , benchIOSink value "all" (Ops.all value)
257− , benchIOSink value "any" (Ops.any value)
258− , benchIOSink value "and" (Ops.and value)
259− , benchIOSink value "or" (Ops.or value)
260−
261− , benchIOSink value "length" Ops.length
262− , benchHoistSink value "length . generally" (Ops.length . IP.generally)
263− , benchIOSink value "sum" Ops.sum
264− , benchIOSink value "product" Ops.product
265−
266− , benchIOSink value "maximumBy" Ops.maximumBy
267− , benchIOSink value "maximum" Ops.maximum
268− , benchIOSink value "minimumBy" Ops.minimumBy
269− , benchIOSink value "minimum" Ops.minimum
270−
271− ]
272− , bgroup "folds"
273− [ benchIOSink value "drain" (S.fold FL.drain)
274− , benchIOSink value "drainN" (S.fold (IFL.drainN value))
275− , benchIOSink value "drainWhileTrue" (S.fold (IFL.drainWhile $ (<=) (value + 1)))
276− , benchIOSink value "drainWhileFalse" (S.fold (IFL.drainWhile $ (>=) (value + 1)))
277− , benchIOSink value "sink" (S.fold $ Sink.toFold Sink.drain)
278− , benchIOSink value "last" (S.fold FL.last)
279− , benchIOSink value "lastN.1" (S.fold (IA.lastN 1))
280− , benchIOSink value "lastN.10" (S.fold (IA.lastN 10))
281− , benchIOSink value "length" (S.fold FL.length)
282− , benchIOSink value "sum" (S.fold FL.sum)
283− , benchIOSink value "product" (S.fold FL.product)
284− , benchIOSink value "maximumBy" (S.fold (FL.maximumBy compare))
285− , benchIOSink value "maximum" (S.fold FL.maximum)
286− , benchIOSink value "minimumBy" (S.fold (FL.minimumBy compare))
287− , benchIOSink value "minimum" (S.fold FL.minimum)
288− , benchIOSink value "mean" (\s -> S.fold FL.mean (S.map (fromIntegral :: Int -> Double) s))
289− , benchIOSink value "variance" (\s -> S.fold FL.variance (S.map (fromIntegral :: Int -> Double) s))
290− , benchIOSink value "stdDev" (\s -> S.fold FL.stdDev (S.map (fromIntegral :: Int -> Double) s))
291−
292− , benchIOSink value "mconcat" (S.fold FL.mconcat . (S.map (Last . Just)))
293− , benchIOSink value "foldMap" (S.fold (FL.foldMap (Last . Just)))
294−
295− , benchIOSink value "index" (S.fold (FL.index (value + 1)))
296− , benchIOSink value "head" (S.fold FL.head)
297− , benchIOSink value "find" (S.fold (FL.find (== (value + 1))))
298− , benchIOSink value "findIndex" (S.fold (FL.findIndex (== (value + 1))))
299− , benchIOSink value "elemIndex" (S.fold (FL.elemIndex (value + 1)))
300−
301− , benchIOSink value "null" (S.fold FL.null)
302− , benchIOSink value "elem" (S.fold (FL.elem (value + 1)))
303− , benchIOSink value "notElem" (S.fold (FL.notElem (value + 1)))
304− , benchIOSink value "all" (S.fold (FL.all (<= (value + 1))))
305− , benchIOSink value "any" (S.fold (FL.any (> (value + 1))))
306− , benchIOSink value "and" (\s -> S.fold FL.and (S.map (<= (value + 1)) s))
307− , benchIOSink value "or" (\s -> S.fold FL.or (S.map (> (value + 1)) s))
308− ]
309− , bgroup "fold-multi-stream"
310− [ benchIOSink1 "eqBy" (Ops.eqBy value)
311− , benchIOSink1 "cmpBy" (Ops.cmpBy value)
312− , benchIOSink value "isPrefixOf" Ops.isPrefixOf
313− , benchIOSink value "isSubsequenceOf" Ops.isSubsequenceOf
314− , benchIOSink value "stripPrefix" Ops.stripPrefix
315− ]
316− , bgroup "folds-transforms"
317− [ benchIOSink value "drain" (S.fold FL.drain)
318− , benchIOSink value "lmap" (S.fold (IFL.lmap (+1) FL.drain))
319− , benchIOSink value "pipe-mapM"
320− (S.fold (IFL.transform (Pipe.mapM (\x -> return $ x + 1)) FL.drain))
321− ]
322− , bgroup "folds-compositions" -- Applicative
323− [
324− benchIOSink value "all,any" (S.fold ((,) <$> FL.all (<= (value + 1))
325− <*> FL.any (> (value + 1))))
326− , benchIOSink value "sum,length" (S.fold ((,) <$> FL.sum <*> FL.length))
327− ]
328− , bgroup "pipes"
329− [ benchIOSink value "mapM" (Ops.transformMapM serially 1)
330− , benchIOSink value "compose" (Ops.transformComposeMapM serially 1)
331− , benchIOSink value "tee" (Ops.transformTeeMapM serially 1)
332− , benchIOSink value "zip" (Ops.transformZipMapM serially 1)
333− ]
334− , bgroup "pipesX4"
335− [ benchIOSink value "mapM" (Ops.transformMapM serially 4)
336− , benchIOSink value "compose" (Ops.transformComposeMapM serially 4)
337− , benchIOSink value "tee" (Ops.transformTeeMapM serially 4)
338− , benchIOSink value "zip" (Ops.transformZipMapM serially 4)
339− ]
340− , bgroup "transformer"
341− [ benchIOSrc serially "evalState" (Ops.evalStateT value)
342− , benchIOSrc serially "withState" (Ops.withState value)
343− ]
344− , bgroup "transformation"
345− [ benchIOSink value "scanl" (Ops.scan 1)
346− , benchIOSink value "scanl1'" (Ops.scanl1' 1)
347− , benchIOSink value "map" (Ops.map 1)
348− , benchIOSink value "fmap" (Ops.fmap 1)
349− , benchIOSink value "mapM" (Ops.mapM serially 1)
350− , benchIOSink value "mapMaybe" (Ops.mapMaybe 1)
351− , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 1)
352− , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
353− Ops.sequence serially (Ops.sourceUnfoldrMAction value n)
354− , benchIOSink value "findIndices" (Ops.findIndices value 1)
355− , benchIOSink value "elemIndices" (Ops.elemIndices value 1)
356− , benchIOSink value "foldrS" (Ops.foldrS 1)
357− , benchIOSink value "foldrSMap" (Ops.foldrSMap 1)
358− , benchIOSink value "foldrT" (Ops.foldrT 1)
359− , benchIOSink value "foldrTMap" (Ops.foldrTMap 1)
360− , benchIOSink value "tap" (Ops.tap 1)
361− , benchIOSink value "tapRate 1 second" (Ops.tapRate 1)
362− , benchIOSink value "pollCounts 1 second" (Ops.pollCounts 1)
363− , benchIOSink value "tapAsync" (Ops.tapAsync 1)
364− , benchIOSink value "tapAsyncS" (Ops.tapAsyncS 1)
365− ]
366− , bgroup "transformationX4"
367− [ benchIOSink value "scan" (Ops.scan 4)
368− , benchIOSink value "scanl1'" (Ops.scanl1' 4)
369− , benchIOSink value "map" (Ops.map 4)
370− , benchIOSink value "fmap" (Ops.fmap 4)
371− , benchIOSink value "mapM" (Ops.mapM serially 4)
372− , benchIOSink value "mapMaybe" (Ops.mapMaybe 4)
373− , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 4)
374− -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
375− -- Ops.sequence serially (Ops.sourceUnfoldrMAction n)
376− , benchIOSink value "findIndices" (Ops.findIndices value 4)
377− , benchIOSink value "elemIndices" (Ops.elemIndices value 4)
378− ]
379− , bgroup "filtering"
380− [ benchIOSink value "filter-even" (Ops.filterEven 1)
381− , benchIOSink value "filter-all-out" (Ops.filterAllOut value 1)
382− , benchIOSink value "filter-all-in" (Ops.filterAllIn value 1)
383−
384− , benchIOSink value "take-all" (Ops.takeAll value 1)
385− , benchIOSink value "takeByTime-all"
386− (Ops.takeByTime (NanoSecond64 maxBound) 1)
387− , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 1)
388− --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 1)
389−
390− -- "drop-one" is dual to "last"
391− , benchIOSink value "drop-one" (Ops.dropOne 1)
392− , benchIOSink value "drop-all" (Ops.dropAll value 1)
393− , benchIOSink value "dropByTime-all"
394− (Ops.dropByTime (NanoSecond64 maxBound) 1)
395− , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 1)
396− --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 1)
397− , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 1)
398−
399− , benchIOSink value "deleteBy" (Ops.deleteBy value 1)
400− , benchIOSink value "intersperse" (Ops.intersperse value 1)
401− , benchIOSink value "insertBy" (Ops.insertBy value 1)
402− ]
403− , bgroup "filteringX4"
404− [ benchIOSink value "filter-even" (Ops.filterEven 4)
405− , benchIOSink value "filter-all-out" (Ops.filterAllOut value 4)
406− , benchIOSink value "filter-all-in" (Ops.filterAllIn value 4)
407− , benchIOSink value "take-all" (Ops.takeAll value 4)
408− , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 4)
409− --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 4)
410− , benchIOSink value "drop-one" (Ops.dropOne 4)
411− , benchIOSink value "drop-all" (Ops.dropAll value 4)
412− , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 4)
413− --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 4)
414− , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 4)
415− , benchIOSink value "deleteBy" (Ops.deleteBy value 4)
416− , benchIOSink value "intersperse" (Ops.intersperse value 4)
417− , benchIOSink value "insertBy" (Ops.insertBy value 4)
418− ]
419− , bgroup "joining"
420− [ benchIOSrc1 "zip (2,x/2)" (Ops.zip (value `div` 2))
421− , benchIOSrc1 "zipM (2,x/2)" (Ops.zipM (value `div` 2))
422− , benchIOSrc1 "mergeBy (2,x/2)" (Ops.mergeBy (value `div` 2))
423− , benchIOSrc1 "serial (2,x/2)" (Ops.serial2 (value `div` 2))
424− , benchIOSrc1 "append (2,x/2)" (Ops.append2 (value `div` 2))
425− , benchIOSrc1 "serial (2,2,x/4)" (Ops.serial4 (value `div` 4))
426− , benchIOSrc1 "append (2,2,x/4)" (Ops.append4 (value `div` 4))
427− , benchIOSrc1 "wSerial (2,x/2)" (Ops.wSerial2 value)
428− , benchIOSrc1 "interleave (2,x/2)" (Ops.interleave2 value)
429− , benchIOSrc1 "roundRobin (2,x/2)" (Ops.roundRobin2 value)
430− ]
431− , bgroup "concat-foldable"
432− [ benchIOSrc serially "foldMapWith" (Ops.sourceFoldMapWith value)
433− , benchIOSrc serially "foldMapWithM" (Ops.sourceFoldMapWithM value)
434− , benchIOSrc serially "foldMapM" (Ops.sourceFoldMapM value)
435− , benchIOSrc serially "foldWithConcatMapId" (Ops.sourceConcatMapId value)
436− ]
437− , bgroup "concat-serial"
438− [ benchIOSrc1 "concatMapPure (2,x/2)" (Ops.concatMapPure 2 (value `div` 2))
439− , benchIOSrc1 "concatMap (2,x/2)" (Ops.concatMap 2 (value `div` 2))
440− , benchIOSrc1 "concatMap (x/2,2)" (Ops.concatMap (value `div` 2) 2)
441− , benchIOSrc1 "concatMapRepl (x/4,4)" (Ops.concatMapRepl4xN value)
442− , benchIOSrc1 "concatUnfoldRepl (x/4,4)" (Ops.concatUnfoldRepl4xN value)
443−
444− , benchIOSrc1 "concatMapWithSerial (2,x/2)"
445− (Ops.concatMapWithSerial 2 (value `div` 2))
446− , benchIOSrc1 "concatMapWithSerial (x/2,2)"
447− (Ops.concatMapWithSerial (value `div` 2) 2)
448−
449− , benchIOSrc1 "concatMapWithAppend (2,x/2)"
450− (Ops.concatMapWithAppend 2 (value `div` 2))
451− ]
452− , bgroup "concat-interleave"
453− [ benchIOSrc1 "concatMapWithWSerial (2,x/2)"
454− (Ops.concatMapWithWSerial 2 (value `div` 2))
455− , benchIOSrc1 "concatMapWithWSerial (x/2,2)"
456− (Ops.concatMapWithWSerial (value `div` 2) 2)
457− ]
458− -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
459− -- library. If scan/fold followed by a map is efficient enough we may not
460− -- need monolithic implementations of these.
461− , bgroup "mixed"
462− [ benchIOSink value "scanl-map" (Ops.scanMap 1)
463− , benchIOSink value "foldl-map" Ops.foldl'ReduceMap
464− , benchIOSink value "sum-product-fold" Ops.sumProductFold
465− , benchIOSink value "sum-product-scan" Ops.sumProductScan
466− ]
467− , bgroup "mixedX4"
468− [ benchIOSink value "scan-map" (Ops.scanMap 4)
469− , benchIOSink value "drop-map" (Ops.dropMap 4)
470− , benchIOSink value "drop-scan" (Ops.dropScan 4)
471− , benchIOSink value "take-drop" (Ops.takeDrop value 4)
472− , benchIOSink value "take-scan" (Ops.takeScan value 4)
473− , benchIOSink value "take-map" (Ops.takeMap value 4)
474− , benchIOSink value "filter-drop" (Ops.filterDrop value 4)
475− , benchIOSink value "filter-take" (Ops.filterTake value 4)
476− , benchIOSink value "filter-scan" (Ops.filterScan 4)
477− , benchIOSink value "filter-scanl1" (Ops.filterScanl1 4)
478− , benchIOSink value "filter-map" (Ops.filterMap value 4)
479− ]
480− ]
481− , bgroup "wSerially"
482− [ bgroup "transformation"
483− [ benchIOSink value "fmap" $ Ops.fmap' wSerially 1
484− ]
485− ]
486− , bgroup "zipSerially"
487− [ bgroup "transformation"
488− [ benchIOSink value "fmap" $ Ops.fmap' zipSerially 1
489− ]
490− ]
491− -- Operations that cannot work on infinite streams.
492− --
493− -- We keep these in a spearate group so that we
494− -- can run these conveniently with smaller stream size.
495− --
496− -- These are also the operations that programmers should be aware of and
497− -- should avoid using in a streaming application.
498−
499− -- Operations using O(n) stack space but O(1) heap space.
500− -- Head recursive operations.
501− , bgroup "iterated"
502− [ benchIOSrc serially "mapMx10K" Ops.iterateMapM
503− , benchIOSrc serially "scanx100" Ops.iterateScan
504− , benchIOSrc serially "scanl1x100" Ops.iterateScanl1
505− , benchIOSrc serially "filterEvenx10K" Ops.iterateFilterEven
506− , benchIOSrc serially "takeAllx10K" (Ops.iterateTakeAll value)
507− , benchIOSrc serially "dropOnex10K" Ops.iterateDropOne
508− , benchIOSrc serially "dropWhileFalsex10K"
509− (Ops.iterateDropWhileFalse value)
510− , benchIOSrc serially "dropWhileTruex10K"
511− (Ops.iterateDropWhileTrue value)
512−
513− , benchIOSink bufValue "tail" Ops.tail
514− , benchIOSink bufValue "nullHeadTail" Ops.nullHeadTail
515− ]
516− -- Head recursive strict right folds.
517− , bgroup "foldr"
518− [
519− -- Right folds for reducing are inherently non-streaming as the
520− -- expression needs to be fully built before it can be reduced.
521− benchIOSink bufValue "foldrM/reduce/IO" Ops.foldrMReduce
522− , benchIdentitySink bufValue "foldrM/reduce/Identity" Ops.foldrMReduce
523−
524− -- accumulation due to strictness of IO monad
525− , benchIOSink bufValue "foldrM/build/IO" Ops.foldrMBuild
526− ]
527− -- Operations using O(1) stack space and O(n) heap space.
528− -- Tail recursive left folds
529− , bgroup "foldl"
530− [
531− -- Left folds for building a structure are inherently non-streaming as
532− -- the structure cannot be lazily consumed until fully built.
533− benchIOSink bufValue "foldl'/build/IO" Ops.foldl'Build
534− , benchIdentitySink bufValue "foldl'/build/Identity" Ops.foldl'Build
535− , benchIOSink bufValue "foldlM'/build/IO" Ops.foldlM'Build
536− , benchIdentitySink bufValue "foldlM'/build/Identity" Ops.foldlM'Build
537−
538− , benchIOSink bufValue "toStream" (S.fold IP.toStream)
539− , benchIOSink bufValue "toStreamRev" (S.fold IP.toStreamRev)
540−
541− , benchIOSink bufValue "toList" (S.fold FL.toList)
542− , benchIOSink bufValue "toListRevF" (S.fold IFL.toListRevF)
543−
544− -- Converting the stream to an array
545− , benchIOSink bufValue "lastN.Max" (S.fold (IA.lastN (bufValue + 1)))
546− , benchIOSink bufValue "writeN" (S.fold (A.writeN bufValue))
547−
548− -- Reversing/sorting a stream
549− , benchIOSink bufValue "reverse" (Ops.reverse 1)
550− , benchIOSink bufValue "reverse'" (Ops.reverse' 1)
551−
552− -- XXX the definitions of minimumBy and maximumBy in Data.Foldable use
553− -- foldl1 which does not work in constant memory for our implementation.
554− -- It works in constant memory for lists but even for lists it takes 15x
555− -- more time compared to our foldl' based implementation.
556− , bench "minimumBy" $ nf (flip Ops.foldableMinBy 1) value
557− , bench "maximumBy" $ nf (flip Ops.foldableMaxBy 1) value
558− , bench "minimumByList" $ nf (flip Ops.foldableListMinBy 1) value
559− ]
560−
561− -- Buffering operations using heap proportional to number of elements.
562− , bgroup "traversable"
563− [ -- Traversable instance
564− benchPureSinkIO bufValue "traverse" Ops.traversableTraverse
565− , benchPureSinkIO bufValue "sequenceA" Ops.traversableSequenceA
566− , benchPureSinkIO bufValue "mapM" Ops.traversableMapM
567− , benchPureSinkIO bufValue "sequence" Ops.traversableSequence
568− ]
569− , bgroup "buffering"
570− [
571− -- Buffers the output of show/read.
572− -- XXX can the outputs be streaming? Can we have special read/show
573− -- style type classes, readM/showM supporting streaming effects?
574− bench "readsPrec pure streams" $
575− nf Ops.readInstance (mkString bufValue)
576− , bench "readsPrec Haskell lists" $
577− nf Ops.readInstanceList (mkListString bufValue)
578− , bench "showPrec Haskell lists" $
579− nf Ops.showInstanceList (mkList bufValue)
580−
581− -- interleave x/4 streams of 4 elements each. Needs to buffer
582− -- proportional to x/4. This is different from WSerial because WSerial
583− -- expands slowly because of binary interleave behavior and this expands
584− -- immediately because of Nary interleave behavior.
585− , benchIOSrc1 "concatUnfoldInterleaveRepl (x/4,4)"
586− (Ops.concatUnfoldInterleaveRepl4xN bufValue)
587− , benchIOSrc1 "concatUnfoldRoundrobinRepl (x/4,4)"
588− (Ops.concatUnfoldRoundrobinRepl4xN bufValue)
589− ]
590− -- Both heap and stack space are O(n)
591− , bgroup "toList"
592− [
593− -- Converting the stream to a list or pure stream in a strict monad
594− benchIOSink bufValue "foldrMToList" Ops.foldrMBuild
595− , benchIOSink bufValue "toList" Ops.toList
596− , benchIOSink bufValue "toListRev" Ops.toListRev
597− -- , benchIOSink bufValue "toPure" Ops.toPure
598− -- , benchIOSink bufValue "toPureRev" Ops.toPureRev
599− ]
600− ]