on 3be5560 help sign in
streamly/benchmark/Linear.hs
510 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 , benchIOSrc serially "currentTime/0.00001s"
165 $ Ops.currentTime value 0.00001
166 ]
167 , bgroup "elimination"
168 [ bgroup "reduce"
169 [ bgroup "IO"
170 [
171 benchIOSink value "foldl'" Ops.foldl'Reduce
172 , benchIOSink value "foldl1'" Ops.foldl1'Reduce
173 , benchIOSink value "foldlM'" Ops.foldlM'Reduce
174 ]
175 , bgroup "Identity"
176 [
177 benchIdentitySink value "foldl'" Ops.foldl'Reduce
178 , benchIdentitySink value "foldl1'" Ops.foldl1'Reduce
179 , benchIdentitySink value "foldlM'" Ops.foldlM'Reduce
180 ]
181 ]
183 , bgroup "build"
184 [ bgroup "Identity"
185 [ benchIdentitySink value "foldrM" Ops.foldrMBuild
186 ]
187 ]
188 , benchIOSink value "uncons" Ops.uncons
189 , benchIOSink value "toNull" $ Ops.toNull serially
190 , benchIOSink value "mapM_" Ops.mapM_
192 , benchIOSink value "init" Ops.init
194 -- this is too low and causes all benchmarks reported in ns
195 -- , benchIOSink value "head" Ops.head
196 , benchIOSink value "last" Ops.last
197 -- , benchIOSink value "lookup" Ops.lookup
198 , benchIOSink value "find" (Ops.find value)
199 , benchIOSink value "findIndex" (Ops.findIndex value)
200 , benchIOSink value "elemIndex" (Ops.elemIndex value)
202 -- this is too low and causes all benchmarks reported in ns
203 -- , benchIOSink value "null" Ops.null
204 , benchIOSink value "elem" (Ops.elem value)
205 , benchIOSink value "notElem" (Ops.notElem value)
206 , benchIOSink value "all" (Ops.all value)
207 , benchIOSink value "any" (Ops.any value)
208 , benchIOSink value "and" (Ops.and value)
209 , benchIOSink value "or" (Ops.or value)
211 , benchIOSink value "length" Ops.length
212 , benchHoistSink value "length . generally" (Ops.length . IP.generally)
213 , benchIOSink value "sum" Ops.sum
214 , benchIOSink value "product" Ops.product
216 , benchIOSink value "maximumBy" Ops.maximumBy
217 , benchIOSink value "maximum" Ops.maximum
218 , benchIOSink value "minimumBy" Ops.minimumBy
219 , benchIOSink value "minimum" Ops.minimum
221 ]
222 , bgroup "folds"
223 [ benchIOSink value "drain" (S.fold FL.drain)
224 , benchIOSink value "drainN" (S.fold (IFL.drainN value))
225 , benchIOSink value "drainWhileTrue" (S.fold (IFL.drainWhile $ (<=) (value + 1)))
226 , benchIOSink value "drainWhileFalse" (S.fold (IFL.drainWhile $ (>=) (value + 1)))
227 , benchIOSink value "sink" (S.fold $ Sink.toFold Sink.drain)
228 , benchIOSink value "last" (S.fold FL.last)
229 , benchIOSink value "lastN.1" (S.fold (IA.lastN 1))
230 , benchIOSink value "lastN.10" (S.fold (IA.lastN 10))
231 , benchIOSink value "length" (S.fold FL.length)
232 , benchIOSink value "sum" (S.fold FL.sum)
233 , benchIOSink value "product" (S.fold FL.product)
234 , benchIOSink value "maximumBy" (S.fold (FL.maximumBy compare))
235 , benchIOSink value "maximum" (S.fold FL.maximum)
236 , benchIOSink value "minimumBy" (S.fold (FL.minimumBy compare))
237 , benchIOSink value "minimum" (S.fold FL.minimum)
238 , benchIOSink value "mean" (\s -> S.fold FL.mean (S.map (fromIntegral :: Int -> Double) s))
239 , benchIOSink value "variance" (\s -> S.fold FL.variance (S.map (fromIntegral :: Int -> Double) s))
240 , benchIOSink value "stdDev" (\s -> S.fold FL.stdDev (S.map (fromIntegral :: Int -> Double) s))
242 , benchIOSink value "mconcat" (S.fold FL.mconcat . (S.map (Last . Just)))
243 , benchIOSink value "foldMap" (S.fold (FL.foldMap (Last . Just)))
245 , benchIOSink value "index" (S.fold (FL.index (value + 1)))
246 , benchIOSink value "head" (S.fold FL.head)
247 , benchIOSink value "find" (S.fold (FL.find (== (value + 1))))
248 , benchIOSink value "findIndex" (S.fold (FL.findIndex (== (value + 1))))
249 , benchIOSink value "elemIndex" (S.fold (FL.elemIndex (value + 1)))
251 , benchIOSink value "null" (S.fold FL.null)
252 , benchIOSink value "elem" (S.fold (FL.elem (value + 1)))
253 , benchIOSink value "notElem" (S.fold (FL.notElem (value + 1)))
254 , benchIOSink value "all" (S.fold (FL.all (<= (value + 1))))
255 , benchIOSink value "any" (S.fold (FL.any (> (value + 1))))
256 , benchIOSink value "and" (\s -> S.fold FL.and (S.map (<= (value + 1)) s))
257 , benchIOSink value "or" (\s -> S.fold FL.or (S.map (> (value + 1)) s))
258 ]
259 , bgroup "fold-multi-stream"
260 [ benchIOSink1 "eqBy" (Ops.eqBy value)
261 , benchIOSink1 "cmpBy" (Ops.cmpBy value)
262 , benchIOSink value "isPrefixOf" Ops.isPrefixOf
263 , benchIOSink value "isSubsequenceOf" Ops.isSubsequenceOf
264 , benchIOSink value "stripPrefix" Ops.stripPrefix
265 ]
266 , bgroup "folds-transforms"
267 [ benchIOSink value "drain" (S.fold FL.drain)
268 , benchIOSink value "lmap" (S.fold (IFL.lmap (+1) FL.drain))
269 , benchIOSink value "pipe-mapM"
270 (S.fold (IFL.transform (Pipe.mapM (\x -> return $ x + 1)) FL.drain))
271 ]
272 , bgroup "folds-compositions" -- Applicative
273 [
274 benchIOSink value "all,any" (S.fold ((,) <$> FL.all (<= (value + 1))
275 <*> FL.any (> (value + 1))))
276 , benchIOSink value "sum,length" (S.fold ((,) <$> FL.sum <*> FL.length))
277 ]
278 , bgroup "pipes"
279 [ benchIOSink value "mapM" (Ops.transformMapM serially 1)
280 , benchIOSink value "compose" (Ops.transformComposeMapM serially 1)
281 , benchIOSink value "tee" (Ops.transformTeeMapM serially 1)
282 , benchIOSink value "zip" (Ops.transformZipMapM serially 1)
283 ]
284 , bgroup "pipesX4"
285 [ benchIOSink value "mapM" (Ops.transformMapM serially 4)
286 , benchIOSink value "compose" (Ops.transformComposeMapM serially 4)
287 , benchIOSink value "tee" (Ops.transformTeeMapM serially 4)
288 , benchIOSink value "zip" (Ops.transformZipMapM serially 4)
289 ]
290 , bgroup "transformer"
291 [ benchIOSrc serially "evalState" (Ops.evalStateT value)
292 , benchIOSrc serially "withState" (Ops.withState value)
293 ]
294 , bgroup "transformation"
295 [ benchIOSink value "scanl" (Ops.scan 1)
296 , benchIOSink value "scanl1'" (Ops.scanl1' 1)
297 , benchIOSink value "map" (Ops.map 1)
298 , benchIOSink value "fmap" (Ops.fmap 1)
299 , benchIOSink value "mapM" (Ops.mapM serially 1)
300 , benchIOSink value "mapMaybe" (Ops.mapMaybe 1)
301 , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 1)
302 , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
303 Ops.sequence serially (Ops.sourceUnfoldrMAction value n)
304 , benchIOSink value "findIndices" (Ops.findIndices value 1)
305 , benchIOSink value "elemIndices" (Ops.elemIndices value 1)
306 , benchIOSink value "foldrS" (Ops.foldrS 1)
307 , benchIOSink value "foldrSMap" (Ops.foldrSMap 1)
308 , benchIOSink value "foldrT" (Ops.foldrT 1)
309 , benchIOSink value "foldrTMap" (Ops.foldrTMap 1)
310 , benchIOSink value "tap" (Ops.tap 1)
311 , benchIOSink value "tapRate 1 second" (Ops.tapRate 1)
312 , benchIOSink value "pollCounts 1 second" (Ops.pollCounts 1)
313 , benchIOSink value "tapAsync" (Ops.tapAsync 1)
314 , benchIOSink value "tapAsyncS" (Ops.tapAsyncS 1)
315 ]
316 , bgroup "transformationX4"
317 [ benchIOSink value "scan" (Ops.scan 4)
318 , benchIOSink value "scanl1'" (Ops.scanl1' 4)
319 , benchIOSink value "map" (Ops.map 4)
320 , benchIOSink value "fmap" (Ops.fmap 4)
321 , benchIOSink value "mapM" (Ops.mapM serially 4)
322 , benchIOSink value "mapMaybe" (Ops.mapMaybe 4)
323 , benchIOSink value "mapMaybeM" (Ops.mapMaybeM 4)
324 -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
325 -- Ops.sequence serially (Ops.sourceUnfoldrMAction n)
326 , benchIOSink value "findIndices" (Ops.findIndices value 4)
327 , benchIOSink value "elemIndices" (Ops.elemIndices value 4)
328 ]
329 , bgroup "filtering"
330 [ benchIOSink value "filter-even" (Ops.filterEven 1)
331 , benchIOSink value "filter-all-out" (Ops.filterAllOut value 1)
332 , benchIOSink value "filter-all-in" (Ops.filterAllIn value 1)
334 , benchIOSink value "take-all" (Ops.takeAll value 1)
335 , benchIOSink value "takeByTime-all"
336 (Ops.takeByTime (NanoSecond64 maxBound) 1)
337 , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 1)
338 --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 1)
340 -- "drop-one" is dual to "last"
341 , benchIOSink value "drop-one" (Ops.dropOne 1)
342 , benchIOSink value "drop-all" (Ops.dropAll value 1)
343 , benchIOSink value "dropByTime-all"
344 (Ops.dropByTime (NanoSecond64 maxBound) 1)
345 , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 1)
346 --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 1)
347 , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 1)
349 , benchIOSink value "deleteBy" (Ops.deleteBy value 1)
350 , benchIOSink value "intersperse" (Ops.intersperse value 1)
351 , benchIOSink value "insertBy" (Ops.insertBy value 1)
352 ]
353 , bgroup "filteringX4"
354 [ benchIOSink value "filter-even" (Ops.filterEven 4)
355 , benchIOSink value "filter-all-out" (Ops.filterAllOut value 4)
356 , benchIOSink value "filter-all-in" (Ops.filterAllIn value 4)
357 , benchIOSink value "take-all" (Ops.takeAll value 4)
358 , benchIOSink value "takeWhile-true" (Ops.takeWhileTrue value 4)
359 --, benchIOSink value "takeWhileM-true" (Ops.takeWhileMTrue 4)
360 , benchIOSink value "drop-one" (Ops.dropOne 4)
361 , benchIOSink value "drop-all" (Ops.dropAll value 4)
362 , benchIOSink value "dropWhile-true" (Ops.dropWhileTrue value 4)
363 --, benchIOSink value "dropWhileM-true" (Ops.dropWhileMTrue 4)
364 , benchIOSink value "dropWhile-false" (Ops.dropWhileFalse value 4)
365 , benchIOSink value "deleteBy" (Ops.deleteBy value 4)
366 , benchIOSink value "intersperse" (Ops.intersperse value 4)
367 , benchIOSink value "insertBy" (Ops.insertBy value 4)
368 ]
369 , bgroup "joining"
370 [ benchIOSrc1 "zip (2,x/2)" (Ops.zip (value `div` 2))
371 , benchIOSrc1 "zipM (2,x/2)" (Ops.zipM (value `div` 2))
372 , benchIOSrc1 "mergeBy (2,x/2)" (Ops.mergeBy (value `div` 2))
373 , benchIOSrc1 "serial (2,x/2)" (Ops.serial2 (value `div` 2))
374 , benchIOSrc1 "append (2,x/2)" (Ops.append2 (value `div` 2))
375 , benchIOSrc1 "serial (2,2,x/4)" (Ops.serial4 (value `div` 4))
376 , benchIOSrc1 "append (2,2,x/4)" (Ops.append4 (value `div` 4))
377 , benchIOSrc1 "wSerial (2,x/2)" (Ops.wSerial2 value)
378 , benchIOSrc1 "interleave (2,x/2)" (Ops.interleave2 value)
379 , benchIOSrc1 "roundRobin (2,x/2)" (Ops.roundRobin2 value)
380 ]
381 , bgroup "concat-foldable"
382 [ benchIOSrc serially "foldMapWith" (Ops.sourceFoldMapWith value)
383 , benchIOSrc serially "foldMapWithM" (Ops.sourceFoldMapWithM value)
384 , benchIOSrc serially "foldMapM" (Ops.sourceFoldMapM value)
385 , benchIOSrc serially "foldWithConcatMapId" (Ops.sourceConcatMapId value)
386 ]
387 , bgroup "concat-serial"
388 [ benchIOSrc1 "concatMapPure (2,x/2)" (Ops.concatMapPure 2 (value `div` 2))
389 , benchIOSrc1 "concatMap (2,x/2)" (Ops.concatMap 2 (value `div` 2))
390 , benchIOSrc1 "concatMap (x/2,2)" (Ops.concatMap (value `div` 2) 2)
391 , benchIOSrc1 "concatMapRepl (x/4,4)" (Ops.concatMapRepl4xN value)
392 , benchIOSrc1 "concatUnfoldRepl (x/4,4)" (Ops.concatUnfoldRepl4xN value)
394 , benchIOSrc1 "concatMapWithSerial (2,x/2)"
395 (Ops.concatMapWithSerial 2 (value `div` 2))
396 , benchIOSrc1 "concatMapWithSerial (x/2,2)"
397 (Ops.concatMapWithSerial (value `div` 2) 2)
399 , benchIOSrc1 "concatMapWithAppend (2,x/2)"
400 (Ops.concatMapWithAppend 2 (value `div` 2))
401 ]
402 , bgroup "concat-interleave"
403 [ benchIOSrc1 "concatMapWithWSerial (2,x/2)"
404 (Ops.concatMapWithWSerial 2 (value `div` 2))
405 , benchIOSrc1 "concatMapWithWSerial (x/2,2)"
406 (Ops.concatMapWithWSerial (value `div` 2) 2)
407 ]
408 -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
409 -- library. If scan/fold followed by a map is efficient enough we may not
410 -- need monolithic implementations of these.
411 , bgroup "mixed"
412 [ benchIOSink value "scanl-map" (Ops.scanMap 1)
413 , benchIOSink value "foldl-map" Ops.foldl'ReduceMap
414 , benchIOSink value "sum-product-fold" Ops.sumProductFold
415 , benchIOSink value "sum-product-scan" Ops.sumProductScan
416 ]
417 , bgroup "mixedX4"
418 [ benchIOSink value "scan-map" (Ops.scanMap 4)
419 , benchIOSink value "drop-map" (Ops.dropMap 4)
420 , benchIOSink value "drop-scan" (Ops.dropScan 4)
421 , benchIOSink value "take-drop" (Ops.takeDrop value 4)
422 , benchIOSink value "take-scan" (Ops.takeScan value 4)
423 , benchIOSink value "take-map" (Ops.takeMap value 4)
424 , benchIOSink value "filter-drop" (Ops.filterDrop value 4)
425 , benchIOSink value "filter-take" (Ops.filterTake value 4)
426 , benchIOSink value "filter-scan" (Ops.filterScan 4)
427 , benchIOSink value "filter-scanl1" (Ops.filterScanl1 4)
428 , benchIOSink value "filter-map" (Ops.filterMap value 4)
429 ]
430 , bgroup "iterated"
431 [ benchIOSrc serially "mapM" Ops.iterateMapM
432 , benchIOSrc serially "scan(1/100)" Ops.iterateScan
433 , benchIOSrc serially "scanl1(1/100)" Ops.iterateScanl1
434 , benchIOSrc serially "filterEven" Ops.iterateFilterEven
435 , benchIOSrc serially "takeAll" (Ops.iterateTakeAll value)
436 , benchIOSrc serially "dropOne" Ops.iterateDropOne
437 , benchIOSrc serially "dropWhileFalse" (Ops.iterateDropWhileFalse value)
438 , benchIOSrc serially "dropWhileTrue" (Ops.iterateDropWhileTrue value)
439 ]
440 ]
441 , bgroup "wSerially"
442 [ bgroup "transformation"
443 [ benchIOSink value "fmap" $ Ops.fmap' wSerially 1
444 ]
445 ]
446 , bgroup "zipSerially"
447 [ bgroup "transformation"
448 [ benchIOSink value "fmap" $ Ops.fmap' zipSerially 1
449 ]
450 ]
451 -- Non-streaming operations. We keep these in a spearate group so that we
452 -- can run these conveniently with smaller stream size.
453 --
454 -- These are also the operations that programmers should be aware of and
455 -- should avoid using in a streaming application.
456 , bgroup "buffered"
457 [ -- Inherently non-streaming operations
459 -- Right folds for reducing are inherently non-streaming as the
460 -- expression needs to be fully built before it can be reduced.
461 benchIOSink value "foldrM/reduce/IO" Ops.foldrMReduce
462 , benchIdentitySink value "foldrM/reduce/Identity" Ops.foldrMReduce
464 -- Left folds for building a structure are inherently non-streaming as
465 -- the structure cannot be lazily consumed until fully built.
466 , benchIOSink value "foldl'/build/IO" Ops.foldl'Build
467 , benchIdentitySink value "foldl'/build/Identity" Ops.foldl'Build
468 , benchIOSink value "foldlM'/build/IO" Ops.foldlM'Build
469 , benchIdentitySink value "foldlM'/build/Identity" Ops.foldlM'Build
471 -- accumulation due to strictness of IO monad
472 , benchIOSink value "foldrM/build/IO" Ops.foldrMBuild
473 , benchPureSinkIO value "traversable/mapM" Ops.traversableMapM
475 -- Converting the stream to a list or pure stream
476 , benchIOSink value "toList" Ops.toList
477 , benchIOSink value "toListRev" Ops.toListRev
478 , benchIOSink value "toStream" (S.fold IP.toStream)
479 , benchIOSink value "toStreamRev" (S.fold IP.toStreamRev)
481 , benchIOSink value "folds/toList" (S.fold FL.toList)
482 , benchIOSink value "folds/toListRevF" (S.fold IFL.toListRevF)
484 -- Converting the stream to an array
485 , benchIOSink value "folds/lastN.Max" (S.fold (IA.lastN (value + 1)))
486 , benchIOSink value "folds/writeN" (S.fold (A.writeN value))
488 -- Reversing/sorting a stream
489 , benchIOSink value "reverse" (Ops.reverse 1)
490 , benchIOSink value "reverse'" (Ops.reverse' 1)
492 -- XXX can these be streaming? Can we have special read/show style type
493 -- classes supporting streaming?
494 , mkString value `deepseq` (bench "readsPrec pure streams" $
495 nf Ops.readInstance (mkString value))
496 , mkString value `deepseq` (bench "readsPrec Haskell lists" $
497 nf Ops.readInstanceList (mkListString value))
498 , mkList value `deepseq` (bench "showPrec Haskell lists" $
499 nf Ops.showInstanceList (mkList value))
501 -- XXX streaming operations that can potentially be fixed
502 , benchPureSink value "foldable/sum" Ops.foldableSum
503 , benchIOSink value "tail" Ops.tail
504 , benchIOSink value "nullHeadTail" Ops.nullHeadTail
505 , benchIOSrc1 "concatUnfoldInterleaveRepl (x/4,4)"
506 (Ops.concatUnfoldInterleaveRepl4xN value)
507 , benchIOSrc1 "concatUnfoldRoundrobinRepl (x/4,4)"
508 (Ops.concatUnfoldRoundrobinRepl4xN value)
509 ]
510 ]