on master help sign in
Move array stream bench/tests to separate modules
cd916f5Adithya Kumar
benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hsnew file+207
@@ -0,0 +1,207 @@
1+-- |
2+-- Module : Streamly.Benchmark.Data.ParserD
3+-- Copyright : (c) 2020 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+
8+{-# LANGUAGE CPP #-}
9+{-# LANGUAGE FlexibleContexts #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+
12+#ifdef __HADDOCK_VERSION__
13+#undef INSPECTION
14+#endif
15+
16+#ifdef INSPECTION
17+{-# LANGUAGE TemplateHaskell #-}
18+{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
19+#endif
20+
21+module Main
22+ (
23+ main
24+ ) where
25+
26+import Data.Functor.Identity (runIdentity)
27+import Data.Word (Word8)
28+import System.IO (Handle)
29+import Prelude hiding ()
30+
31+import qualified Streamly.Prelude as Stream
32+import qualified Streamly.Internal.Data.Array.Foreign as Array
33+import qualified Streamly.Internal.Data.Array.Stream.Foreign as ArrayStream
34+import qualified Streamly.Internal.FileSystem.Handle as Handle
35+import qualified Streamly.Internal.Unicode.Stream as Unicode
36+
37+import Gauge hiding (env)
38+import Streamly.Benchmark.Common
39+import Streamly.Benchmark.Common.Handle
40+
41+#ifdef INSPECTION
42+import Foreign.Storable (Storable)
43+import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
44+import Test.Inspection
45+#endif
46+
47+-------------------------------------------------------------------------------
48+-- read chunked using toChunks
49+-------------------------------------------------------------------------------
50+
51+-- | Get the last byte from a file bytestream.
52+toChunksLast :: Handle -> IO (Maybe Word8)
53+toChunksLast inh = do
54+ let s = Handle.toChunks inh
55+ larr <- Stream.last s
56+ return $ case larr of
57+ Nothing -> Nothing
58+ Just arr -> Array.readIndex arr (Array.length arr - 1)
59+
60+#ifdef INSPECTION
61+inspect $ hasNoTypeClasses 'toChunksLast
62+inspect $ 'toChunksLast `hasNoType` ''Step
63+#endif
64+
65+-- | Count the number of bytes in a file.
66+toChunksSumLengths :: Handle -> IO Int
67+toChunksSumLengths inh =
68+ let s = Handle.toChunks inh
69+ in Stream.sum (Stream.map Array.length s)
70+
71+#ifdef INSPECTION
72+inspect $ hasNoTypeClasses 'toChunksSumLengths
73+inspect $ 'toChunksSumLengths `hasNoType` ''Step
74+#endif
75+
76+-- | Sum the bytes in a file.
77+toChunksCountBytes :: Handle -> IO Word8
78+toChunksCountBytes inh = do
79+ let foldlArr' f z = runIdentity . Stream.foldl' f z . Array.toStream
80+ let s = Handle.toChunks inh
81+ Stream.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
82+
83+#ifdef INSPECTION
84+inspect $ hasNoTypeClasses 'toChunksCountBytes
85+inspect $ 'toChunksCountBytes `hasNoType` ''Step
86+#endif
87+
88+toChunksDecodeUtf8Arrays :: Handle -> IO ()
89+toChunksDecodeUtf8Arrays =
90+ Stream.drain . Unicode.decodeUtf8Arrays . Handle.toChunks
91+
92+#ifdef INSPECTION
93+inspect $ hasNoTypeClasses 'toChunksDecodeUtf8Arrays
94+-- inspect $ 'toChunksDecodeUtf8ArraysLenient `hasNoType` ''Step
95+#endif
96+
97+-------------------------------------------------------------------------------
98+-- Splitting
99+-------------------------------------------------------------------------------
100+
101+-- | Count the number of lines in a file.
102+toChunksSplitOnSuffix :: Handle -> IO Int
103+toChunksSplitOnSuffix =
104+ Stream.length . ArrayStream.splitOnSuffix 10 . Handle.toChunks
105+
106+#ifdef INSPECTION
107+inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
108+inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
109+#endif
110+
111+-- XXX use a word splitting combinator instead of splitOn and test it.
112+-- | Count the number of words in a file.
113+toChunksSplitOn :: Handle -> IO Int
114+toChunksSplitOn = Stream.length . ArrayStream.splitOn 32 . Handle.toChunks
115+
116+#ifdef INSPECTION
117+inspect $ hasNoTypeClasses 'toChunksSplitOn
118+inspect $ 'toChunksSplitOn `hasNoType` ''Step
119+#endif
120+
121+o_1_space_read_chunked :: BenchEnv -> [Benchmark]
122+o_1_space_read_chunked env =
123+ -- read using toChunks instead of read
124+ [ bgroup "reduce/toChunks"
125+ [ mkBench "Stream.last" env $ \inH _ ->
126+ toChunksLast inH
127+ -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
128+ -- wc uses lseek to just determine the file size rather than reading
129+ -- and counting characters.
130+ , mkBench "Stream.sum . Stream.map Array.length" env $ \inH _ ->
131+ toChunksSumLengths inH
132+ , mkBench "splitOnSuffix" env $ \inH _ ->
133+ toChunksSplitOnSuffix inH
134+ , mkBench "splitOn" env $ \inH _ ->
135+ toChunksSplitOn inH
136+ , mkBench "countBytes" env $ \inH _ ->
137+ toChunksCountBytes inH
138+ , mkBenchSmall "decodeUtf8Arrays" env $ \inH _ ->
139+ toChunksDecodeUtf8Arrays inH
140+ ]
141+ ]
142+
143+-------------------------------------------------------------------------------
144+-- copy with group/ungroup transformations
145+-------------------------------------------------------------------------------
146+
147+-- | Lines and unlines
148+{-# NOINLINE copyChunksSplitInterposeSuffix #-}
149+copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
150+copyChunksSplitInterposeSuffix inh outh =
151+ Stream.fold (Handle.write outh)
152+ $ ArrayStream.interposeSuffix 10
153+ $ ArrayStream.splitOnSuffix 10
154+ $ Handle.toChunks inh
155+
156+#ifdef INSPECTION
157+inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterposeSuffix [''Storable]
158+inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
159+#endif
160+
161+-- | Words and unwords
162+{-# NOINLINE copyChunksSplitInterpose #-}
163+copyChunksSplitInterpose :: Handle -> Handle -> IO ()
164+copyChunksSplitInterpose inh outh =
165+ Stream.fold (Handle.write outh)
166+ $ ArrayStream.interpose 32
167+ -- XXX this is not correct word splitting combinator
168+ $ ArrayStream.splitOn 32
169+ $ Handle.toChunks inh
170+
171+#ifdef INSPECTION
172+inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterpose [''Storable]
173+inspect $ 'copyChunksSplitInterpose `hasNoType` ''Step
174+#endif
175+
176+o_1_space_copy_toChunks_group_ungroup :: BenchEnv -> [Benchmark]
177+o_1_space_copy_toChunks_group_ungroup env =
178+ [ bgroup "copy/toChunks/group-ungroup"
179+ [ mkBench "interposeSuffix . splitOnSuffix" env $ \inh outh ->
180+ copyChunksSplitInterposeSuffix inh outh
181+ , mkBenchSmall "interpose . splitOn" env $ \inh outh ->
182+ copyChunksSplitInterpose inh outh
183+ ]
184+ ]
185+
186+-------------------------------------------------------------------------------
187+-- Driver
188+-------------------------------------------------------------------------------
189+
190+moduleName :: String
191+moduleName = "Data.Array.Stream.Foreign"
192+
193+main :: IO ()
194+main = do
195+ (value, cfg, benches) <- parseCLIOpts defaultStreamSize
196+ env <- mkHandleBenchEnv
197+ value `seq` runMode (mode cfg) cfg benches
198+ (allBenchmarks env)
199+
200+ where
201+
202+ allBenchmarks env =
203+ [ bgroup (o_1_space_prefix moduleName)
204+ ( o_1_space_read_chunked env
205+ ++ o_1_space_copy_toChunks_group_ungroup env
206+ )
207+ ]
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+5−4
@@ -361,17 +361,18 @@ o_n_space_serial value =
361main :: IO ()
361main :: IO ()
362main = do
362main = do
363 (value, cfg, benches) <- parseCLIOpts defaultStreamSize
363 (value, cfg, benches) <- parseCLIOpts defaultStreamSize
364− arrays <- IP.toList $ IP.arraysOf 100 $ sourceUnfoldrM value 0
364+ arraysSmall <- IP.toList $ IP.arraysOf 100 $ sourceUnfoldrM value 0
365− value `seq` runMode (mode cfg) cfg benches (allBenchmarks value arrays)
365+ value `seq` runMode (mode cfg) cfg benches
366+ (allBenchmarks value arraysSmall)
366
367
367 where
368 where
368
369
369− allBenchmarks value arrays =
370+ allBenchmarks value arraysSmall =
370 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
371 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
371 , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_spanning value)
372 , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_spanning value)
372 , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_nested value)
373 , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_nested value)
373 , bgroup (o_1_space_prefix moduleName)
374 , bgroup (o_1_space_prefix moduleName)
374− (o_1_space_serial_unfold value arrays)
375+ (o_1_space_serial_unfold value arraysSmall)
375 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
376 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
376 , bgroup (o_n_space_prefix moduleName) (o_n_space_serial value)
377 , bgroup (o_n_space_prefix moduleName) (o_n_space_serial value)
377 ]
378 ]
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+1−95
@@ -22,7 +22,6 @@ module Handle.Read
22 (allBenchmarks)
22 (allBenchmarks)
23where
23where
24
24
25−import Data.Functor.Identity (runIdentity)
26import Data.Word (Word8)
25import Data.Word (Word8)
27import GHC.Magic (inline)
26import GHC.Magic (inline)
28#if __GLASGOW_HASKELL__ >= 802
27#if __GLASGOW_HASKELL__ >= 802
@@ -38,7 +37,6 @@ import qualified Streamly.Internal.Data.Array.Foreign.Type as AT
38import qualified Streamly.Internal.Data.Fold as FL
37import qualified Streamly.Internal.Data.Fold as FL
39import qualified Streamly.Internal.Data.Stream.IsStream as IP
38import qualified Streamly.Internal.Data.Stream.IsStream as IP
40import qualified Streamly.Internal.FileSystem.Handle as IFH
39import qualified Streamly.Internal.FileSystem.Handle as IFH
41−import qualified Streamly.Internal.Data.Array.Stream.Foreign as AS
42import qualified Streamly.Internal.Unicode.Stream as IUS
40import qualified Streamly.Internal.Unicode.Stream as IUS
43import qualified Streamly.Prelude as S
41import qualified Streamly.Prelude as S
44import qualified Streamly.Unicode.Stream as SS
42import qualified Streamly.Unicode.Stream as SS
@@ -57,97 +55,6 @@ import qualified Streamly.Internal.Data.Unfold as IUF
57import Test.Inspection
55import Test.Inspection
58#endif
56#endif
59
57
60−-------------------------------------------------------------------------------
61−-- read chunked using toChunks
62−-------------------------------------------------------------------------------
63−
64−-- | Get the last byte from a file bytestream.
65−toChunksLast :: Handle -> IO (Maybe Word8)
66−toChunksLast inh = do
67− let s = IFH.toChunks inh
68− larr <- S.last s
69− return $ case larr of
70− Nothing -> Nothing
71− Just arr -> A.readIndex arr (A.length arr - 1)
72−
73−#ifdef INSPECTION
74−inspect $ hasNoTypeClasses 'toChunksLast
75−inspect $ 'toChunksLast `hasNoType` ''Step
76−#endif
77−
78−-- | Count the number of bytes in a file.
79−toChunksSumLengths :: Handle -> IO Int
80−toChunksSumLengths inh =
81− let s = IFH.toChunks inh
82− in S.sum (S.map A.length s)
83−
84−#ifdef INSPECTION
85−inspect $ hasNoTypeClasses 'toChunksSumLengths
86−inspect $ 'toChunksSumLengths `hasNoType` ''Step
87−#endif
88−
89−-- | Count the number of lines in a file.
90−toChunksSplitOnSuffix :: Handle -> IO Int
91−toChunksSplitOnSuffix = S.length . AS.splitOnSuffix 10 . IFH.toChunks
92−
93−#ifdef INSPECTION
94−inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
95−inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
96−#endif
97−
98−-- XXX use a word splitting combinator instead of splitOn and test it.
99−-- | Count the number of words in a file.
100−toChunksSplitOn :: Handle -> IO Int
101−toChunksSplitOn = S.length . AS.splitOn 32 . IFH.toChunks
102−
103−#ifdef INSPECTION
104−inspect $ hasNoTypeClasses 'toChunksSplitOn
105−inspect $ 'toChunksSplitOn `hasNoType` ''Step
106−#endif
107−
108−-- | Sum the bytes in a file.
109−toChunksCountBytes :: Handle -> IO Word8
110−toChunksCountBytes inh = do
111− let foldlArr' f z = runIdentity . S.foldl' f z . A.toStream
112− let s = IFH.toChunks inh
113− S.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
114−
115−#ifdef INSPECTION
116−inspect $ hasNoTypeClasses 'toChunksCountBytes
117−inspect $ 'toChunksCountBytes `hasNoType` ''Step
118−#endif
119−
120−toChunksDecodeUtf8Arrays :: Handle -> IO ()
121−toChunksDecodeUtf8Arrays =
122− S.drain . IUS.decodeUtf8Arrays . IFH.toChunks
123−
124−#ifdef INSPECTION
125−inspect $ hasNoTypeClasses 'toChunksDecodeUtf8Arrays
126−-- inspect $ 'toChunksDecodeUtf8ArraysLenient `hasNoType` ''Step
127−#endif
128−
129−o_1_space_read_chunked :: BenchEnv -> [Benchmark]
130−o_1_space_read_chunked env =
131− -- read using toChunks instead of read
132− [ bgroup "reduce/toChunks"
133− [ mkBench "S.last" env $ \inH _ ->
134− toChunksLast inH
135− -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
136− -- wc uses lseek to just determine the file size rather than reading
137− -- and counting characters.
138− , mkBench "S.sum . S.map A.length" env $ \inH _ ->
139− toChunksSumLengths inH
140− , mkBench "AS.splitOnSuffix" env $ \inH _ ->
141− toChunksSplitOnSuffix inH
142− , mkBench "AS.splitOn" env $ \inH _ ->
143− toChunksSplitOn inH
144− , mkBench "countBytes" env $ \inH _ ->
145− toChunksCountBytes inH
146− , mkBenchSmall "US.decodeUtf8Arrays" env $ \inH _ ->
147− toChunksDecodeUtf8Arrays inH
148− ]
149− ]
150−
151-- TBD reading with unfold
58-- TBD reading with unfold
152
59
153-------------------------------------------------------------------------------
60-------------------------------------------------------------------------------
@@ -388,8 +295,7 @@ o_1_space_reduce_read_grouped env =
388
295
389allBenchmarks :: BenchEnv -> [Benchmark]
296allBenchmarks :: BenchEnv -> [Benchmark]
390allBenchmarks env = Prelude.concat
297allBenchmarks env = Prelude.concat
391− [ o_1_space_read_chunked env
392− , o_1_space_reduce_read env
298+ [ o_1_space_reduce_read env
393 , o_1_space_reduce_toBytes env
299 , o_1_space_reduce_toBytes env
394 , o_1_space_reduce_read_grouped env
300 , o_1_space_reduce_read_grouped env
395 ]
301 ]
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs−45
@@ -29,7 +29,6 @@ import Streamly.Internal.Data.Array.Foreign.Type (defaultChunkSize)
29import qualified Streamly.FileSystem.Handle as FH
29import qualified Streamly.FileSystem.Handle as FH
30import qualified Streamly.Internal.Data.Unfold as IUF
30import qualified Streamly.Internal.Data.Unfold as IUF
31import qualified Streamly.Internal.FileSystem.Handle as IFH
31import qualified Streamly.Internal.FileSystem.Handle as IFH
32−import qualified Streamly.Internal.Data.Array.Stream.Foreign as AS
33import qualified Streamly.Data.Array.Foreign as A
32import qualified Streamly.Data.Array.Foreign as A
34import qualified Streamly.Prelude as S
33import qualified Streamly.Prelude as S
35
34
@@ -37,7 +36,6 @@ import Gauge hiding (env)
37import Streamly.Benchmark.Common.Handle
36import Streamly.Benchmark.Common.Handle
38
37
39#ifdef INSPECTION
38#ifdef INSPECTION
40−import Foreign.Storable (Storable)
41import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
39import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
42
40
43import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
41import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
@@ -206,48 +204,6 @@ o_1_space_copy env =
206 ]
204 ]
207 ]
205 ]
208
206
209−-------------------------------------------------------------------------------
210−-- copy with group/ungroup transformations
211−-------------------------------------------------------------------------------
212−
213−-- | Lines and unlines
214−copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
215−copyChunksSplitInterposeSuffix inh outh =
216− S.fold (IFH.write outh)
217− $ AS.interposeSuffix 10
218− $ AS.splitOnSuffix 10
219− $ IFH.toChunks inh
220−
221−#ifdef INSPECTION
222−inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterposeSuffix [''Storable]
223−inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
224−#endif
225−
226−-- | Words and unwords
227−copyChunksSplitInterpose :: Handle -> Handle -> IO ()
228−copyChunksSplitInterpose inh outh =
229− S.fold (IFH.write outh)
230− $ AS.interpose 32
231− -- XXX this is not correct word splitting combinator
232− $ AS.splitOn 32
233− $ IFH.toChunks inh
234−
235−#ifdef INSPECTION
236−inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterpose [''Storable]
237−inspect $ 'copyChunksSplitInterpose `hasNoType` ''Step
238−#endif
239−
240−o_1_space_copy_toChunks_group_ungroup :: BenchEnv -> [Benchmark]
241−o_1_space_copy_toChunks_group_ungroup env =
242− [ bgroup "copy/toChunks/group-ungroup"
243− [ mkBench "AS.interposeSuffix . AS.splitOnSuffix" env $ \inh outh ->
244− copyChunksSplitInterposeSuffix inh outh
245− , mkBenchSmall "AS.interpose . AS.splitOn" env $ \inh outh ->
246− copyChunksSplitInterpose inh outh
247− ]
248− ]
249−
250−
251-------------------------------------------------------------------------------
207-------------------------------------------------------------------------------
252--
208--
253-------------------------------------------------------------------------------
209-------------------------------------------------------------------------------
@@ -258,5 +214,4 @@ allBenchmarks env = Prelude.concat
258 , o_1_space_copy_read env
214 , o_1_space_copy_read env
259 , o_1_space_copy_fromBytes env
215 , o_1_space_copy_fromBytes env
260 , o_1_space_copy env
216 , o_1_space_copy env
261− , o_1_space_copy_toChunks_group_ungroup env
262 ]
217 ]
benchmark/streamly-benchmarks.cabal+15−1
@@ -299,7 +299,6 @@ benchmark Data.Parser.ParserD
299 if flag(limit-build-mem)
299 if flag(limit-build-mem)
300 ghc-options: +RTS -M750M -RTS
300 ghc-options: +RTS -M750M -RTS
301
301
302−
303benchmark Data.Parser.ParserK
302benchmark Data.Parser.ParserK
304 import: bench-options
303 import: bench-options
305 type: exitcode-stdio-1.0
304 type: exitcode-stdio-1.0
@@ -458,6 +457,21 @@ benchmark Data.Array.Foreign
458 other-modules: Streamly.Benchmark.Data.ArrayOps
457 other-modules: Streamly.Benchmark.Data.ArrayOps
459 cpp-options: -DMEMORY_ARRAY
458 cpp-options: -DMEMORY_ARRAY
460
459
460+-------------------------------------------------------------------------------
461+-- Array Stream Benchmarks
462+-------------------------------------------------------------------------------
463+
464+benchmark Data.Array.Stream.Foreign
465+ import: bench-options
466+ type: exitcode-stdio-1.0
467+ hs-source-dirs: Streamly/Benchmark/Data/Array/Stream
468+ main-is: Foreign.hs
469+ if impl(ghcjs)
470+ buildable: False
471+ else
472+ buildable: True
473+ build-depends: exceptions >= 0.8 && < 0.11
474+
461-------------------------------------------------------------------------------
475-------------------------------------------------------------------------------
462-- FileIO Benchmarks
476-- FileIO Benchmarks
463-------------------------------------------------------------------------------
477-------------------------------------------------------------------------------
hie.yaml+2
@@ -4,6 +4,8 @@ cradle:
4 config:
4 config:
5 cradle:
5 cradle:
6 cabal:
6 cabal:
7+ - path: "./benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hs"
8+ component: "bench:Data.Array.Stream.Foreign"
7 - path: "./benchmark/Streamly/Benchmark/Data/Fold.hs"
9 - path: "./benchmark/Streamly/Benchmark/Data/Fold.hs"
8 component: "bench:Data.Fold"
10 component: "bench:Data.Fold"
9 - path: "./benchmark/Streamly/Benchmark/Data/Parser.hs"
11 - path: "./benchmark/Streamly/Benchmark/Data/Parser.hs"
streamly.cabal+1
@@ -71,6 +71,7 @@ extra-source-files:
71 benchmark/*.hs
71 benchmark/*.hs
72 benchmark/README.md
72 benchmark/README.md
73 benchmark/Streamly/Benchmark/Data/*.hs
73 benchmark/Streamly/Benchmark/Data/*.hs
74+ benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hs
74 benchmark/Streamly/Benchmark/Data/Parser/*.hs
75 benchmark/Streamly/Benchmark/Data/Parser/*.hs
75 benchmark/Streamly/Benchmark/Data/Stream/*.hs
76 benchmark/Streamly/Benchmark/Data/Stream/*.hs
76 benchmark/Streamly/Benchmark/FileSystem/*.hs
77 benchmark/Streamly/Benchmark/FileSystem/*.hs