2-- Module : Streamly.Benchmark.Data.Parser
3-- Copyright : (c) 2020 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
8{-# LANGUAGE FlexibleContexts #-}
15import Control.DeepSeq (NFData(..))
16import Control.Monad.Catch (MonadCatch)
17import Data.Foldable (asum)
18import Data.Functor (($>))
19import Data.Maybe (fromMaybe)
20import Data.Monoid (Sum(..))
21import System.Random (randomRIO)
23 hiding (any, all, take, sequence, sequence_, sequenceA, takeWhile)
25import qualified Data.Traversable as TR
26import qualified Data.Foldable as F
27import qualified Control.Applicative as AP
28import qualified Streamly.Prelude as S
29import qualified Streamly.Internal.Data.Fold as FL
30import qualified Streamly.Internal.Data.Parser as PR
31import qualified Streamly.Internal.Data.Stream.IsStream as IP
34import Streamly.Prelude (SerialT)
35import Streamly.Benchmark.Common
37-------------------------------------------------------------------------------
39-------------------------------------------------------------------------------
41-- XXX these can be moved to the common module
43{-# INLINE sourceUnfoldrM #-}
44sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
45sourceUnfoldrM value n = S.unfoldrM step n
50 else return (Just (cnt, cnt + 1))
52-- | Takes a fold method, and uses it with a default source.
53{-# INLINE benchIOSink #-}
55 :: (S.IsStream t, NFData b)
56 => Int -> String -> (t IO Int -> IO b) -> Benchmark
57benchIOSink value name f =
58 bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldrM value
60-------------------------------------------------------------------------------
62-------------------------------------------------------------------------------
64{-# INLINE takeBetween #-}
65takeBetween :: MonadCatch m => Int -> SerialT m a -> m ()
66takeBetween value = IP.parse (PR.takeBetween 0 value FL.drain)
69takeEQ :: MonadCatch m => Int -> SerialT m a -> m ()
70takeEQ value = IP.parse (PR.takeEQ value FL.drain)
72{-# INLINE drainWhile #-}
73drainWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
74drainWhile value = IP.parse (PR.drainWhile (<= value))
76{-# INLINE sliceBeginWith #-}
77sliceBeginWith :: MonadCatch m => Int -> SerialT m Int -> m ()
78sliceBeginWith value stream = do
79 stream1 <- return . fromMaybe (S.yield (value + 1)) =<< S.tail stream
80 let stream2 = value `S.cons` stream1
81 IP.parse (PR.sliceBeginWith (== value) FL.drain) stream2
83{-# INLINE takeWhile #-}
84takeWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
85takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
88groupBy :: MonadCatch m => SerialT m Int -> m ()
89groupBy = IP.parse (PR.groupBy (<=) FL.drain)
91{-# INLINE groupByRolling #-}
92groupByRolling :: MonadCatch m => SerialT m Int -> m ()
93groupByRolling = IP.parse (PR.groupByRolling (<=) FL.drain)
96wordBy :: MonadCatch m => Int -> SerialT m Int -> m ()
97wordBy value = IP.parse (PR.wordBy (>= value) FL.drain)
99{-# INLINE manyWordByEven #-}
100manyWordByEven :: MonadCatch m => SerialT m Int -> m ()
101manyWordByEven = IP.parse (PR.many FL.drain (PR.wordBy (Prelude.even) FL.drain))
104many :: MonadCatch m => SerialT m Int -> m Int
105many = IP.parse (PR.many FL.length (PR.satisfy (> 0)))
107{-# INLINE manyAlt #-}
108manyAlt :: MonadCatch m => SerialT m Int -> m Int
110 x <- IP.parse (AP.many (PR.satisfy (> 0))) xs
111 return $ Prelude.length x
114some :: MonadCatch m => SerialT m Int -> m Int
115some = IP.parse (PR.some FL.length (PR.satisfy (> 0)))
117{-# INLINE someAlt #-}
118someAlt :: MonadCatch m => SerialT m Int -> m Int
120 x <- IP.parse (AP.some (PR.satisfy (> 0))) xs
121 return $ Prelude.length x
123{-# INLINE manyTill #-}
124manyTill :: MonadCatch m => Int -> SerialT m Int -> m Int
126 IP.parse (PR.manyTill FL.length (PR.satisfy (> 0)) (PR.satisfy (== value)))
128{-# INLINE splitAp #-}
129splitAp :: MonadCatch m
130 => Int -> SerialT m Int -> m ((), ())
134 <$> PR.drainWhile (<= (value `div` 2))
135 <*> PR.drainWhile (<= value)
138{-# INLINE splitApBefore #-}
139splitApBefore :: MonadCatch m
140 => Int -> SerialT m Int -> m ()
143 ( PR.drainWhile (<= (value `div` 2))
144 *> PR.drainWhile (<= value)
147{-# INLINE splitApAfter #-}
148splitApAfter :: MonadCatch m
149 => Int -> SerialT m Int -> m ()
152 ( PR.drainWhile (<= (value `div` 2))
153 <* PR.drainWhile (<= value)
156{-# INLINE splitWith #-}
157splitWith :: MonadCatch m
158 => Int -> SerialT m Int -> m ((), ())
162 (PR.drainWhile (<= (value `div` 2)))
163 (PR.drainWhile (<= value))
167split_ :: MonadCatch m
168 => Int -> SerialT m Int -> m ()
172 (PR.drainWhile (<= (value `div` 2)))
173 (PR.drainWhile (<= value))
176{-# INLINE sliceSepByP #-}
177sliceSepByP :: MonadCatch m
178 => Int -> SerialT m Int -> m()
179sliceSepByP value = IP.parse (PR.sliceSepByP (>= value) (PR.fromFold FL.drain))
181{-# INLINE teeAllAny #-}
182teeAllAny :: MonadCatch m
183 => Int -> SerialT m Int -> m ((), ())
187 (PR.drainWhile (<= value))
188 (PR.drainWhile (<= value))
191{-# INLINE teeFstAllAny #-}
192teeFstAllAny :: MonadCatch m
193 => Int -> SerialT m Int -> m ((), ())
197 (PR.drainWhile (<= value))
198 (PR.drainWhile (<= value))
201{-# INLINE shortestAllAny #-}
202shortestAllAny :: MonadCatch m
203 => Int -> SerialT m Int -> m ()
204shortestAllAny value =
207 (PR.drainWhile (<= value))
208 (PR.drainWhile (<= value))
211{-# INLINE longestAllAny #-}
212longestAllAny :: MonadCatch m
213 => Int -> SerialT m Int -> m ()
217 (PR.drainWhile (<= value))
218 (PR.drainWhile (<= value))
221-------------------------------------------------------------------------------
222-- Parsers in which -fspec-constr-recursive=16 is problematic
223-------------------------------------------------------------------------------
225-- XXX -fspec-constr-recursive=16 makes GHC go beserk when compiling these.
226-- We need to fix GHC so that we can have better control over that option or do
227-- not have to rely on it.
229{-# INLINE lookAhead #-}
230lookAhead :: MonadCatch m => Int -> SerialT m Int -> m ()
232 IP.parse (PR.lookAhead (PR.takeWhile (<= value) FL.drain) $> ())
234{-# INLINE sequenceA #-}
235sequenceA :: MonadCatch m => Int -> SerialT m Int -> m Int
236sequenceA value xs = do
237 x <- IP.parse (TR.sequenceA (replicate value (PR.satisfy (> 0)))) xs
240{-# INLINE sequenceA_ #-}
241sequenceA_ :: MonadCatch m => Int -> SerialT m Int -> m ()
243 IP.parse (F.sequenceA_ $ replicate value (PR.satisfy (> 0)))
245{-# INLINE sequence #-}
246sequence :: MonadCatch m => Int -> SerialT m Int -> m Int
247sequence value xs = do
248 x <- IP.parse (TR.sequence (replicate value (PR.satisfy (> 0)))) xs
251{-# INLINE sequence_ #-}
252sequence_ :: MonadCatch m => Int -> SerialT m Int -> m ()
254 IP.parse (F.sequence_ $ replicate value (PR.satisfy (> 0)))
257choice :: MonadCatch m => Int -> SerialT m Int -> m Int
259 IP.parse (asum (replicate value (PR.satisfy (< 0)))
260 AP.<|> PR.satisfy (> 0))
262-------------------------------------------------------------------------------
263-- Stream transformation
264-------------------------------------------------------------------------------
266{-# INLINE parseMany #-}
267parseMany :: MonadCatch m => SerialT m Int -> m ()
271 . IP.parseMany (PR.fromFold $ FL.takeLE 2 FL.mconcat)
274{-# INLINE parseIterate #-}
275parseIterate :: MonadCatch m => SerialT m Int -> m ()
279 . IP.parseIterate (PR.fromFold . FL.takeLE 2 . FL.sconcat) (Sum 0)
282-------------------------------------------------------------------------------
284-------------------------------------------------------------------------------
287moduleName = "Data.Parser"
289o_1_space_serial :: Int -> [Benchmark]
290o_1_space_serial value =
291 [ benchIOSink value "takeBetween" $ takeBetween value
292 , benchIOSink value "takeEQ" $ takeEQ value
293 , benchIOSink value "takeWhile" $ takeWhile value
294 , benchIOSink value "drainWhile" $ drainWhile value
295 , benchIOSink value "sliceBeginWith" $ sliceBeginWith value
296 , benchIOSink value "groupBy" $ groupBy
297 , benchIOSink value "groupByRolling" $ groupByRolling
298 , benchIOSink value "wordBy" $ wordBy value
299 , benchIOSink value "splitAp" $ splitAp value
300 , benchIOSink value "splitApBefore" $ splitApBefore value
301 , benchIOSink value "splitApAfter" $ splitApAfter value
302 , benchIOSink value "splitWith" $ splitWith value
303 , benchIOSink value "sliceSepByP" $ sliceSepByP value
304 , benchIOSink value "many" many
305 , benchIOSink value "many (wordBy even)" $ manyWordByEven
306 , benchIOSink value "some" some
307 , benchIOSink value "manyTill" $ manyTill value
308 , benchIOSink value "tee" $ teeAllAny value
309 , benchIOSink value "teeFst" $ teeFstAllAny value
310 , benchIOSink value "shortest" $ shortestAllAny value
311 , benchIOSink value "longest" $ longestAllAny value
312 , benchIOSink value "parseMany" parseMany
313 , benchIOSink value "parseIterate" parseIterate
316o_n_heap_serial :: Int -> [Benchmark]
317o_n_heap_serial value =
319 -- lookahead benchmark holds the entire input till end
320 benchIOSink value "lookAhead" $ lookAhead value
322 -- accumulates the results in a list
323 , benchIOSink value "sequence" $ sequence value
324 , benchIOSink value "sequenceA" $ sequenceA value
326 -- XXX why should this take O(n) heap, it discards the results?
327 , benchIOSink value "sequence_" $ sequence_ value
328 , benchIOSink value "sequenceA_" $ sequenceA_ value
329 -- non-linear time complexity (parserD)
330 , benchIOSink value "split_" $ split_ value
331 -- XXX why O(n) heap?
332 , benchIOSink value "choice" $ choice value
334 -- These show non-linear time complexity.
335 -- They accumulate the results in a list.
336 , benchIOSink value "manyAlt" manyAlt
337 , benchIOSink value "someAlt" someAlt
340-------------------------------------------------------------------------------
342-------------------------------------------------------------------------------
346 (value, cfg, benches) <- parseCLIOpts defaultStreamSize
347 value `seq` runMode (mode cfg) cfg benches (allBenchmarks value)
351 allBenchmarks value =
352 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
353 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list