1{-# OPTIONS_GHC -Wno-deprecations #-}
4-- Module : Streamly.Benchmark.Data.ParserD
5-- Copyright : (c) 2020 Composewell Technologies
7-- License : BSD-3-Clause
8-- Maintainer : streamly@composewell.com
11{-# LANGUAGE FlexibleContexts #-}
12{-# LANGUAGE ScopedTypeVariables #-}
14#ifdef __HADDOCK_VERSION__
19{-# LANGUAGE TemplateHaskell #-}
20{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
28import Control.DeepSeq (NFData(..))
29import Control.Monad (void, when)
30import Control.Monad.Catch (MonadCatch, try, SomeException)
31import Data.Functor.Identity (runIdentity)
32import Data.Maybe (isJust)
33import Data.Word (Word8)
34import Streamly.Internal.Data.Stream (Stream)
35import System.IO (Handle)
36import System.Random (randomRIO)
37import Prelude hiding ()
39import qualified Streamly.Internal.Data.Array as Array
40import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
41import qualified Streamly.Internal.Data.Fold as Fold
42import qualified Streamly.Internal.Data.Parser as Parser
43import qualified Streamly.Internal.Data.Stream as S
44import qualified Streamly.Internal.Data.Stream.IsStream as Stream
45import qualified Streamly.Internal.FileSystem.Handle as Handle
46import qualified Streamly.Internal.Unicode.Stream as Unicode
48import Gauge hiding (env)
49import Streamly.Benchmark.Common
50import Streamly.Benchmark.Common.Handle
51import Control.Monad.IO.Class (MonadIO)
54import Streamly.Internal.Data.Unboxed (Unbox)
55import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
59-------------------------------------------------------------------------------
61-------------------------------------------------------------------------------
63-- XXX these can be moved to the common module
65{-# INLINE sourceUnfoldrM #-}
66sourceUnfoldrM :: MonadIO m => Int -> Int -> Stream m Int
67sourceUnfoldrM value n = S.unfoldrM step n
72 else return (Just (cnt, cnt + 1))
77 => String -> (Int -> Stream IO a) -> (Stream IO a -> IO b) -> Benchmark
78benchIO name src sink =
79 bench name $ nfIO $ randomRIO (1,1) >>= sink . src
81-------------------------------------------------------------------------------
82-- read chunked using toChunks
83-------------------------------------------------------------------------------
85-- | Get the last byte from a file bytestream.
86toChunksLast :: Handle -> IO (Maybe Word8)
88 let s = Handle.readChunks inh
92 Just arr -> Array.getIndex (Array.length arr - 1) arr
95inspect $ hasNoTypeClasses 'toChunksLast
96inspect $ 'toChunksLast `hasNoType` ''Step
99-- | Count the number of bytes in a file.
100toChunksSumLengths :: Handle -> IO Int
101toChunksSumLengths inh =
102 let s = Handle.readChunks inh
103 in Stream.sum (Stream.map Array.length s)
106inspect $ hasNoTypeClasses 'toChunksSumLengths
107inspect $ 'toChunksSumLengths `hasNoType` ''Step
110-- | Sum the bytes in a file.
111toChunksCountBytes :: Handle -> IO Word8
112toChunksCountBytes inh = do
113 let foldlArr' f z = runIdentity . Stream.foldl' f z . Array.read
114 let s = Handle.readChunks inh
115 Stream.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
118inspect $ hasNoTypeClasses 'toChunksCountBytes
119inspect $ 'toChunksCountBytes `hasNoType` ''Step
122toChunksDecodeUtf8Arrays :: Handle -> IO ()
123toChunksDecodeUtf8Arrays =
124 Stream.drain . Unicode.decodeUtf8Arrays . Handle.readChunks
127inspect $ hasNoTypeClasses 'toChunksDecodeUtf8Arrays
128-- inspect $ 'toChunksDecodeUtf8ArraysLenient `hasNoType` ''Step
131-------------------------------------------------------------------------------
133-------------------------------------------------------------------------------
135-- | Count the number of lines in a file.
136toChunksSplitOnSuffix :: Handle -> IO Int
137toChunksSplitOnSuffix =
138 Stream.length . ArrayStream.splitOnSuffix 10 . Handle.readChunks
141inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
142inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
145-- XXX use a word splitting combinator instead of splitOn and test it.
146-- | Count the number of words in a file.
147toChunksSplitOn :: Handle -> IO Int
148toChunksSplitOn = Stream.length . ArrayStream.splitOn 32 . Handle.readChunks
151inspect $ hasNoTypeClasses 'toChunksSplitOn
152inspect $ 'toChunksSplitOn `hasNoType` ''Step
155o_1_space_read_chunked :: BenchEnv -> [Benchmark]
156o_1_space_read_chunked env =
157 -- read using toChunks instead of read
158 [ bgroup "reduce/toChunks"
159 [ mkBench "Stream.last" env $ \inH _ ->
161 -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
162 -- wc uses lseek to just determine the file size rather than reading
163 -- and counting characters.
164 , mkBench "Stream.sum . Stream.map Array.length" env $ \inH _ ->
165 toChunksSumLengths inH
166 , mkBench "splitOnSuffix" env $ \inH _ ->
167 toChunksSplitOnSuffix inH
168 , mkBench "splitOn" env $ \inH _ ->
170 , mkBench "countBytes" env $ \inH _ ->
171 toChunksCountBytes inH
172 , mkBenchSmall "decodeUtf8Arrays" env $ \inH _ ->
173 toChunksDecodeUtf8Arrays inH
177-------------------------------------------------------------------------------
178-- copy with group/ungroup transformations
179-------------------------------------------------------------------------------
181-- | Lines and unlines
182{-# NOINLINE copyChunksSplitInterposeSuffix #-}
183copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
184copyChunksSplitInterposeSuffix inh outh =
185 Stream.fold (Handle.write outh)
186 $ ArrayStream.interposeSuffix 10
187 $ ArrayStream.splitOnSuffix 10
188 $ Handle.readChunks inh
191inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterposeSuffix [''Unbox]
192inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
195-- | Words and unwords
196{-# NOINLINE copyChunksSplitInterpose #-}
197copyChunksSplitInterpose :: Handle -> Handle -> IO ()
198copyChunksSplitInterpose inh outh =
199 Stream.fold (Handle.write outh)
200 $ ArrayStream.interpose 32
201 -- XXX this is not correct word splitting combinator
202 $ ArrayStream.splitOn 32
203 $ Handle.readChunks inh
206inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterpose [''Unbox]
207inspect $ 'copyChunksSplitInterpose `hasNoType` ''Step
210o_1_space_copy_toChunks_group_ungroup :: BenchEnv -> [Benchmark]
211o_1_space_copy_toChunks_group_ungroup env =
212 [ bgroup "copy/toChunks/group-ungroup"
213 [ mkBench "interposeSuffix . splitOnSuffix" env $ \inh outh ->
214 copyChunksSplitInterposeSuffix inh outh
215 , mkBenchSmall "interpose . splitOn" env $ \inh outh ->
216 copyChunksSplitInterpose inh outh
220-------------------------------------------------------------------------------
222-------------------------------------------------------------------------------
224{-# INLINE drainWhile #-}
225drainWhile :: MonadCatch m => (a -> Bool) -> Parser.Parser a m ()
226drainWhile p = Parser.takeWhile p Fold.drain
228-------------------------------------------------------------------------------
230-------------------------------------------------------------------------------
233fold :: Stream IO (Array.Array Int) -> IO ()
234fold s = void $ ArrayStream.foldBreak Fold.drain s
237parse :: Int -> Stream IO (Array.Array Int) -> IO ()
238parse value s = void $ ArrayStream.parseBreak (drainWhile (< value)) s
240{-# INLINE foldBreak #-}
241foldBreak :: Stream IO (Array.Array Int) -> IO ()
243 (r, s1) <- ArrayStream.foldBreak Fold.one s
244 when (isJust r) $ foldBreak s1
246{-# INLINE parseBreak #-}
247parseBreak :: Stream IO (Array.Array Int) -> IO ()
249 r <- try $ ArrayStream.parseBreak Parser.one s
251 Left (_ :: SomeException) -> return ()
252 Right (_, s1) -> parseBreak s1
254o_1_space_serial_array ::
255 Int -> [Array.Array Int] -> [Array.Array Int] -> [Benchmark]
256o_1_space_serial_array bound arraysSmall arraysBig =
257 [ benchIO "fold (of 100)" (\_ -> Stream.fromList arraysSmall) fold
258 , benchIO "fold (single)" (\_ -> Stream.fromList arraysBig) fold
260 "foldBreak (recursive, small arrays)"
261 (\_ -> Stream.fromList arraysSmall)
263 , benchIO "parse (of 100)" (\_ -> Stream.fromList arraysSmall)
265 , benchIO "parse (single)" (\_ -> Stream.fromList arraysBig)
268 "parseBreak (recursive, small arrays)"
269 (\_ -> Stream.fromList arraysSmall)
273-------------------------------------------------------------------------------
275-------------------------------------------------------------------------------
278moduleName = "Data.Array.Stream"
282 env <- mkHandleBenchEnv
283 runWithCLIOptsEnv defaultStreamSize alloc (allBenchmarks env)
288 small <- Stream.toList $ Stream.arraysOf 100 $ sourceUnfoldrM value 0
289 big <- Stream.toList $ Stream.arraysOf value $ sourceUnfoldrM value 0
292 allBenchmarks env arrays value =
293 let (arraysSmall, arraysBig) = arrays
294 in [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
295 [ o_1_space_read_chunked env
296 , o_1_space_serial_array value arraysSmall arraysBig
297 , o_1_space_copy_toChunks_group_ungroup env
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