2-- Module : Streamly.Benchmark.Data.ParserD
3-- Copyright : (c) 2020 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
9{-# LANGUAGE FlexibleContexts #-}
10{-# LANGUAGE ScopedTypeVariables #-}
12#ifdef __HADDOCK_VERSION__
17{-# LANGUAGE TemplateHaskell #-}
18{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
26import Control.DeepSeq (NFData(..))
27import Control.Monad (void)
28import Control.Monad.Catch (MonadThrow)
29import Data.Functor.Identity (runIdentity)
30import Data.Word (Word8)
31import System.IO (Handle)
32import System.Random (randomRIO)
33import Prelude hiding ()
35import qualified Streamly.Prelude as Stream
36import qualified Streamly.Internal.Data.Array.Foreign as Array
37import qualified Streamly.Internal.Data.Array.Stream.Foreign as ArrayStream
38import qualified Streamly.Internal.Data.Fold as Fold
39import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
40import qualified Streamly.Internal.Data.Stream.IsStream as Stream (arraysOf)
41import qualified Streamly.Internal.FileSystem.Handle as Handle
42import qualified Streamly.Internal.Unicode.Stream as Unicode
44import Gauge hiding (env)
45import Streamly.Prelude (SerialT, MonadAsync, IsStream)
46import Streamly.Benchmark.Common
47import Streamly.Benchmark.Common.Handle
50import Foreign.Storable (Storable)
51import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
55-------------------------------------------------------------------------------
57-------------------------------------------------------------------------------
59-- XXX these can be moved to the common module
61{-# INLINE sourceUnfoldrM #-}
62sourceUnfoldrM :: (IsStream t, MonadAsync m) => Int -> Int -> t m Int
63sourceUnfoldrM value n = Stream.unfoldrM step n
68 else return (Just (cnt, cnt + 1))
73 => String -> (Int -> t IO a) -> (t IO a -> IO b) -> Benchmark
74benchIO name src sink =
75 bench name $ nfIO $ randomRIO (1,1) >>= sink . src
77-------------------------------------------------------------------------------
78-- read chunked using toChunks
79-------------------------------------------------------------------------------
81-- | Get the last byte from a file bytestream.
82toChunksLast :: Handle -> IO (Maybe Word8)
84 let s = Handle.toChunks inh
88 Just arr -> Array.getIndex arr (Array.length arr - 1)
91inspect $ hasNoTypeClasses 'toChunksLast
92inspect $ 'toChunksLast `hasNoType` ''Step
95-- | Count the number of bytes in a file.
96toChunksSumLengths :: Handle -> IO Int
97toChunksSumLengths inh =
98 let s = Handle.toChunks inh
99 in Stream.sum (Stream.map Array.length s)
102inspect $ hasNoTypeClasses 'toChunksSumLengths
103inspect $ 'toChunksSumLengths `hasNoType` ''Step
106-- | Sum the bytes in a file.
107toChunksCountBytes :: Handle -> IO Word8
108toChunksCountBytes inh = do
109 let foldlArr' f z = runIdentity . Stream.foldl' f z . Array.toStream
110 let s = Handle.toChunks inh
111 Stream.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
114inspect $ hasNoTypeClasses 'toChunksCountBytes
115inspect $ 'toChunksCountBytes `hasNoType` ''Step
118toChunksDecodeUtf8Arrays :: Handle -> IO ()
119toChunksDecodeUtf8Arrays =
120 Stream.drain . Unicode.decodeUtf8Arrays . Handle.toChunks
123inspect $ hasNoTypeClasses 'toChunksDecodeUtf8Arrays
124-- inspect $ 'toChunksDecodeUtf8ArraysLenient `hasNoType` ''Step
127-------------------------------------------------------------------------------
129-------------------------------------------------------------------------------
131-- | Count the number of lines in a file.
132toChunksSplitOnSuffix :: Handle -> IO Int
133toChunksSplitOnSuffix =
134 Stream.length . ArrayStream.splitOnSuffix 10 . Handle.toChunks
137inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
138inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
141-- XXX use a word splitting combinator instead of splitOn and test it.
142-- | Count the number of words in a file.
143toChunksSplitOn :: Handle -> IO Int
144toChunksSplitOn = Stream.length . ArrayStream.splitOn 32 . Handle.toChunks
147inspect $ hasNoTypeClasses 'toChunksSplitOn
148inspect $ 'toChunksSplitOn `hasNoType` ''Step
151o_1_space_read_chunked :: BenchEnv -> [Benchmark]
152o_1_space_read_chunked env =
153 -- read using toChunks instead of read
154 [ bgroup "reduce/toChunks"
155 [ mkBench "Stream.last" env $ \inH _ ->
157 -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
158 -- wc uses lseek to just determine the file size rather than reading
159 -- and counting characters.
160 , mkBench "Stream.sum . Stream.map Array.length" env $ \inH _ ->
161 toChunksSumLengths inH
162 , mkBench "splitOnSuffix" env $ \inH _ ->
163 toChunksSplitOnSuffix inH
164 , mkBench "splitOn" env $ \inH _ ->
166 , mkBench "countBytes" env $ \inH _ ->
167 toChunksCountBytes inH
168 , mkBenchSmall "decodeUtf8Arrays" env $ \inH _ ->
169 toChunksDecodeUtf8Arrays inH
173-------------------------------------------------------------------------------
174-- copy with group/ungroup transformations
175-------------------------------------------------------------------------------
177-- | Lines and unlines
178{-# NOINLINE copyChunksSplitInterposeSuffix #-}
179copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
180copyChunksSplitInterposeSuffix inh outh =
181 Stream.fold (Handle.write outh)
182 $ ArrayStream.interposeSuffix 10
183 $ ArrayStream.splitOnSuffix 10
184 $ Handle.toChunks inh
187inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterposeSuffix [''Storable]
188inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
191-- | Words and unwords
192{-# NOINLINE copyChunksSplitInterpose #-}
193copyChunksSplitInterpose :: Handle -> Handle -> IO ()
194copyChunksSplitInterpose inh outh =
195 Stream.fold (Handle.write outh)
196 $ ArrayStream.interpose 32
197 -- XXX this is not correct word splitting combinator
198 $ ArrayStream.splitOn 32
199 $ Handle.toChunks inh
202inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterpose [''Storable]
203inspect $ 'copyChunksSplitInterpose `hasNoType` ''Step
206o_1_space_copy_toChunks_group_ungroup :: BenchEnv -> [Benchmark]
207o_1_space_copy_toChunks_group_ungroup env =
208 [ bgroup "copy/toChunks/group-ungroup"
209 [ mkBench "interposeSuffix . splitOnSuffix" env $ \inh outh ->
210 copyChunksSplitInterposeSuffix inh outh
211 , mkBenchSmall "interpose . splitOn" env $ \inh outh ->
212 copyChunksSplitInterpose inh outh
216-------------------------------------------------------------------------------
218-------------------------------------------------------------------------------
220{-# INLINE drainWhile #-}
221drainWhile :: MonadThrow m => (a -> Bool) -> ParserD.Parser m a ()
222drainWhile p = ParserD.takeWhile p Fold.drain
224-------------------------------------------------------------------------------
226-------------------------------------------------------------------------------
229fold :: SerialT IO (Array.Array Int) -> IO ()
230fold s = void $ ArrayStream.fold Fold.drain s
232{-# INLINE parseArray #-}
233parseArray :: Int -> SerialT IO (Array.Array Int) -> IO ()
234parseArray value s = void $ ArrayStream.parse (drainWhile (< value)) s
236o_1_space_serial_array ::
237 Int -> [Array.Array Int] -> [Array.Array Int] -> [Benchmark]
238o_1_space_serial_array bound arraysSmall arraysBig =
239 [ benchIO "fold (of 100)" (\_ -> Stream.fromList arraysSmall) fold
240 , benchIO "fold (single)" (\_ -> Stream.fromList arraysBig) fold
241 , benchIO "parse (of 100)" (\_ -> Stream.fromList arraysSmall)
243 , benchIO "parse (single)" (\_ -> Stream.fromList arraysBig)
247-------------------------------------------------------------------------------
249-------------------------------------------------------------------------------
252moduleName = "Data.Array.Stream.Foreign"
256 env <- mkHandleBenchEnv
257 runWithCLIOptsEnv defaultStreamSize alloc (allBenchmarks env)
262 small <- Stream.toList $ Stream.arraysOf 100 $ sourceUnfoldrM value 0
263 big <- Stream.toList $ Stream.arraysOf value $ sourceUnfoldrM value 0
266 allBenchmarks env arrays value =
267 let (arraysSmall, arraysBig) = arrays
268 in [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
269 [ o_1_space_read_chunked env
270 , o_1_space_serial_array value arraysSmall arraysBig
271 , 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