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 #-}
9{-# OPTIONS_GHC -fspec-constr-recursive=4 #-}
16import Control.DeepSeq (NFData(..))
17import Control.Monad.Catch (MonadCatch)
18import Data.Foldable (asum)
19import Data.Monoid (Sum(..))
20import System.Random (randomRIO)
22 hiding (any, all, take, sequence, sequence_, sequenceA, takeWhile)
24import qualified Data.Traversable as TR
25import qualified Data.Foldable as F
26import qualified Control.Applicative as AP
27import qualified Streamly as S hiding (runStream)
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.Prelude as IP
34import Streamly hiding (runStream)
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 :: (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-------------------------------------------------------------------------------
65any :: (MonadCatch m, Ord a) => a -> SerialT m a -> m Bool
66any value = IP.parse (PR.any (> value))
69all :: (MonadCatch m, Ord a) => a -> SerialT m a -> m Bool
70all value = IP.parse (PR.all (<= value))
73take :: MonadCatch m => Int -> SerialT m a -> m ()
74take value = IP.parse (PR.take value FL.drain)
76{-# INLINE takeWhile #-}
77takeWhile :: MonadCatch m => Int -> SerialT m Int -> m ()
78takeWhile value = IP.parse (PR.takeWhile (<= value) FL.drain)
81many :: MonadCatch m => SerialT m Int -> m Int
82many = IP.parse (PR.many FL.length (PR.satisfy (> 0)))
85manyAlt :: MonadCatch m => SerialT m Int -> m Int
87 x <- IP.parse (AP.many (PR.satisfy (> 0))) xs
88 return $ Prelude.length x
91some :: MonadCatch m => SerialT m Int -> m Int
92some = IP.parse (PR.some FL.length (PR.satisfy (> 0)))
95someAlt :: MonadCatch m => SerialT m Int -> m Int
97 x <- IP.parse (AP.some (PR.satisfy (> 0))) xs
98 return $ Prelude.length x
100{-# INLINE manyTill #-}
101manyTill :: MonadCatch m => Int -> SerialT m Int -> m Int
103 IP.parse (PR.manyTill FL.length (PR.satisfy (> 0)) (PR.satisfy (== value)))
105{-# INLINE splitAp #-}
106splitAp :: MonadCatch m
107 => Int -> SerialT m Int -> m (Bool, Bool)
109 IP.parse ((,) <$> PR.all (<= (value `div` 2)) <*> PR.any (> value))
111{-# INLINE splitApBefore #-}
112splitApBefore :: MonadCatch m
113 => Int -> SerialT m Int -> m Bool
115 IP.parse (PR.all (<= (value `div` 2)) *> PR.any (> value))
117{-# INLINE splitApAfter #-}
118splitApAfter :: MonadCatch m
119 => Int -> SerialT m Int -> m Bool
121 IP.parse (PR.all (<= (value `div` 2)) <* PR.any (> value))
123{-# INLINE splitWith #-}
124splitWith :: MonadCatch m
125 => Int -> SerialT m Int -> m (Bool, Bool)
127 IP.parse (PR.splitWith (,) (PR.all (<= (value `div` 2))) (PR.any (> value)))
130split_ :: MonadCatch m
131 => Int -> SerialT m Int -> m Bool
133 IP.parse (PR.split_ (PR.all (<= (value `div` 2))) (PR.any (> value)))
135{-# INLINE teeAllAny #-}
136teeAllAny :: (MonadCatch m, Ord a)
137 => a -> SerialT m a -> m (Bool, Bool)
139 IP.parse (PR.teeWith (,) (PR.all (<= value)) (PR.any (> value)))
141{-# INLINE teeFstAllAny #-}
142teeFstAllAny :: (MonadCatch m, Ord a)
143 => a -> SerialT m a -> m (Bool, Bool)
145 IP.parse (PR.teeWithFst (,) (PR.all (<= value)) (PR.any (> value)))
147{-# INLINE shortestAllAny #-}
148shortestAllAny :: (MonadCatch m, Ord a)
149 => a -> SerialT m a -> m Bool
150shortestAllAny value =
151 IP.parse (PR.shortest (PR.all (<= value)) (PR.any (> value)))
153{-# INLINE longestAllAny #-}
154longestAllAny :: (MonadCatch m, Ord a)
155 => a -> SerialT m a -> m Bool
157 IP.parse (PR.longest (PR.all (<= value)) (PR.any (> value)))
159-------------------------------------------------------------------------------
160-- Parsers in which -fspec-constr-recursive=16 is problematic
161-------------------------------------------------------------------------------
163-- XXX -fspec-constr-recursive=16 makes GHC go beserk when compiling these.
164-- We need to fix GHC so that we can have better control over that option or do
165-- not have to rely on it.
167{-# INLINE lookAhead #-}
168lookAhead :: MonadCatch m => Int -> SerialT m Int -> m ()
170 IP.parse (PR.lookAhead (PR.takeWhile (<= value) FL.drain) *> pure ())
172{-# INLINE sequenceA #-}
173sequenceA :: MonadCatch m => Int -> SerialT m Int -> m Int
174sequenceA value xs = do
175 x <- IP.parse (TR.sequenceA (replicate value (PR.satisfy (> 0)))) xs
178{-# INLINE sequenceA_ #-}
179sequenceA_ :: MonadCatch m => Int -> SerialT m Int -> m ()
181 IP.parse (F.sequenceA_ $ replicate value (PR.satisfy (> 0)))
183{-# INLINE sequence #-}
184sequence :: MonadCatch m => Int -> SerialT m Int -> m Int
185sequence value xs = do
186 x <- IP.parse (TR.sequence (replicate value (PR.satisfy (> 0)))) xs
189{-# INLINE sequence_ #-}
190sequence_ :: MonadCatch m => Int -> SerialT m Int -> m ()
192 IP.parse (F.sequence_ $ replicate value (PR.satisfy (> 0)))
195choice :: MonadCatch m => Int -> SerialT m Int -> m Int
197 IP.parse (asum (replicate value (PR.satisfy (< 0)))
198 AP.<|> PR.satisfy (> 0))
200-------------------------------------------------------------------------------
201-- Stream transformation
202-------------------------------------------------------------------------------
204{-# INLINE parseMany #-}
205parseMany :: MonadCatch m => SerialT m Int -> m ()
209 . IP.parseMany (PR.take 2 FL.mconcat)
212{-# INLINE parseIterate #-}
213parseIterate :: MonadCatch m => SerialT m Int -> m ()
217 . IP.parseIterate (\b -> (PR.take 2 (FL.sconcat b))) (Sum 0)
220-------------------------------------------------------------------------------
222-------------------------------------------------------------------------------
225moduleName = "Data.Parser"
227o_1_space_serial :: Int -> [Benchmark]
228o_1_space_serial value =
229 [ benchIOSink value "any" $ any value
230 , benchIOSink value "all" $ all value
231 , benchIOSink value "take" $ take value
232 , benchIOSink value "takeWhile" $ takeWhile value
233 , benchIOSink value "splitAp" $ splitAp value
234 , benchIOSink value "splitApBefore" $ splitApBefore value
235 , benchIOSink value "splitApAfter" $ splitApAfter value
236 , benchIOSink value "splitWith" $ splitWith value
237 , benchIOSink value "many" many
238 , benchIOSink value "some" some
239 , benchIOSink value "manyTill" $ manyTill value
240 , benchIOSink value "tee" $ teeAllAny value
241 , benchIOSink value "teeFst" $ teeFstAllAny value
242 , benchIOSink value "shortest" $ shortestAllAny value
243 , benchIOSink value "longest" $ longestAllAny value
244 , benchIOSink value "parseMany" parseMany
245 , benchIOSink value "parseIterate" parseIterate
248o_n_heap_serial :: Int -> [Benchmark]
249o_n_heap_serial value =
251 -- lookahead benchmark holds the entire input till end
252 benchIOSink value "lookAhead" $ lookAhead value
254 -- accumulates the results in a list
255 , benchIOSink value "sequence" $ sequence value
256 , benchIOSink value "sequenceA" $ sequenceA value
258 -- XXX why should this take O(n) heap, it discards the results?
259 , benchIOSink value "sequence_" $ sequence_ value
260 , benchIOSink value "sequenceA_" $ sequenceA_ value
261 -- non-linear time complexity (parserD)
262 , benchIOSink value "split_" $ split_ value
263 -- XXX why O(n) heap?
264 , benchIOSink value "choice" $ choice value
266 -- These show non-linear time complexity.
267 -- They accumulate the results in a list.
268 , benchIOSink value "manyAlt" manyAlt
269 , benchIOSink value "someAlt" someAlt
272-------------------------------------------------------------------------------
274-------------------------------------------------------------------------------
278 (value, cfg, benches) <- parseCLIOpts defaultStreamSize
279 value `seq` runMode (mode cfg) cfg benches (allBenchmarks value)
283 allBenchmarks value =
284 [ bgroup (o_1_space_prefix moduleName) $ concat
286 o_1_space_serial value
288 , bgroup (o_n_heap_prefix moduleName) $ concat
290 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