on efecb26 help sign in
278 lines 9.8 kB history raw
1-- |
2-- Module : Stream.Generate
3-- Copyright : (c) 2018 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
7{-# LANGUAGE CPP #-}
8{-# LANGUAGE FlexibleContexts #-}
9{-# LANGUAGE FlexibleInstances #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE RankNTypes #-}
13{-# OPTIONS_GHC -Wno-orphans #-}
14#ifdef USE_PRELUDE
15{-# OPTIONS_GHC -Wno-deprecations #-}
16#endif
18module Stream.Generate (benchmarks) where
20import Control.DeepSeq (NFData(..))
21import Data.Functor.Identity (Identity(..))
23import qualified GHC.Exts as GHC
24import qualified Streamly.Internal.Data.Fold as Fold
26#ifdef USE_PRELUDE
27import Streamly.Prelude (MonadAsync)
28import Stream.Common hiding (MonadAsync)
29import Streamly.Benchmark.Prelude (sourceFromFoldableM, absTimes)
30import qualified Streamly.Prelude as S
31import qualified Streamly.Internal.Data.Stream.IsStream as Stream
32#else
33import Stream.Common
34import Streamly.Internal.Data.Stream (Stream)
35import qualified Streamly.Internal.Data.Stream as Stream
36#ifdef USE_STREAMK
37import System.IO.Unsafe (unsafeInterleaveIO)
38import qualified Streamly.Internal.Data.StreamK as StreamK
39import qualified Stream.Common as Common
40#endif
41#endif
43import Gauge
44import Streamly.Benchmark.Common
45import qualified Prelude
47import Prelude hiding (repeat, replicate, iterate)
49-------------------------------------------------------------------------------
50-- Generation
51-------------------------------------------------------------------------------
53#ifdef USE_PRELUDE
54type Stream = Stream.SerialT
55toStreamD = Stream.toStream
56#else
57toStreamD :: a -> a
58toStreamD = id
59#endif
61-------------------------------------------------------------------------------
62-- fromList
63-------------------------------------------------------------------------------
65{-# INLINE sourceFromList #-}
66sourceFromList :: Monad m => Int -> Int -> Stream m Int
67sourceFromList value n = Stream.fromList [n..n+value]
69{-# INLINE sourceFromListM #-}
70sourceFromListM :: MonadAsync m => Int -> Int -> Stream m Int
71sourceFromListM value n = fromListM (fmap return [n..n+value])
73{-# INLINE sourceIsList #-}
74sourceIsList :: Int -> Int -> Stream Identity Int
75sourceIsList value n = GHC.fromList [n..n+value]
77{-# INLINE sourceIsString #-}
78sourceIsString :: Int -> Int -> Stream Identity Char
79sourceIsString value n = GHC.fromString (Prelude.replicate (n + value) 'a')
81{-# INLINE readInstance #-}
82readInstance :: String -> Stream Identity Int
83readInstance str =
84 let r = reads str
85 in case r of
86 [(x,"")] -> x
87 _ -> error "readInstance: no parse"
89-- For comparisons
90{-# INLINE readInstanceList #-}
91readInstanceList :: String -> [Int]
92readInstanceList str =
93 let r = reads str
94 in case r of
95 [(x,"")] -> x
96 _ -> error "readInstance: no parse"
98{-# INLINE repeat #-}
99repeat :: Monad m => Int -> Int -> Stream m Int
100repeat count = Stream.take count . Stream.repeat
102{-# INLINE replicate #-}
103replicate :: Monad m => Int -> Int -> Stream m Int
104replicate = Stream.replicate
106-------------------------------------------------------------------------------
107-- enumerate
108-------------------------------------------------------------------------------
110{-# INLINE sourceIntFromTo #-}
111sourceIntFromTo :: Monad m => Int -> Int -> Stream m Int
112sourceIntFromTo value n = Stream.enumerateFromTo n (n + value)
114{-# INLINE sourceIntFromThenTo #-}
115sourceIntFromThenTo :: Monad m => Int -> Int -> Stream m Int
116sourceIntFromThenTo value n = Stream.enumerateFromThenTo n (n + 1) (n + value)
118{-# INLINE sourceFracFromTo #-}
119sourceFracFromTo :: Monad m => Int -> Int -> Stream m Double
120sourceFracFromTo value n =
121 Stream.enumerateFromTo (fromIntegral n) (fromIntegral (n + value))
123{-# INLINE sourceFracFromThenTo #-}
124sourceFracFromThenTo :: Monad m => Int -> Int -> Stream m Double
125sourceFracFromThenTo value n = Stream.enumerateFromThenTo (fromIntegral n)
126 (fromIntegral n + 1.0001) (fromIntegral (n + value))
128{-# INLINE sourceIntegerFromStep #-}
129sourceIntegerFromStep :: Monad m => Int -> Int -> Stream m Integer
130sourceIntegerFromStep value n =
131 Stream.take value $ Stream.enumerateFromThen (fromIntegral n) (fromIntegral n + 1)
133{-# INLINE enumerateFrom #-}
134enumerateFrom :: Monad m => Int -> Int -> Stream m Int
135enumerateFrom count = Stream.take count . Stream.enumerateFrom
137{-# INLINE enumerateFromTo #-}
138enumerateFromTo :: Monad m => Int -> Int -> Stream m Int
139enumerateFromTo = sourceIntFromTo
141{-# INLINE enumerateFromThen #-}
142enumerateFromThen :: Monad m => Int -> Int -> Stream m Int
143enumerateFromThen count inp = Stream.take count $ Stream.enumerateFromThen inp (inp + 1)
145{-# INLINE enumerateFromThenTo #-}
146enumerateFromThenTo :: Monad m => Int -> Int -> Stream m Int
147enumerateFromThenTo = sourceIntFromThenTo
149-- n ~ 1
150{-# INLINE enumerate #-}
151enumerate :: Monad m => Int -> Int -> Stream m Int
152enumerate count n = Stream.take (count + n) Stream.enumerate
154-- n ~ 1
155{-# INLINE enumerateTo #-}
156enumerateTo :: Monad m => Int -> Int -> Stream m Int
157enumerateTo count n = Stream.enumerateTo (minBound + count + n)
159{-# INLINE iterate #-}
160iterate :: Monad m => Int -> Int -> Stream m Int
161iterate count = Stream.take count . Stream.iterate (+1)
163{-# INLINE iterateM #-}
164iterateM :: MonadAsync m => Int -> Int -> Stream m Int
165iterateM count = Stream.take count . Stream.iterateM (return . (+1)) . return
167{-# INLINE repeatM #-}
168repeatM :: MonadAsync m => Int -> Int -> Stream m Int
169repeatM count = Stream.take count . Stream.repeatM . return
171{-# INLINE replicateM #-}
172replicateM :: MonadAsync m => Int -> Int -> Stream m Int
173replicateM count = Stream.replicateM count . return
175#ifdef USE_PRELUDE
176{-# INLINE fromIndices #-}
177fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
178fromIndices value n = S.take value $ S.fromIndices (+ n)
180{-# INLINE fromIndicesM #-}
181fromIndicesM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
182fromIndicesM value n = S.take value $ S.fromIndicesM (return <$> (+ n))
183#endif
185#ifdef USE_STREAMK
186{-# INLINE mfixUnfold #-}
187mfixUnfold :: Int -> Int -> Stream IO (Int, Int)
188mfixUnfold count start = toStream $ StreamK.mfix f
189 where
190 f action = StreamK.unCross $ do
191 let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
192 x <- StreamK.mkCross (fromStream $ Common.fromListM [incr 1 action, incr 2 action])
193 y <- StreamK.mkCross (fromStream $ Common.sourceUnfoldr count start)
194 return (x, y)
195#endif
197o_1_space_generation :: Int -> [Benchmark]
198o_1_space_generation value =
199 [ bgroup "generation"
200 [ benchIOSrc "unfoldr" (sourceUnfoldr value)
201 , benchIOSrc "unfoldrM" (sourceUnfoldrM value)
202 , benchIOSrc "repeat" (repeat value)
203 , benchIOSrc "replicate" (replicate value)
204 , benchIOSrc "iterate" (iterate value)
205 , benchIOSrc "iterateM" (iterateM value)
206 , benchIOSrc "intFromTo" (sourceIntFromTo value)
207 , benchIOSrc "intFromThenTo" (sourceIntFromThenTo value)
208 , benchIOSrc "integerFromStep" (sourceIntegerFromStep value)
209 , benchIOSrc "fracFromThenTo" (sourceFracFromThenTo value)
210 , benchIOSrc "fracFromTo" (sourceFracFromTo value)
211 , benchIOSrc "fromList" (sourceFromList value)
212 , benchIOSrc "fromListM" (sourceFromListM value)
213 , benchPureSrc "IsList.fromList" (toStreamD . sourceIsList value)
214 , benchPureSrc "IsString.fromString" (toStreamD . sourceIsString value)
215 , benchIOSrc "enumerateFrom" (enumerateFrom value)
216 , benchIOSrc "enumerateFromTo" (enumerateFromTo value)
217 , benchIOSrc "enumerateFromThen" (enumerateFromThen value)
218 , benchIOSrc "enumerateFromThenTo" (enumerateFromThenTo value)
219 , benchIOSrc "enumerate" (enumerate value)
220 , benchIOSrc "enumerateTo" (enumerateTo value)
221 , benchIOSrc "repeatM" (repeatM value)
222 , benchIOSrc "replicateM" (replicateM value)
223#ifdef USE_PRELUDE
224 , benchIOSrc "fromIndices" (fromIndices value)
225 , benchIOSrc "fromIndicesM" (fromIndicesM value)
226#endif
228 -- These essentially test cons and consM
229#ifdef USE_STREAMK
230 , benchIOSrc "fromFoldable" (sourceFromFoldable value)
231 -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16)
232#else
233 -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16)
234#endif
236#ifdef USE_PRELUDE
237 , benchIOSrc "fromFoldableM" (sourceFromFoldableM value)
238 , benchIOSrc "absTimes" $ absTimes value
239#endif
240#ifdef USE_STREAMK
241 , Common.benchIOSrc "mfix_10" (mfixUnfold 10)
242 , Common.benchIOSrc "mfix_100" (mfixUnfold 100)
243 , Common.benchIOSrc "mfix_1000" (mfixUnfold 1000)
244#endif
245 ]
246 ]
248#ifndef USE_PRELUDE
249instance NFData a => NFData (Stream Identity a) where
250 {-# INLINE rnf #-}
251 rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
252#endif
254o_n_heap_generation :: Int -> [Benchmark]
255o_n_heap_generation value =
256 [ bgroup "buffered"
257 -- Buffers the output of show/read.
258 -- XXX can the outputs be streaming? Can we have special read/show
259 -- style type classes, readM/showM supporting streaming effects?
260 [ bench "readsPrec pure streams" $
261 nf readInstance (mkString value)
262 , bench "readsPrec Haskell lists" $
263 nf readInstanceList (mkListString value)
264 ]
265 ]
267-------------------------------------------------------------------------------
268-- Main
269-------------------------------------------------------------------------------
271-- In addition to gauge options, the number of elements in the stream can be
272-- passed using the --stream-size option.
273--
274benchmarks :: String -> Int -> [Benchmark]
275benchmarks moduleName size =
276 [ bgroup (o_1_space_prefix moduleName) (o_1_space_generation size)
277 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_generation size)
278 ]