on master help sign in
separate const mem benchmarks from buffered ones

Streaming benchmarks take constant memory whereas the buffering ones take memory proportional to the stream size. We would like to test them separately. For streaming benchmarks we can use a very large stream size to make sure there is no space leak and we are running in constant memory for long time.

commitafc02e6970739fd34878ec64429efb8c24b54cc2 authorHarendra Kumar <harendra.kumar@gmail.com> dateThu 16 Jan 2020, 15:47 (7 years ago) parent880a072
5 files changed+82−55
benchmark/Linear.hs+64−42 benchmark/LinearAsync.hs+1 benchmark/Nested.hs+4−4 benchmark/NestedConcurrent.hs+10−8 benchmark/NestedOps.hs+3−1
benchmark/Linear.hs+64−42
@@ -143,17 +143,9 @@ main = do
143143 -- length is used to check for foldr/build fusion
144144 , benchPureSink value "length . IsList.toList" (length . GHC.toList)
145145 , benchPureSrc "IsString.fromString" (Ops.sourceIsString value)
146− , mkString value `deepseq` (bench "readsPrec pure streams" $
147− nf Ops.readInstance (mkString value))
148− , mkString value `deepseq` (bench "readsPrec Haskell lists" $
149− nf Ops.readInstanceList (mkListString value))
150146 , benchPureSink value "showsPrec pure streams" Ops.showInstance
151− , mkList value `deepseq` (bench "showPrec Haskell lists" $
152− nf Ops.showInstanceList (mkList value))
153147 , benchPureSink value "foldl'" Ops.pureFoldl'
154148 , benchPureSink value "foldable/foldl'" Ops.foldableFoldl'
155− , benchPureSink value "foldable/sum" Ops.foldableSum
156− , benchPureSinkIO value "traversable/mapM" Ops.traversableMapM
157149 ]
158150 , bgroup "generation"
159151 [ -- Most basic, barely stream continuations running
@@ -173,29 +165,22 @@ main = do
173165 , bgroup "elimination"
174166 [ bgroup "reduce"
175167 [ bgroup "IO"
176− [ benchIOSink value "foldrM" Ops.foldrMReduce
177− , benchIOSink value "foldl'" Ops.foldl'Reduce
168+ [
169+ benchIOSink value "foldl'" Ops.foldl'Reduce
178170 , benchIOSink value "foldl1'" Ops.foldl1'Reduce
179171 , benchIOSink value "foldlM'" Ops.foldlM'Reduce
180172 ]
181173 , bgroup "Identity"
182− [ benchIdentitySink value "foldrM" Ops.foldrMReduce
183− , benchIdentitySink value "foldl'" Ops.foldl'Reduce
174+ [
175+ benchIdentitySink value "foldl'" Ops.foldl'Reduce
184176 , benchIdentitySink value "foldl1'" Ops.foldl1'Reduce
185177 , benchIdentitySink value "foldlM'" Ops.foldlM'Reduce
186178 ]
187179 ]
188180
189181 , bgroup "build"
190− [ bgroup "IO"
191− [ benchIOSink value "foldrM" Ops.foldrMBuild
192− , benchIOSink value "foldl'" Ops.foldl'Build
193− , benchIOSink value "foldlM'" Ops.foldlM'Build
194− ]
195− , bgroup "Identity"
182+ [ bgroup "Identity"
196183 [ benchIdentitySink value "foldrM" Ops.foldrMBuild
197− , benchIdentitySink value "foldl'" Ops.foldl'Build
198− , benchIdentitySink value "foldlM'" Ops.foldlM'Build
199184 ]
200185 ]
201186 , benchIOSink value "uncons" Ops.uncons
@@ -203,8 +188,6 @@ main = do
203188 , benchIOSink value "mapM_" Ops.mapM_
204189
205190 , benchIOSink value "init" Ops.init
206− , benchIOSink value "tail" Ops.tail
207− , benchIOSink value "nullHeadTail" Ops.nullHeadTail
208191
209192 -- this is too low and causes all benchmarks reported in ns
210193 -- , benchIOSink value "head" Ops.head
@@ -233,8 +216,6 @@ main = do
233216 , benchIOSink value "minimumBy" Ops.minimumBy
234217 , benchIOSink value "minimum" Ops.minimum
235218
236− , benchIOSink value "toList" Ops.toList
237− , benchIOSink value "toListRev" Ops.toListRev
238219 ]
239220 , bgroup "folds"
240221 [ benchIOSink value "drain" (S.fold FL.drain)
@@ -245,7 +226,6 @@ main = do
245226 , benchIOSink value "last" (S.fold FL.last)
246227 , benchIOSink value "lastN.1" (S.fold (IA.lastN 1))
247228 , benchIOSink value "lastN.10" (S.fold (IA.lastN 10))
248− , benchIOSink value "lastN.Max" (S.fold (IA.lastN (value + 1)))
249229 , benchIOSink value "length" (S.fold FL.length)
250230 , benchIOSink value "sum" (S.fold FL.sum)
251231 , benchIOSink value "product" (S.fold FL.product)
@@ -260,12 +240,6 @@ main = do
260240 , benchIOSink value "mconcat" (S.fold FL.mconcat . (S.map (Last . Just)))
261241 , benchIOSink value "foldMap" (S.fold (FL.foldMap (Last . Just)))
262242
263− , benchIOSink value "toList" (S.fold FL.toList)
264− , benchIOSink value "toListRevF" (S.fold IFL.toListRevF)
265− , benchIOSink value "toStream" (S.fold IP.toStream)
266− , benchIOSink value "toStreamRev" (S.fold IP.toStreamRev)
267− , benchIOSink value "writeN" (S.fold (A.writeN value))
268−
269243 , benchIOSink value "index" (S.fold (FL.index (value + 1)))
270244 , benchIOSink value "head" (S.fold FL.head)
271245 , benchIOSink value "find" (S.fold (FL.find (== (value + 1))))
@@ -327,8 +301,6 @@ main = do
327301 Ops.sequence serially (Ops.sourceUnfoldrMAction value n)
328302 , benchIOSink value "findIndices" (Ops.findIndices value 1)
329303 , benchIOSink value "elemIndices" (Ops.elemIndices value 1)
330− , benchIOSink value "reverse" (Ops.reverse 1)
331− , benchIOSink value "reverse'" (Ops.reverse' 1)
332304 , benchIOSink value "foldrS" (Ops.foldrS 1)
333305 , benchIOSink value "foldrSMap" (Ops.foldrSMap 1)
334306 , benchIOSink value "foldrT" (Ops.foldrT 1)
@@ -430,10 +402,6 @@ main = do
430402 (Ops.concatMapWithWSerial 2 (value `div` 2))
431403 , benchIOSrc1 "concatMapWithWSerial (x/2,2)"
432404 (Ops.concatMapWithWSerial (value `div` 2) 2)
433− , benchIOSrc1 "concatUnfoldInterleaveRepl (x/4,4)"
434− (Ops.concatUnfoldInterleaveRepl4xN value)
435− , benchIOSrc1 "concatUnfoldRoundrobinRepl (x/4,4)"
436− (Ops.concatUnfoldRoundrobinRepl4xN value)
437405 ]
438406 -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
439407 -- library. If scan/fold followed by a map is efficient enough we may not
@@ -478,9 +446,63 @@ main = do
478446 [ benchIOSink value "fmap" $ Ops.fmap' zipSerially 1
479447 ]
480448 ]
481− , bgroup "zipAsyncly"
482− [ bgroup "transformation"
483− [ benchIOSink value "fmap" $ Ops.fmap' zipAsyncly 1
484− ]
485− ]
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
456+
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
461+
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
468+
469+ -- accumulation due to strictness of IO monad
470+ , benchIOSink value "foldrM/build/IO" Ops.foldrMBuild
471+ , benchPureSinkIO value "traversable/mapM" Ops.traversableMapM
472+
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)
478+
479+ , benchIOSink value "folds/toList" (S.fold FL.toList)
480+ , benchIOSink value "folds/toListRevF" (S.fold IFL.toListRevF)
481+
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))
485+
486+ -- Reversing/sorting a stream
487+ , benchIOSink value "reverse" (Ops.reverse 1)
488+ , benchIOSink value "reverse'" (Ops.reverse' 1)
489+
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))
498+
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+ ]
486508 ]
benchmark/LinearAsync.hs+1
@@ -126,6 +126,7 @@ main = do
126126 , benchIO value "zip" Ops.zipAsync
127127 , benchIO value "zipM" Ops.zipAsyncM
128128 , benchIO value "zipAp" Ops.zipAsyncAp
129+ , benchIO value "fmap zipAsyncly" $ Ops.fmap' zipAsyncly 1
129130 -- Parallel stages in a pipeline
130131 , benchIO value "parAppMap" Ops.parAppMap
131132 , benchIO value "parAppSum" Ops.parAppSum
benchmark/Nested.hs+4−4
@@ -34,8 +34,8 @@ main = do
3434 [ benchIO "toNullAp" $ Ops.toNullAp linearCount serially
3535 , benchIO "toNull" $ Ops.toNull linearCount serially
3636 , benchIO "toNull3" $ Ops.toNull3 linearCount serially
37− , benchIO "toList" $ Ops.toList linearCount serially
38− -- , benchIO "toListSome" $ Ops.toListSome serially
37+ -- , benchIO "toList" $ Ops.toList linearCount serially
38+ , benchIO "toListSome" $ Ops.toListSome linearCount serially
3939 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount serially
4040 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount serially
4141 , benchIO "filterSome" $ Ops.filterSome linearCount serially
@@ -46,8 +46,8 @@ main = do
4646 [ benchIO "toNullAp" $ Ops.toNullAp linearCount wSerially
4747 , benchIO "toNull" $ Ops.toNull linearCount wSerially
4848 , benchIO "toNull3" $ Ops.toNull3 linearCount wSerially
49− , benchIO "toList" $ Ops.toList linearCount wSerially
50− -- , benchIO "toListSome" $ Ops.toListSome wSerially
49+ -- , benchIO "toList" $ Ops.toList linearCount wSerially
50+ , benchIO "toListSome" $ Ops.toListSome linearCount wSerially
5151 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount wSerially
5252 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount wSerially
5353 , benchIO "filterSome" $ Ops.filterSome linearCount wSerially
benchmark/NestedConcurrent.hs+10−8
@@ -35,8 +35,8 @@ main = do
3535 [ benchIO "toNullAp" $ Ops.toNullAp linearCount aheadly
3636 , benchIO "toNull" $ Ops.toNull linearCount aheadly
3737 , benchIO "toNull3" $ Ops.toNull3 linearCount aheadly
38− , benchIO "toList" $ Ops.toList linearCount aheadly
39− -- , benchIO "toListSome" $ Ops.toListSome aheadly
38+ -- , benchIO "toList" $ Ops.toList linearCount aheadly
39+ , benchIO "toListSome" $ Ops.toListSome linearCount aheadly
4040 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount aheadly
4141 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount aheadly
4242 , benchIO "filterSome" $ Ops.filterSome linearCount aheadly
@@ -47,8 +47,8 @@ main = do
4747 [ benchIO "toNullAp" $ Ops.toNullAp linearCount asyncly
4848 , benchIO "toNull" $ Ops.toNull linearCount asyncly
4949 , benchIO "toNull3" $ Ops.toNull3 linearCount asyncly
50− , benchIO "toList" $ Ops.toList linearCount asyncly
51− -- , benchIO "toListSome" $ Ops.toListSome asyncly
50+ -- , benchIO "toList" $ Ops.toList linearCount asyncly
51+ , benchIO "toListSome" $ Ops.toListSome linearCount asyncly
5252 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount asyncly
5353 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount asyncly
5454 , benchIO "filterSome" $ Ops.filterSome linearCount asyncly
@@ -59,20 +59,22 @@ main = do
5959 [ benchIO "toNullAp" $ Ops.toNullAp linearCount wAsyncly
6060 , benchIO "toNull" $ Ops.toNull linearCount wAsyncly
6161 , benchIO "toNull3" $ Ops.toNull3 linearCount wAsyncly
62− , benchIO "toList" $ Ops.toList linearCount wAsyncly
63− -- , benchIO "toListSome" $ Ops.toListSome wAsyncly
62+ -- , benchIO "toList" $ Ops.toList linearCount wAsyncly
63+ , benchIO "toListSome" $ Ops.toListSome linearCount wAsyncly
6464 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount wAsyncly
6565 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount wAsyncly
6666 , benchIO "filterSome" $ Ops.filterSome linearCount wAsyncly
6767 , benchIO "breakAfterSome" $ Ops.breakAfterSome linearCount wAsyncly
6868 ]
6969
70+ -- XXX move this in a separate benchmark
7071 , bgroup "parallely"
7172 [ benchIO "toNullAp" $ Ops.toNullAp linearCount parallely
7273 , benchIO "toNull" $ Ops.toNull linearCount parallely
7374 , benchIO "toNull3" $ Ops.toNull3 linearCount parallely
74− , benchIO "toList" $ Ops.toList linearCount parallely
75− --, benchIO "toListSome" $ Ops.toListSome parallely
75+ -- , benchIO "toList" $ Ops.toList linearCount parallely
76+ -- XXX fix thread blocked indefinitely in MVar
77+ -- , benchIO "toListSome" $ Ops.toListSome linearCount parallely
7678 , benchIO "filterAllOut" $ Ops.filterAllOut linearCount parallely
7779 , benchIO "filterAllIn" $ Ops.filterAllIn linearCount parallely
7880 , benchIO "filterSome" $ Ops.filterSome linearCount parallely
benchmark/NestedOps.hs+3−1
@@ -101,12 +101,14 @@ toList linearCount t start = runToList . t $ do
101101 where
102102 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
103103
104+-- Taking a specified number of elements is very expensive in logict so we have
105+-- a test to measure the same.
104106{-# INLINE toListSome #-}
105107toListSome
106108 :: (S.IsStream t, S.MonadAsync m, Monad (t m))
107109 => Int -> (t m Int -> S.SerialT m Int) -> Int -> m [Int]
108110toListSome linearCount t start =
109− runToList . t $ S.take 1000 $ do
111+ runToList . t $ S.take 10000 $ do
110112 x <- source start nestedCount2
111113 y <- source start nestedCount2
112114 return $ x + y