@@ -8,24 +8,14 @@
8{-# LANGUAGE CPP #-}
8{-# LANGUAGE CPP #-}
10import Control.DeepSeq (NFData)
10import Control.DeepSeq (NFData)
11−import Data.Functor.Identity (runIdentity)
12import System.IO (openFile, IOMode(..), Handle, hClose)
11import System.IO (openFile, IOMode(..), Handle, hClose)
13import System.Process.Typed (shell, runProcess_)
12import System.Process.Typed (shell, runProcess_)
15import Data.IORef
14import Data.IORef
16import Gauge
15import Gauge
18−import qualified Streamly.FileSystem.Handle as FH
17+import qualified Streamly.Benchmark.FileIO.Stream as BFS
19−import qualified Streamly.Memory.Array as A
18+import qualified Streamly.Benchmark.FileIO.Array as BFA
20−import qualified Streamly.Prelude as S
21−import qualified Streamly.Fold as FL
22−import qualified Streamly.Data.String as SS
23−import qualified Streamly.Internal as Internal
26−import Data.Char (ord, chr)
27−import qualified Streamly.Internal as Internal
30-- Input and output file handles
20-- Input and output file handles
31data Handles = Handles Handle Handle
21data Handles = Handles Handle Handle
@@ -51,23 +41,6 @@ infile = "benchmark/text-processing/gutenberg-500.txt"
51fileSize :: Int
41fileSize :: Int
52fileSize = blockSize * blockCount
42fileSize = blockSize * blockCount
54−foreign import ccall unsafe "u_iswspace"
55− iswspace :: Int -> Int
57−-- Code copied from base/Data.Char to INLINE it
58−{-# INLINE isSpace #-}
59−isSpace :: Char -> Bool
60−-- isSpace includes non-breaking space
61−-- The magic 0x377 isn't really that magical. As of 2014, all the codepoints
62−-- at or below 0x377 have been assigned, so we shouldn't have to worry about
63−-- any new spaces appearing below there. It would probably be best to
64−-- use branchless ||, but currently the eqLit transformation will undo that,
65−-- so we'll do it like this until there's a way around that.
67− | uc <= 0x377 = uc == 32 || uc - 0x9 <= 4 || uc == 0xa0
68− | otherwise = iswspace (ord c) /= 0
70− uc = fromIntegral (ord c) :: Word
72infile :: String
45infile :: String
73infile = scratchDir ++ "in-100MB.txt"
46infile = scratchDir ++ "in-100MB.txt"
@@ -96,213 +69,154 @@ main = do
96 [ bgroup "readArray"
69 [ bgroup "readArray"
97 [ mkBench "last" href $ do
70 [ mkBench "last" href $ do
98 Handles inh _ <- readIORef href
71 Handles inh _ <- readIORef href
99− let s = FH.readArrays inh
100− larr <- S.last s
72+ BFA.last inh
101− return $ case larr of
103− Just arr -> A.readIndex arr (A.length arr - 1)
104 -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
73 -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
105 -- wc uses lseek to just determine the file size rather than reading
74 -- wc uses lseek to just determine the file size rather than reading
106 -- and counting characters.
75 -- and counting characters.
107 , mkBench "length (bytecount)" href $ do
76 , mkBench "length (bytecount)" href $ do
108 Handles inh _ <- readIORef href
77 Handles inh _ <- readIORef href
109− let s = FH.readArrays inh
78+ BFA.countBytes inh
110− S.sum (S.map A.length s)
111 , mkBench "linecount" href $ do
79 , mkBench "linecount" href $ do
112 Handles inh _ <- readIORef href
80 Handles inh _ <- readIORef href
113− S.length $ A.splitOn 10 $ FH.readArrays inh
81+ BFA.countLines inh
114 , mkBench "sum" href $ do
82 , mkBench "sum" href $ do
115− let foldlArr' f z = runIdentity . S.foldl' f z . A.read
116 Handles inh _ <- readIORef href
83 Handles inh _ <- readIORef href
117− let s = FH.readArrays inh
84+ BFA.sumBytes inh
118− S.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
119 , mkBench "cat" href $ do
85 , mkBench "cat" href $ do
120 Handles inh _ <- readIORef href
86 Handles inh _ <- readIORef href
121− S.runFold (FH.writeArrays devNull) $ FH.readArraysOf (256*1024) inh
87+ BFA.cat devNull inh
123 , bgroup "readStream"
89 , bgroup "readStream"
124 [ mkBench "last" href $ do
90 [ mkBench "last" href $ do
125 Handles inh _ <- readIORef href
91 Handles inh _ <- readIORef href
126− S.last $ FH.read inh
92+ BFS.last inh
127 , mkBench "length (bytecount)" href $ do
93 , mkBench "length (bytecount)" href $ do
128 Handles inh _ <- readIORef href
94 Handles inh _ <- readIORef href
129− S.length $ FH.read inh
95+ BFS.countBytes inh
130 , mkBench "linecount" href $ do
96 , mkBench "linecount" href $ do
131 Handles inh _ <- readIORef href
97 Handles inh _ <- readIORef href
132− S.length
98+ BFS.countLines inh
133− $ SS.foldLines FL.drain
136 , mkBench "linecountU" href $ do
99 , mkBench "linecountU" href $ do
137 Handles inh _ <- readIORef href
100 Handles inh _ <- readIORef href
138− S.length
101+ BFS.countLinesU inh
139− $ SS.foldLines FL.drain
141− $ Internal.concatMapU Internal.readU (FH.readArrays inh)
142 , mkBench "sum" href $ do
102 , mkBench "sum" href $ do
143 Handles inh _ <- readIORef href
103 Handles inh _ <- readIORef href
144− S.sum $ FH.read inh
104+ BFS.sumBytes inh
145 , mkBench "cat" href $ do
105 , mkBench "cat" href $ do
146 Handles inh _ <- readIORef href
106 Handles inh _ <- readIORef href
147− S.runFold (FH.write devNull) $ FH.read inh
107+ BFS.cat devNull inh
148 , mkBench "catStream" href $ do
108 , mkBench "catStream" href $ do
149 Handles inh _ <- readIORef href
109 Handles inh _ <- readIORef href
150− Internal.writeS devNull $ FH.read inh
110+ BFS.catStreamWrite devNull inh
152 , bgroup "copyArray"
112 , bgroup "copyArray"
153 [ mkBench "copy" href $ do
113 [ mkBench "copy" href $ do
154 Handles inh outh <- readIORef href
114 Handles inh outh <- readIORef href
155− let s = FH.readArrays inh
115+ BFA.copy inh outh
156− S.runFold (FH.writeArrays outh) s
158#ifdef DEVBUILD
117#ifdef DEVBUILD
159 -- This takes a little longer therefore put under the dev conditional
118 -- This takes a little longer therefore put under the dev conditional
160 , bgroup "copyStream"
119 , bgroup "copyStream"
161 [ mkBench "fromToHandle" href $ do
120 [ mkBench "fromToHandle" href $ do
162 Handles inh outh <- readIORef href
121 Handles inh outh <- readIORef href
163− S.runFold (FH.write outh) (FH.read inh)
122+ BFS.copy inh outh
165 -- This needs an ascii file, as decode just errors out.
124 -- This needs an ascii file, as decode just errors out.
166 , bgroup "decode-encode"
125 , bgroup "decode-encode"
167 [ mkBench "char8" href $ do
126 [ mkBench "char8" href $ do
168 Handles inh outh <- readIORef href
127 Handles inh outh <- readIORef href
169− S.runFold (FH.write outh)
128+ BFS.copyCodecChar8 inh outh
173 , mkBench "utf8" href $ do
129 , mkBench "utf8" href $ do
174 Handles inh outh <- readIORef href
130 Handles inh outh <- readIORef href
175− S.runFold (FH.write outh)
131+ BFS.copyCodecUtf8 inh outh
180 , bgroup "grouping"
133 , bgroup "grouping"
181− [ mkBench "chunksOf 1 (A.writeNF)" href $ do
134+ [ mkBench "chunksOf 1 (A.writeN)" href $ do
182 Handles inh _ <- readIORef href
135 Handles inh _ <- readIORef href
183− S.length $ S.chunksOf fileSize (A.writeN fileSize)
136+ BFS.chunksOf fileSize inh
186 , mkBench "chunksOf 1" href $ do
138 , mkBench "chunksOf 1" href $ do
187 Handles inh _ <- readIORef href
139 Handles inh _ <- readIORef href
188− S.length $ S.chunksOf 1 FL.drain (FH.read inh)
140+ BFS.chunksOf 1 inh
189 , mkBench "chunksOf 10" href $ do
141 , mkBench "chunksOf 10" href $ do
190 Handles inh _ <- readIORef href
142 Handles inh _ <- readIORef href
191− S.length $ S.chunksOf 10 FL.drain (FH.read inh)
143+ BFS.chunksOf 10 inh
192 , mkBench "chunksOf 1000" href $ do
144 , mkBench "chunksOf 1000" href $ do
193 Handles inh _ <- readIORef href
145 Handles inh _ <- readIORef href
194− S.length $ S.chunksOf 1000 FL.drain (FH.read inh)
146+ BFS.chunksOf 1000 inh
196 , bgroup "group-ungroup"
148 , bgroup "group-ungroup"
197 [ mkBench "lines-unlines" href $ do
149 [ mkBench "lines-unlines" href $ do
198 Handles inh outh <- readIORef href
150 Handles inh outh <- readIORef href
199− S.runFold (FH.write outh)
151+ BFS.linesUnlinesCopy inh outh
205 , mkBench "lines-unlines-arrays" href $ do
152 , mkBench "lines-unlines-arrays" href $ do
206 Handles inh outh <- readIORef href
153 Handles inh outh <- readIORef href
207− S.runFold (FH.writeArraysInChunksOf (1024*1024) outh)
154+ BFA.linesUnlinesCopy inh outh
208− $ Internal.insertAfterEach (return $ A.fromList [10])
210− $ FH.readArraysOf (1024*1024) inh
211 , mkBench "words-unwords" href $ do
155 , mkBench "words-unwords" href $ do
212 Handles inh outh <- readIORef href
156 Handles inh outh <- readIORef href
213− S.runFold (FH.write outh)
157+ BFS.wordsUnwordsCopy inh outh
221− , let lf = fromIntegral (ord '\n')
222− lfarr = A.fromList [lf]
223− isSp = isSpace . chr . fromIntegral
224− toarr = A.fromList . map (fromIntegral . ord)
225− in bgroup "splitting"
160+ , bgroup "splitting"
226 [ bgroup "predicate"
161 [ bgroup "predicate"
227 [ mkBench "splitOn \\n (line count)" href $ do
162 [ mkBench "splitOn \\n (line count)" href $ do
228 Handles inh _ <- readIORef href
163 Handles inh _ <- readIORef href
229− (S.length $ S.splitOn (== lf) FL.drain
164+ BFS.splitOn inh
230− $ FH.read inh) -- >>= print
231 , mkBench "splitOnSuffix \\n (line count)" href $ do
165 , mkBench "splitOnSuffix \\n (line count)" href $ do
232 Handles inh _ <- readIORef href
166 Handles inh _ <- readIORef href
233− (S.length $ S.splitOnSuffix (== lf) FL.drain
167+ BFS.splitOnSuffix inh
234− $ FH.read inh) -- >>= print
235 , mkBench "wordsBy isSpace (word count)" href $ do
168 , mkBench "wordsBy isSpace (word count)" href $ do
236 Handles inh _ <- readIORef href
169 Handles inh _ <- readIORef href
237− (S.length $ S.wordsBy isSp FL.drain
170+ BFS.wordsBy inh
238− $ FH.read inh) -- >>= print
241 , bgroup "empty-pattern"
173 , bgroup "empty-pattern"
242 [ mkBench "splitOnSeq \"\"" href $ do
174 [ mkBench "splitOnSeq \"\"" href $ do
243 Handles inh _ <- readIORef href
175 Handles inh _ <- readIORef href
244− (S.length $ Internal.splitOnSeq (A.fromList []) FL.drain
176+ BFS.splitOnSeq "" inh
245− $ FH.read inh) -- >>= print
246 , mkBench "splitOnSuffixSeq \"\"" href $ do
177 , mkBench "splitOnSuffixSeq \"\"" href $ do
247 Handles inh _ <- readIORef href
178 Handles inh _ <- readIORef href
248− (S.length $ Internal.splitOnSuffixSeq (A.fromList []) FL.drain
179+ BFS.splitOnSuffixSeq "" inh
249− $ FH.read inh) -- >>= print
251 , bgroup "short-pattern"
181 , bgroup "short-pattern"
252 [ mkBench "splitOnSeq \\n (line count)" href $ do
182 [ mkBench "splitOnSeq \\n (line count)" href $ do
253 Handles inh _ <- readIORef href
183 Handles inh _ <- readIORef href
254− (S.length $ Internal.splitOnSeq lfarr FL.drain
184+ BFS.splitOnSeq "\n" inh
255− $ FH.read inh) -- >>= print
256 , mkBench "splitOnSuffixSeq \\n (line count)" href $ do
185 , mkBench "splitOnSuffixSeq \\n (line count)" href $ do
257 Handles inh _ <- readIORef href
186 Handles inh _ <- readIORef href
258− (S.length $ Internal.splitOnSuffixSeq lfarr FL.drain
187+ BFS.splitOnSuffixSeq "\n" inh
259− $ FH.read inh) -- >>= print
260 , mkBench "splitOnSeq a" href $ do
188 , mkBench "splitOnSeq a" href $ do
261 Handles inh _ <- readIORef href
189 Handles inh _ <- readIORef href
262− (S.length $ Internal.splitOnSeq (toarr "a") FL.drain
190+ BFS.splitOnSeq "a" inh
263− $ FH.read inh) -- >>= print
264 , mkBench "splitOnSeq \\r\\n" href $ do
191 , mkBench "splitOnSeq \\r\\n" href $ do
265 Handles inh _ <- readIORef href
192 Handles inh _ <- readIORef href
266− (S.length $ Internal.splitOnSeq (toarr "\r\n") FL.drain
193+ BFS.splitOnSeq "\r\n" inh
267− $ FH.read inh) -- >>= print
268 , mkBench "splitOnSuffixSeq \\r\\n)" href $ do
194 , mkBench "splitOnSuffixSeq \\r\\n)" href $ do
269 Handles inh _ <- readIORef href
195 Handles inh _ <- readIORef href
270− (S.length $ Internal.splitOnSuffixSeq (toarr "\r\n") FL.drain
196+ BFS.splitOnSuffixSeq "\r\n" inh
271− $ FH.read inh) -- >>= print
272 , mkBench "splitOnSeq aa" href $ do
197 , mkBench "splitOnSeq aa" href $ do
273 Handles inh _ <- readIORef href
198 Handles inh _ <- readIORef href
274− (S.length $ Internal.splitOnSeq (toarr "aa") FL.drain
199+ BFS.splitOnSeq "aa" inh
275− $ FH.read inh) -- >>= print
276 , mkBench "splitOnSeq aaaa" href $ do
200 , mkBench "splitOnSeq aaaa" href $ do
277 Handles inh _ <- readIORef href
201 Handles inh _ <- readIORef href
278− (S.length $ Internal.splitOnSeq (toarr "aaaa") FL.drain
202+ BFS.splitOnSeq "aaaa" inh
279− $ FH.read inh) -- >>= print
280 , mkBench "splitOnSeq abcdefgh" href $ do
203 , mkBench "splitOnSeq abcdefgh" href $ do
281 Handles inh _ <- readIORef href
204 Handles inh _ <- readIORef href
282− (S.length $ Internal.splitOnSeq (toarr "abcdefgh") FL.drain
205+ BFS.splitOnSeq "abcdefgh" inh
283− $ FH.read inh) -- >>= print
285 , bgroup "long-pattern"
207 , bgroup "long-pattern"
286 [ mkBench "splitOnSeq abcdefghi" href $ do
208 [ mkBench "splitOnSeq abcdefghi" href $ do
287 Handles inh _ <- readIORef href
209 Handles inh _ <- readIORef href
288− (S.length $ Internal.splitOnSeq (toarr "abcdefghi") FL.drain
210+ BFS.splitOnSeq "abcdefghi" inh
289− $ FH.read inh) -- >>= print
290 , mkBench "splitOnSeq catcatcatcatcat" href $ do
211 , mkBench "splitOnSeq catcatcatcatcat" href $ do
291 Handles inh _ <- readIORef href
212 Handles inh _ <- readIORef href
292− (S.length $ Internal.splitOnSeq (toarr "catcatcatcatcat") FL.drain
213+ BFS.splitOnSeq "catcatcatcatcat" inh
293− $ FH.read inh) -- >>= print
294 , mkBench "splitOnSeq abc...xyz" href $ do
214 , mkBench "splitOnSeq abc...xyz" href $ do
295 Handles inh _ <- readIORef href
215 Handles inh _ <- readIORef href
296− (S.length $ Internal.splitOnSeq
297− (toarr "abcdefghijklmnopqrstuvwxyz")
216+ BFS.splitOnSeq "abcdefghijklmnopqrstuvwxyz" inh
299− $ FH.read inh) -- >>= print
300 , mkBench "splitOnSuffixSeq abc...xyz" href $ do
217 , mkBench "splitOnSuffixSeq abc...xyz" href $ do
301 Handles inh _ <- readIORef href
218 Handles inh _ <- readIORef href
302− (S.length $ Internal.splitOnSuffixSeq
303− (toarr "abcdefghijklmnopqrstuvwxyz")
219+ BFS.splitOnSuffixSeq "abcdefghijklmnopqrstuvwxyz" inh
305− $ FH.read inh) -- >>= print