on 4008a26 help sign in
streamly/benchmark/Linear.hs
508 lines 24 kB history raw
1{-# LANGUAGE CPP #-}
2#if __GLASGOW_HASKELL__ >= 800
3{-# OPTIONS_GHC -Wno-orphans #-}
4#endif
6-- |
7-- Module : Main
8-- Copyright : (c) 2018 Harendra Kumar
9--
10-- License : BSD3
11-- Maintainer : streamly@composewell.com
13import Control.DeepSeq (NFData(..), deepseq)
14import Data.Functor.Identity (Identity, runIdentity)
15import Data.Monoid (Last(..))
16import System.Random (randomRIO)
18import Common (parseCLIOpts)
20import qualified GHC.Exts as GHC
21import qualified Streamly.Benchmark.Prelude as Ops
23import Streamly
24import qualified Streamly.Data.Fold as FL
25import qualified Streamly.Memory.Array as A
26import qualified Streamly.Prelude as S
27import qualified Streamly.Internal.Data.Sink as Sink
29import Streamly.Internal.Data.Time.Units
30import qualified Streamly.Internal.Memory.Array as IA
31import qualified Streamly.Internal.Data.Fold as IFL
32import qualified Streamly.Internal.Prelude as IP
33import qualified Streamly.Internal.Data.Pipe as Pipe
35import Gauge
37-------------------------------------------------------------------------------
38--
39-------------------------------------------------------------------------------
41#if !MIN_VERSION_deepseq(1,4,3)
42instance NFData Ordering where rnf = (`seq` ())
43#endif
45-- We need a monadic bind here to make sure that the function f does not get
46-- completely optimized out by the compiler in some cases.
48-- | Takes a fold method, and uses it with a default source.
49{-# INLINE benchIOSink #-}
50benchIOSink
51 :: (IsStream t, NFData b)
52 => Int -> String -> (t IO Int -> IO b) -> Benchmark
53benchIOSink value name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source value
55{-# INLINE benchHoistSink #-}
56benchHoistSink
57 :: (IsStream t, NFData b)
58 => Int -> String -> (t Identity Int -> IO b) -> Benchmark
59benchHoistSink value name f =
60 bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.sourceUnfoldr value
62-- XXX once we convert all the functions to use this we can rename this to
63-- benchIOSink
64{-# INLINE benchIOSink1 #-}
65benchIOSink1 :: NFData b => String -> (Int -> IO b) -> Benchmark
66benchIOSink1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
68-- XXX We should be using sourceUnfoldrM for fair comparison with IO monad, but
69-- we can't use it as it requires MonadAsync constraint.
70{-# INLINE benchIdentitySink #-}
71benchIdentitySink
72 :: (IsStream t, NFData b)
73 => Int -> String -> (t Identity Int -> Identity b) -> Benchmark
74benchIdentitySink value name f = bench name $ nf (f . Ops.sourceUnfoldr value) 1
76-- | Takes a source, and uses it with a default drain/fold method.
77{-# INLINE benchIOSrc #-}
78benchIOSrc
79 :: (t IO a -> SerialT IO a)
80 -> String
81 -> (Int -> t IO a)
82 -> Benchmark
83benchIOSrc t name f =
84 bench name $ nfIO $ randomRIO (1,1) >>= Ops.toNull t . f
86{-# INLINE benchIOSrc1 #-}
87benchIOSrc1 :: String -> (Int -> IO ()) -> Benchmark
88benchIOSrc1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
90{-# INLINE benchPure #-}
91benchPure :: NFData b => String -> (Int -> a) -> (a -> b) -> Benchmark
92benchPure name src f = bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
94{-# INLINE benchPureSink #-}
95benchPureSink :: NFData b => Int -> String -> (SerialT Identity Int -> b) -> Benchmark
96benchPureSink value name f = benchPure name (Ops.sourceUnfoldr value) f
98-- XXX once we convert all the functions to use this we can rename this to
99-- benchPureSink
100{-# INLINE benchPureSink1 #-}
101benchPureSink1 :: NFData b => String -> (Int -> Identity b) -> Benchmark
102benchPureSink1 name f =
103 bench name $ nfIO $ randomRIO (1,1) >>= return . runIdentity . f
105{-# INLINE benchPureSinkIO #-}
106benchPureSinkIO
107 :: NFData b
108 => Int -> String -> (SerialT Identity Int -> IO b) -> Benchmark
109benchPureSinkIO value name f =
110 bench name $ nfIO $ randomRIO (1, 1) >>= f . Ops.sourceUnfoldr value
112{-# INLINE benchPureSrc #-}
113benchPureSrc :: String -> (Int -> SerialT Identity a) -> Benchmark
114benchPureSrc name src = benchPure name src (runIdentity . S.drain)
116mkString :: Int -> String
117mkString value = "fromList [1" ++ concat (replicate value ",1") ++ "]"
119mkListString :: Int -> String
120mkListString value = "[1" ++ concat (replicate value ",1") ++ "]"
122mkList :: Int -> [Int]
123mkList value = [1..value]
125defaultStreamSize :: Int
126defaultStreamSize = 100000
128main :: IO ()
129main = do
130 -- XXX Fix indentation
131 (value, cfg, benches) <- parseCLIOpts defaultStreamSize
132 value `seq` runMode (mode cfg) cfg benches
133 [ bgroup "serially"
134 [ bgroup "pure"
135 [ benchPureSink value "id" id
136 , benchPureSink1 "eqBy" (Ops.eqByPure value)
137 , benchPureSink value "==" Ops.eqInstance
138 , benchPureSink value "/=" Ops.eqInstanceNotEq
139 , benchPureSink1 "cmpBy" (Ops.cmpByPure value)
140 , benchPureSink value "<" Ops.ordInstance
141 , benchPureSink value "min" Ops.ordInstanceMin
142 , benchPureSrc "IsList.fromList" (Ops.sourceIsList value)
143 -- length is used to check for foldr/build fusion
144 , benchPureSink value "length . IsList.toList" (length . GHC.toList)
145 , benchPureSrc "IsString.fromString" (Ops.sourceIsString value)
146 , benchPureSink value "showsPrec pure streams" Ops.showInstance
147 , benchPureSink value "foldl'" Ops.pureFoldl'
148 , benchPureSink value "foldable/foldl'" Ops.foldableFoldl'
149 ]
150 , bgroup "generation"
151 [ -- Most basic, barely stream continuations running
152 benchIOSrc serially "unfoldr" (Ops.sourceUnfoldr value)
153 , benchIOSrc serially "unfoldrM" (Ops.sourceUnfoldrM value)
154 , benchIOSrc serially "intFromTo" (Ops.sourceIntFromTo value)
155 , benchIOSrc serially "intFromThenTo" (Ops.sourceIntFromThenTo value)
156 , benchIOSrc serially "integerFromStep" (Ops.sourceIntegerFromStep value)
157 , benchIOSrc serially "fracFromThenTo" (Ops.sourceFracFromThenTo value)
158 , benchIOSrc serially "fracFromTo" (Ops.sourceFracFromTo value)
159 , benchIOSrc serially "fromList" (Ops.sourceFromList value)
160 , benchIOSrc serially "fromListM" (Ops.sourceFromListM value)
161 -- These are essentially cons and consM
162 , benchIOSrc serially "fromFoldable" (Ops.sourceFromFoldable value)
163 , benchIOSrc serially "fromFoldableM" (Ops.sourceFromFoldableM value)
164 ]
165 , bgroup "elimination"
166 [ bgroup "reduce"
167 [ bgroup "IO"
168 [
169 benchIOSink value "foldl'" Ops.foldl'Reduce
170 , benchIOSink value "foldl1'" Ops.foldl1'Reduce
171 , benchIOSink value "foldlM'" Ops.foldlM'Reduce
172 ]
173 , bgroup "Identity"
174 [
175 benchIdentitySink value "foldl'" Ops.foldl'Reduce
176 , benchIdentitySink value "foldl1'" Ops.foldl1'Reduce
177 , benchIdentitySink value "foldlM'" Ops.foldlM'Reduce
178 ]
179 ]
181 , bgroup "build"
182 [ bgroup "Identity"
183 [ benchIdentitySink value "foldrM" Ops.foldrMBuild
184 ]
185 ]
186 , benchIOSink value "uncons" Ops.uncons
187 , benchIOSink value "toNull" $ Ops.toNull serially
188 , benchIOSink value "mapM_" Ops.mapM_
190 , benchIOSink value "init" Ops.init
192 -- this is too low and causes all benchmarks reported in ns
193 -- , benchIOSink value "head" Ops.head
194 , benchIOSink value "last" Ops.last
195 -- , benchIOSink value "lookup" Ops.lookup
196 , benchIOSink value "find" (Ops.find value)
197 , benchIOSink value "findIndex" (Ops.findIndex value)
198 , benchIOSink value "elemIndex" (Ops.elemIndex value)
200 -- this is too low and causes all benchmarks reported in ns
201 -- , benchIOSink value "null" Ops.null
202 , benchIOSink value "elem" (Ops.elem value)
203 , benchIOSink value "notElem" (Ops.notElem value)
204 , benchIOSink value "all" (Ops.all value)
205 , benchIOSink value "any" (Ops.any value)
206 , benchIOSink value "and" (Ops.and value)
207 , benchIOSink value "or" (Ops.or value)
209 , benchIOSink value "length" Ops.length
210 , benchHoistSink value "length . generally" (Ops.length . IP.generally)
211 , benchIOSink value "sum" Ops.sum
212 , benchIOSink value "product" Ops.product
214 , benchIOSink value "maximumBy" Ops.maximumBy
215 , benchIOSink value "maximum" Ops.maximum
216 , benchIOSink value "minimumBy" Ops.minimumBy
217 , benchIOSink value "minimum" Ops.minimum
219 ]
220 , bgroup "folds"
221 [ benchIOSink value "drain" (S.fold FL.drain)
222 , benchIOSink value "drainN" (S.fold (IFL.drainN value))
223 , benchIOSink value "drainWhileTrue" (S.fold (IFL.drainWhile $ (<=) (value + 1)))
224 , benchIOSink value "drainWhileFalse" (S.fold (IFL.drainWhile $ (>=) (value + 1)))
225 , benchIOSink value "sink" (S.fold $ Sink.toFold Sink.drain)
226 , benchIOSink value "last" (S.fold FL.last)
227 , benchIOSink value "lastN.1" (S.fold (IA.lastN 1))
228 , benchIOSink value "lastN.10" (S.fold (IA.lastN 10))
229 , benchIOSink value "length" (S.fold FL.length)
230 , benchIOSink value "sum" (S.fold FL.sum)
231 , benchIOSink value "product" (S.fold FL.product)
232 , benchIOSink value "maximumBy" (S.fold (FL.maximumBy compare))
233 , benchIOSink value "maximum" (S.fold FL.maximum)
234 , benchIOSink value "minimumBy" (S.fold (FL.minimumBy compare))
235 , benchIOSink value "minimum" (S.fold FL.minimum)
236 , benchIOSink value "mean" (\s -> S.fold FL.mean (S.map (fromIntegral :: Int -> Double) s))
237 , benchIOSink value "variance" (\s -> S.fold FL.variance (S.map (fromIntegral :: Int -> Double) s))
238 , benchIOSink value "stdDev" (\s -> S.fold FL.stdDev (S.map (fromIntegral :: Int -> Double) s))
240 , benchIOSink value "mconcat" (S.fold FL.mconcat . (S.map (Last . Just)))
241 , benchIOSink value "foldMap" (S.fold (FL.foldMap (Last . Just)))
243 , benchIOSink value "index" (S.fold (FL.index (value + 1)))
244 , benchIOSink value "head" (S.fold FL.head)
245 , benchIOSink value "find" (S.fold (FL.find (== (value + 1))))
246 , benchIOSink value "findIndex" (S.fold (FL.findIndex (== (value + 1))))
247 , benchIOSink value "elemIndex" (S.fold (FL.elemIndex (value + 1)))
249 , benchIOSink value "null" (S.fold FL.null)
250 , benchIOSink value "elem" (S.fold (FL.elem (value + 1)))
251 , benchIOSink value "notElem" (S.fold (FL.notElem (value + 1)))
252 , benchIOSink value "all" (S.fold (FL.all (<= (value + 1))))
253 , benchIOSink value "any" (S.fold (FL.any (> (value + 1))))
254 , benchIOSink value "and" (\s -> S.fold FL.and (S.map (<= (value + 1)) s))
255 , benchIOSink value "or" (\s -> S.fold FL.or (S.map (> (value + 1)) s))
256 ]
257 , bgroup "fold-multi-stream"
258 [ benchIOSink1 "eqBy" (Ops.eqBy value)
259 , benchIOSink1 "cmpBy" (Ops.cmpBy value)
260 , benchIOSink value "isPrefixOf" Ops.isPrefixOf
261 , benchIOSink value "isSubsequenceOf" Ops.isSubsequenceOf
262 , benchIOSink value "stripPrefix" Ops.stripPrefix
263 ]
264 , bgroup "folds-transforms"
265 [ benchIOSink value "drain" (S.fold FL.drain)
266 , benchIOSink value "lmap" (S.fold (IFL.lmap (+1) FL.drain))
267 , benchIOSink value "pipe-mapM"
268 (S.fold (IFL.transform (Pipe.mapM (\x -> return $ x + 1)) FL.drain))
269 ]
270 , bgroup "folds-compositions" -- Applicative
271 [
272 benchIOSink value "all,any" (S.fold ((,) <$> FL.all (<= (value + 1))
273 <*> FL.any (> (value + 1))))
274 , benchIOSink value "sum,length" (S.fold ((,) <$> FL.sum <*> FL.length))
275 ]
276 , bgroup "pipes"
277 [ benchIOSink value "mapM" (Ops.transformMapM serially 1)
278 , benchIOSink value "compose" (Ops.transformComposeMapM serially 1)
279 , benchIOSink value "tee" (Ops.transformTeeMapM serially 1)
280 , benchIOSink value "zip" (Ops.transformZipMapM serially 1)
281 ]
282 , bgroup "pipesX4"
283 [ benchIOSink value "mapM" (Ops.transformMapM serially 4)
284 , benchIOSink value "compose" (Ops.transformComposeMapM serially 4)
285 , benchIOSink value "tee" (Ops.transformTeeMapM serially 4)
286 , benchIOSink value "zip" (Ops.transformZipMapM serially 4)
287 ]
288 , bgroup "transformer"
289 [ benchIOSrc serially "evalState" (Ops.evalStateT value)
290 , benchIOSrc serially "withState" (Ops.withState value)
291 ]
292 , bgroup "transformation"
293 [ benchIOSink value "scanl" (Ops.scan 1)
294 , benchIOSink value "scanl1'" (Ops.scanl1' 1)
295 , benchIOSink value "map" (Ops.map 1)
296 , benchIOSink value "fmap" (Ops.fmap 1)
297 , benchIOSink value "mapM" (Ops.mapM serially 1)
298 , benchIOSink value "mapMaybe" (Ops.mapMaybe 1)
299 , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 1)
300 , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
301 Ops.sequence serially (Ops.sourceUnfoldrMAction value n)
302 , benchIOSink value "findIndices" (Ops.findIndices value 1)
303 , benchIOSink value "elemIndices" (Ops.elemIndices value 1)
304 , benchIOSink value "foldrS" (Ops.foldrS 1)
305 , benchIOSink value "foldrSMap" (Ops.foldrSMap 1)
306 , benchIOSink value "foldrT" (Ops.foldrT 1)
307 , benchIOSink value "foldrTMap" (Ops.foldrTMap 1)
308 , benchIOSink value "tap" (Ops.tap 1)
309 , benchIOSink value "tapRate 1 second" (Ops.tapRate 1)
310 , benchIOSink value "pollCounts 1 second" (Ops.pollCounts 1)
311 , benchIOSink value "tapAsync" (Ops.tapAsync 1)
312 , benchIOSink value "tapAsyncS" (Ops.tapAsyncS 1)
313 ]
314 , bgroup "transformationX4"
315 [ benchIOSink value "scan" (Ops.scan 4)
316 , benchIOSink value "scanl1'" (Ops.scanl1' 4)
317 , benchIOSink value "map" (Ops.map 4)
318 , benchIOSink value "fmap" (Ops.fmap 4)
319 , benchIOSink value "mapM" (Ops.mapM serially 4)
320 , benchIOSink value "mapMaybe" (Ops.mapMaybe 4)
321 , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 4)
322 -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
323 -- Ops.sequence serially (Ops.sourceUnfoldrMAction n)
324 , benchIOSink value "findIndices" (Ops.findIndices value 4)
325 , benchIOSink value "elemIndices" (Ops.elemIndices value 4)
326 ]
327 , bgroup "filtering"
328 [ benchIOSink value "filter-even" (Ops.filterEven 1)
329 , benchIOSink value "filter-all-out" (Ops.filterAllOut value 1)
330 , benchIOSink value "filter-all-in" (Ops.filterAllIn value 1)
332 , benchIOSink value "take-all" (Ops.takeAll value 1)
333 , benchIOSink value "takeByTime-all"
334 (Ops.takeByTime (NanoSecond64 maxBound) 1)
335 , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 1)
336 --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 1)
338 -- "drop-one" is dual to "last"
339 , benchIOSink value "drop-one" (Ops.dropOne 1)
340 , benchIOSink value "drop-all" (Ops.dropAll value 1)
341 , benchIOSink value "dropByTime-all"
342 (Ops.dropByTime (NanoSecond64 maxBound) 1)
343 , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 1)
344 --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 1)
345 , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 1)
347 , benchIOSink value "deleteBy" (Ops.deleteBy value 1)
348 , benchIOSink value "intersperse" (Ops.intersperse value 1)
349 , benchIOSink value "insertBy" (Ops.insertBy value 1)
350 ]
351 , bgroup "filteringX4"
352 [ benchIOSink value "filter-even" (Ops.filterEven 4)
353 , benchIOSink value "filter-all-out" (Ops.filterAllOut value 4)
354 , benchIOSink value "filter-all-in" (Ops.filterAllIn value 4)
355 , benchIOSink value "take-all" (Ops.takeAll value 4)
356 , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 4)
357 --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 4)
358 , benchIOSink value "drop-one" (Ops.dropOne 4)
359 , benchIOSink value "drop-all" (Ops.dropAll value 4)
360 , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 4)
361 --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 4)
362 , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 4)
363 , benchIOSink value "deleteBy" (Ops.deleteBy value 4)
364 , benchIOSink value "intersperse" (Ops.intersperse value 4)
365 , benchIOSink value "insertBy" (Ops.insertBy value 4)
366 ]
367 , bgroup "joining"
368 [ benchIOSrc1 "zip (2,x/2)" (Ops.zip (value `div` 2))
369 , benchIOSrc1 "zipM (2,x/2)" (Ops.zipM (value `div` 2))
370 , benchIOSrc1 "mergeBy (2,x/2)" (Ops.mergeBy (value `div` 2))
371 , benchIOSrc1 "serial (2,x/2)" (Ops.serial2 (value `div` 2))
372 , benchIOSrc1 "append (2,x/2)" (Ops.append2 (value `div` 2))
373 , benchIOSrc1 "serial (2,2,x/4)" (Ops.serial4 (value `div` 4))
374 , benchIOSrc1 "append (2,2,x/4)" (Ops.append4 (value `div` 4))
375 , benchIOSrc1 "wSerial (2,x/2)" (Ops.wSerial2 value)
376 , benchIOSrc1 "interleave (2,x/2)" (Ops.interleave2 value)
377 , benchIOSrc1 "roundRobin (2,x/2)" (Ops.roundRobin2 value)
378 ]
379 , bgroup "concat-foldable"
380 [ benchIOSrc serially "foldMapWith" (Ops.sourceFoldMapWith value)
381 , benchIOSrc serially "foldMapWithM" (Ops.sourceFoldMapWithM value)
382 , benchIOSrc serially "foldMapM" (Ops.sourceFoldMapM value)
383 , benchIOSrc serially "foldWithConcatMapId" (Ops.sourceConcatMapId value)
384 ]
385 , bgroup "concat-serial"
386 [ benchIOSrc1 "concatMapPure (2,x/2)" (Ops.concatMapPure 2 (value `div` 2))
387 , benchIOSrc1 "concatMap (2,x/2)" (Ops.concatMap 2 (value `div` 2))
388 , benchIOSrc1 "concatMap (x/2,2)" (Ops.concatMap (value `div` 2) 2)
389 , benchIOSrc1 "concatMapRepl (x/4,4)" (Ops.concatMapRepl4xN value)
390 , benchIOSrc1 "concatUnfoldRepl (x/4,4)" (Ops.concatUnfoldRepl4xN value)
392 , benchIOSrc1 "concatMapWithSerial (2,x/2)"
393 (Ops.concatMapWithSerial 2 (value `div` 2))
394 , benchIOSrc1 "concatMapWithSerial (x/2,2)"
395 (Ops.concatMapWithSerial (value `div` 2) 2)
397 , benchIOSrc1 "concatMapWithAppend (2,x/2)"
398 (Ops.concatMapWithAppend 2 (value `div` 2))
399 ]
400 , bgroup "concat-interleave"
401 [ benchIOSrc1 "concatMapWithWSerial (2,x/2)"
402 (Ops.concatMapWithWSerial 2 (value `div` 2))
403 , benchIOSrc1 "concatMapWithWSerial (x/2,2)"
404 (Ops.concatMapWithWSerial (value `div` 2) 2)
405 ]
406 -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
407 -- library. If scan/fold followed by a map is efficient enough we may not
408 -- need monolithic implementations of these.
409 , bgroup "mixed"
410 [ benchIOSink value "scanl-map" (Ops.scanMap 1)
411 , benchIOSink value "foldl-map" Ops.foldl'ReduceMap
412 , benchIOSink value "sum-product-fold" Ops.sumProductFold
413 , benchIOSink value "sum-product-scan" Ops.sumProductScan
414 ]
415 , bgroup "mixedX4"
416 [ benchIOSink value "scan-map" (Ops.scanMap 4)
417 , benchIOSink value "drop-map" (Ops.dropMap 4)
418 , benchIOSink value "drop-scan" (Ops.dropScan 4)
419 , benchIOSink value "take-drop" (Ops.takeDrop value 4)
420 , benchIOSink value "take-scan" (Ops.takeScan value 4)
421 , benchIOSink value "take-map" (Ops.takeMap value 4)
422 , benchIOSink value "filter-drop" (Ops.filterDrop value 4)
423 , benchIOSink value "filter-take" (Ops.filterTake value 4)
424 , benchIOSink value "filter-scan" (Ops.filterScan 4)
425 , benchIOSink value "filter-scanl1" (Ops.filterScanl1 4)
426 , benchIOSink value "filter-map" (Ops.filterMap value 4)
427 ]
428 , bgroup "iterated"
429 [ benchIOSrc serially "mapM" Ops.iterateMapM
430 , benchIOSrc serially "scan(1/100)" Ops.iterateScan
431 , benchIOSrc serially "scanl1(1/100)" Ops.iterateScanl1
432 , benchIOSrc serially "filterEven" Ops.iterateFilterEven
433 , benchIOSrc serially "takeAll" (Ops.iterateTakeAll value)
434 , benchIOSrc serially "dropOne" Ops.iterateDropOne
435 , benchIOSrc serially "dropWhileFalse" (Ops.iterateDropWhileFalse value)
436 , benchIOSrc serially "dropWhileTrue" (Ops.iterateDropWhileTrue value)
437 ]
438 ]
439 , bgroup "wSerially"
440 [ bgroup "transformation"
441 [ benchIOSink value "fmap" $ Ops.fmap' wSerially 1
442 ]
443 ]
444 , bgroup "zipSerially"
445 [ bgroup "transformation"
446 [ benchIOSink value "fmap" $ Ops.fmap' zipSerially 1
447 ]
448 ]
449 -- Non-streaming operations. We keep these in a spearate group so that we
450 -- can run these conveniently with smaller stream size.
451 --
452 -- These are also the operations that programmers should be aware of and
453 -- should avoid using in a streaming application.
454 , bgroup "buffered"
455 [ -- Inherently non-streaming operations
457 -- Right folds for reducing are inherently non-streaming as the
458 -- expression needs to be fully built before it can be reduced.
459 benchIOSink value "foldrM/reduce/IO" Ops.foldrMReduce
460 , benchIdentitySink value "foldrM/reduce/Identity" Ops.foldrMReduce
462 -- Left folds for building a structure are inherently non-streaming as
463 -- the structure cannot be lazily consumed until fully built.
464 , benchIOSink value "foldl'/build/IO" Ops.foldl'Build
465 , benchIdentitySink value "foldl'/build/Identity" Ops.foldl'Build
466 , benchIOSink value "foldlM'/build/IO" Ops.foldlM'Build
467 , benchIdentitySink value "foldlM'/build/Identity" Ops.foldlM'Build
469 -- accumulation due to strictness of IO monad
470 , benchIOSink value "foldrM/build/IO" Ops.foldrMBuild
471 , benchPureSinkIO value "traversable/mapM" Ops.traversableMapM
473 -- Converting the stream to a list or pure stream
474 , benchIOSink value "toList" Ops.toList
475 , benchIOSink value "toListRev" Ops.toListRev
476 , benchIOSink value "toStream" (S.fold IP.toStream)
477 , benchIOSink value "toStreamRev" (S.fold IP.toStreamRev)
479 , benchIOSink value "folds/toList" (S.fold FL.toList)
480 , benchIOSink value "folds/toListRevF" (S.fold IFL.toListRevF)
482 -- Converting the stream to an array
483 , benchIOSink value "folds/lastN.Max" (S.fold (IA.lastN (value + 1)))
484 , benchIOSink value "folds/writeN" (S.fold (A.writeN value))
486 -- Reversing/sorting a stream
487 , benchIOSink value "reverse" (Ops.reverse 1)
488 , benchIOSink value "reverse'" (Ops.reverse' 1)
490 -- XXX can these be streaming? Can we have special read/show style type
491 -- classes supporting streaming?
492 , mkString value `deepseq` (bench "readsPrec pure streams" $
493 nf Ops.readInstance (mkString value))
494 , mkString value `deepseq` (bench "readsPrec Haskell lists" $
495 nf Ops.readInstanceList (mkListString value))
496 , mkList value `deepseq` (bench "showPrec Haskell lists" $
497 nf Ops.showInstanceList (mkList value))
499 -- XXX streaming operations that can potentially be fixed
500 , benchPureSink value "foldable/sum" Ops.foldableSum
501 , benchIOSink value "tail" Ops.tail
502 , benchIOSink value "nullHeadTail" Ops.nullHeadTail
503 , benchIOSrc1 "concatUnfoldInterleaveRepl (x/4,4)"
504 (Ops.concatUnfoldInterleaveRepl4xN value)
505 , benchIOSrc1 "concatUnfoldRoundrobinRepl (x/4,4)"
506 (Ops.concatUnfoldRoundrobinRepl4xN value)
507 ]
508 ]