2-- Module : Streamly.Benchmark.FileSystem.Handle
3-- Copyright : (c) 2019 Composewell Technologies
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
11{-# LANGUAGE ScopedTypeVariables #-}
13#ifdef __HADDOCK_VERSION__
18{-# LANGUAGE TemplateHaskell #-}
19{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
22import Control.DeepSeq (NFData(rnf))
23import Control.Exception (SomeException)
24import Data.Char (ord, chr)
25import Data.Functor.Identity (runIdentity)
26import Data.Word (Word8)
27#if __GLASGOW_HASKELL__ >= 800
28import System.Directory (getFileSize)
30import System.Environment (lookupEnv)
31import System.IO (openFile, IOMode(..), Handle, hClose)
32import System.Process.Typed (shell, runProcess_)
33import Prelude hiding (last, length)
35import qualified Streamly.Data.Fold as FL
36import qualified Streamly.Data.Unicode.Stream as SS
37import qualified Streamly.FileSystem.Handle as FH
38-- import qualified Streamly.Internal.Data.Fold as IFL
39import qualified Streamly.Internal.Data.Parser as PR
40import qualified Streamly.Internal.Data.Stream.StreamD as D
41import qualified Streamly.Internal.Data.Unfold as IUF
42import qualified Streamly.Internal.Data.Unicode.Stream as IUS
43import qualified Streamly.Internal.FileSystem.Handle as IFH
44import qualified Streamly.Internal.Memory.Array as IA
45import qualified Streamly.Internal.Memory.Array.Types as AT
46import qualified Streamly.Internal.Memory.ArrayStream as AS
47import qualified Streamly.Internal.Memory.Unicode.Array as IUA
48import qualified Streamly.Internal.Prelude as IP
49import qualified Streamly.Memory.Array as A
50import qualified Streamly.Prelude as S
53import Gauge hiding (env)
54import Streamly.Benchmark.Common
57import Foreign.Storable (Storable)
58import Streamly.Internal.Data.Stream.StreamD.Type (Step(..), GroupState)
62-------------------------------------------------------------------------------
64-------------------------------------------------------------------------------
67moduleName = "FileSystem.Handle"
69-------------------------------------------------------------------------------
71-------------------------------------------------------------------------------
74scratchDir = "benchmark-tmp"
77outfile = scratchDir ++ "out.txt"
80smallFileSize = 10 * 1024 * 1024
83inFileSmall = scratchDir ++ "in-10MB.txt"
86bigFileSize = 100 * 1024 * 1024
89inFileBig = scratchDir ++ "in-100MB.txt"
94blockCount :: Int -> Int
95blockCount size = (size + blockSize - 1) `div` blockSize
97data RefHandles = RefHandles
103data Handles = Handles !Handle !Handle
105instance NFData Handles where
108data BenchEnv = BenchEnv
109 { href :: IORef RefHandles
115withScaling :: BenchEnv -> String -> String
117 let factor = round (fromIntegral (bigSize env)
118 / (fromIntegral (smallSize env) :: Double)) :: Int
121 else str ++ " (1/" ++ show factor ++ ")"
125 => (RefHandles -> Handles)
128 -> (Handle -> Handle -> IO b)
130mkBenchCommon mkHandles name env action =
131 bench name $ perRunEnv (do
132 r <- readIORef $ href env
140 smallInHandle <- openFile inFileSmall ReadMode
141 bigInHandle <- openFile inFileBig ReadMode
142 outHandle <- openFile outfile WriteMode
144 let refHandles = RefHandles
145 { smallInH = smallInHandle
146 , bigInH = bigInHandle
147 , outputH = outHandle
151 writeIORef (href env) $ refHandles
152 return $ mkHandles refHandles
154 (\(Handles h1 h2) -> action h1 h2)
157 NFData b => String -> BenchEnv -> (Handle -> Handle -> IO b) -> Benchmark
158mkBench name env action = mkBenchCommon useBigH name env action
162 useBigH (RefHandles {bigInH = inh, outputH = outh}) = Handles inh outh
165 NFData b => String -> BenchEnv -> (Handle -> Handle -> IO b) -> Benchmark
166mkBenchSmall name env action =
167 mkBenchCommon useSmallH (withScaling env name) env action
171 useSmallH (RefHandles {smallInH = inh, outputH = outh}) = Handles inh outh
173-------------------------------------------------------------------------------
174-- read chunked using toChunks
175-------------------------------------------------------------------------------
177-- | Get the last byte from a file bytestream.
178{-# INLINE toChunksLast #-}
179toChunksLast :: Handle -> IO (Maybe Word8)
181 let s = IFH.toChunks inh
183 return $ case larr of
185 Just arr -> IA.readIndex arr (A.length arr - 1)
188inspect $ hasNoTypeClasses 'toChunksLast
189inspect $ 'toChunksLast `hasNoType` ''Step
192-- | Count the number of bytes in a file.
193{-# INLINE toChunksSumLengths #-}
194toChunksSumLengths :: Handle -> IO Int
195toChunksSumLengths inh =
196 let s = IFH.toChunks inh
197 in S.sum (S.map A.length s)
200inspect $ hasNoTypeClasses 'toChunksSumLengths
201inspect $ 'toChunksSumLengths `hasNoType` ''Step
204-- | Count the number of lines in a file.
205{-# INLINE toChunksSplitOnSuffix #-}
206toChunksSplitOnSuffix :: Handle -> IO Int
207toChunksSplitOnSuffix = S.length . AS.splitOnSuffix 10 . IFH.toChunks
210inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
211inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
214-- XXX use a word splitting combinator instead of splitOn and test it.
215-- | Count the number of words in a file.
216{-# INLINE toChunksSplitOn #-}
217toChunksSplitOn :: Handle -> IO Int
218toChunksSplitOn = S.length . AS.splitOn 32 . IFH.toChunks
221inspect $ hasNoTypeClasses 'toChunksSplitOn
222inspect $ 'toChunksSplitOn `hasNoType` ''Step
225-- | Sum the bytes in a file.
226{-# INLINE toChunksCountBytes #-}
227toChunksCountBytes :: Handle -> IO Word8
228toChunksCountBytes inh = do
229 let foldlArr' f z = runIdentity . S.foldl' f z . IA.toStream
230 let s = IFH.toChunks inh
231 S.foldl' (\acc arr -> acc + foldlArr' (+) 0 arr) 0 s
234inspect $ hasNoTypeClasses 'toChunksCountBytes
235inspect $ 'toChunksCountBytes `hasNoType` ''Step
238{-# INLINE toChunksWithBufferOfDecodeUtf8ArraysLenient #-}
239toChunksWithBufferOfDecodeUtf8ArraysLenient :: Handle -> IO ()
240toChunksWithBufferOfDecodeUtf8ArraysLenient inh =
242 $ IUS.decodeUtf8ArraysLenient
243 $ IFH.toChunksWithBufferOf (1024*1024) inh
246inspect $ hasNoTypeClasses 'decodeUtf8Lenient
247-- inspect $ 'decodeUtf8Lenient `hasNoType` ''Step
248-- inspect $ 'decodeUtf8Lenient `hasNoType` ''AT.FlattenState
249-- inspect $ 'decodeUtf8Lenient `hasNoType` ''D.ConcatMapUState
252o_1_space_read_chunked :: BenchEnv -> [Benchmark]
253o_1_space_read_chunked env =
254 -- read using toChunks instead of read
255 [ bgroup "reduce/toChunks"
256 [ mkBench "S.last (32K)" env $ \inH _ ->
258 -- Note: this cannot be fairly compared with GNU wc -c or wc -m as
259 -- wc uses lseek to just determine the file size rather than reading
260 -- and counting characters.
261 , mkBench "S.sum . S.map A.length (32K)" env $ \inH _ ->
262 toChunksSumLengths inH
263 , mkBench "AS.splitOnSuffix (32K)" env $ \inH _ ->
264 toChunksSplitOnSuffix inH
265 , mkBench "AS.splitOn (32K)" env $ \inH _ ->
267 , mkBench "countBytes (32K)" env $ \inH _ ->
268 toChunksCountBytes inH
269 , mkBenchSmall "US.decodeUtf8ArraysLenient (1MB)" env $ \inH _ ->
270 toChunksWithBufferOfDecodeUtf8ArraysLenient inH
274-- TBD reading with unfold
276-------------------------------------------------------------------------------
278-------------------------------------------------------------------------------
280-- | Send the file contents to /dev/null
281{-# INLINE toChunksWithBufferOf #-}
282toChunksWithBufferOf :: Handle -> Handle -> IO ()
283toChunksWithBufferOf inh devNull =
284 S.fold (IFH.writeChunks devNull) $ IFH.toChunksWithBufferOf (256*1024) inh
287inspect $ hasNoTypeClasses 'toChunksWithBufferOf
288inspect $ 'toChunksWithBufferOf `hasNoType` ''Step
292{-# INLINE copyChunks #-}
293copyChunks :: Handle -> Handle -> IO ()
295 let s = IFH.toChunks inh
296 in S.fold (IFH.writeChunks outh) s
299inspect $ hasNoTypeClasses 'toChunksWriteChunks
300inspect $ 'toChunksWriteChunks `hasNoType` ''Step
304{-# INLINE copyCodecUtf8ArraysLenient #-}
305copyCodecUtf8ArraysLenient :: Handle -> Handle -> IO ()
306copyCodecUtf8ArraysLenient inh outh =
307 S.fold (FH.write outh)
309 $ IUS.decodeUtf8ArraysLenient
310 $ IFH.toChunksWithBufferOf (1024*1024) inh
313inspect $ hasNoTypeClasses 'copyCodecUtf8ArraysLenient
314-- inspect $ 'copyCodecUtf8ArraysLenient `hasNoType` ''Step
315-- inspect $ 'copyCodecUtf8ArraysLenient `hasNoType` ''AT.FlattenState
316-- inspect $ 'copyCodecUtf8ArraysLenient `hasNoType` ''D.ConcatMapUState
319o_1_space_copy_chunked :: BenchEnv -> [Benchmark]
320o_1_space_copy_chunked env =
321 [ bgroup "copy/toChunks"
322 [ mkBench "toNull (256K)" env $ \inH _ ->
323 toChunksWithBufferOf inH (nullH env)
324 , mkBench "raw" env $ \inH outH ->
326 , mkBenchSmall "decodeEncodeUtf8Lenient" env $ \inH outH ->
327 copyCodecUtf8ArraysLenient inH outH
331-- TBD reading with unfold
333-------------------------------------------------------------------------------
334-- Exceptions readChunks
335-------------------------------------------------------------------------------
337-- | Send the file contents to /dev/null with exception handling
338{-# INLINE readChunksWithBufferOfOnExceptionUnfold #-}
339readChunksWithBufferOfOnExceptionUnfold :: Handle -> Handle -> IO ()
340readChunksWithBufferOfOnExceptionUnfold inh devNull =
341 let readEx = IUF.onException (\_ -> hClose inh)
342 (IUF.supplyFirst FH.readChunksWithBufferOf (256*1024))
343 in IUF.fold readEx (IFH.writeChunks devNull) inh
346inspect $ hasNoTypeClasses 'readChunksWithBufferOfOnExceptionUnfold
347-- inspect $ 'readChunksWithBufferOfOnExceptionUnfold `hasNoType` ''Step
350-- | Send the file contents to /dev/null with exception handling
351{-# INLINE readChunksWithBufferOfBracketUnfold #-}
352readChunksWithBufferOfBracketUnfold :: Handle -> Handle -> IO ()
353readChunksWithBufferOfBracketUnfold inh devNull =
354 let readEx = IUF.bracket return (\_ -> hClose inh)
355 (IUF.supplyFirst FH.readChunksWithBufferOf (256*1024))
356 in IUF.fold readEx (IFH.writeChunks devNull) inh
359inspect $ hasNoTypeClasses 'readChunksWithBufferOfBracketUnfold
360-- inspect $ 'readChunksWithBufferOfBracketUnfold `hasNoType` ''Step
363{-# INLINE readChunksWithBufferOfBracketIOUnfold #-}
364readChunksWithBufferOfBracketIOUnfold :: Handle -> Handle -> IO ()
365readChunksWithBufferOfBracketIOUnfold inh devNull =
366 let readEx = IUF.bracketIO return (\_ -> hClose inh)
367 (IUF.supplyFirst FH.readChunksWithBufferOf (256*1024))
368 in IUF.fold readEx (IFH.writeChunks devNull) inh
370o_1_space_copy_exceptions_readChunks :: BenchEnv -> [Benchmark]
371o_1_space_copy_exceptions_readChunks env =
372 [ bgroup "copy/exceptions/unfold/readChunks"
373 [ mkBench "onException (256K)" env $ \inH _ ->
374 readChunksWithBufferOfOnExceptionUnfold inH (nullH env)
375 , mkBench "bracket (256K)" env $ \inH _ ->
376 readChunksWithBufferOfBracketUnfold inH (nullH env)
377 , mkBench "bracketIO (256K)" env $ \inH _ ->
378 readChunksWithBufferOfBracketIOUnfold inH (nullH env)
382-------------------------------------------------------------------------------
383-- Exceptions toChunks
384-------------------------------------------------------------------------------
386-- | Send the file contents to /dev/null with exception handling
387{-# INLINE toChunksWithBufferOfBracketStream #-}
388toChunksWithBufferOfBracketStream :: Handle -> Handle -> IO ()
389toChunksWithBufferOfBracketStream inh devNull =
390 let readEx = S.bracket (return ()) (\_ -> hClose inh)
391 (\_ -> IFH.toChunksWithBufferOf (256*1024) inh)
392 in S.fold (IFH.writeChunks devNull) $ readEx
395inspect $ hasNoTypeClasses 'toChunksWithBufferOfBracketStream
396-- inspect $ 'toChunksWithBufferOfBracketStream `hasNoType` ''Step
399{-# INLINE toChunksWithBufferOfBracketIOStream #-}
400toChunksWithBufferOfBracketIOStream :: Handle -> Handle -> IO ()
401toChunksWithBufferOfBracketIOStream inh devNull =
402 let readEx = IP.bracketIO (return ()) (\_ -> hClose inh)
403 (\_ -> IFH.toChunksWithBufferOf (256*1024) inh)
404 in S.fold (IFH.writeChunks devNull) $ readEx
406o_1_space_copy_exceptions_toChunks :: BenchEnv -> [Benchmark]
407o_1_space_copy_exceptions_toChunks env =
408 [ bgroup "copy/exceptions/stream/toChunks"
409 [ mkBench "bracket (256K)" env $ \inH _ ->
410 toChunksWithBufferOfBracketStream inH (nullH env)
411 , mkBench "bracketIO (256K)" env $ \inH _ ->
412 toChunksWithBufferOfBracketIOStream inH (nullH env)
416-------------------------------------------------------------------------------
418-------------------------------------------------------------------------------
420-- | Get the last byte from a file bytestream.
421{-# INLINE readLast #-}
422readLast :: Handle -> IO (Maybe Word8)
423readLast = S.last . S.unfold FH.read
426inspect $ hasNoTypeClasses 'readLast
427inspect $ 'readLast `hasNoType` ''Step
428inspect $ 'readLast `hasNoType` ''AT.FlattenState
429inspect $ 'readLast `hasNoType` ''D.ConcatMapUState
432-- assert that flattenArrays constructors are not present
433-- | Count the number of bytes in a file.
434{-# INLINE readCountBytes #-}
435readCountBytes :: Handle -> IO Int
436readCountBytes = S.length . S.unfold FH.read
439inspect $ hasNoTypeClasses 'countBytes
440inspect $ 'countBytes `hasNoType` ''Step
441inspect $ 'countBytes `hasNoType` ''AT.FlattenState
442inspect $ 'countBytes `hasNoType` ''D.ConcatMapUState
445-- | Count the number of lines in a file.
446{-# INLINE readCountLines #-}
447readCountLines :: Handle -> IO Int
455inspect $ hasNoTypeClasses 'readCountLines
456inspect $ 'readCountLines `hasNoType` ''Step
457inspect $ 'readCountLines `hasNoType` ''AT.FlattenState
458inspect $ 'readCountLines `hasNoType` ''D.ConcatMapUState
461-- | Count the number of words in a file.
462{-# INLINE readCountWords #-}
463readCountWords :: Handle -> IO Int
471inspect $ hasNoTypeClasses 'readCountWords
472-- inspect $ 'readCountWords `hasNoType` ''Step
473-- inspect $ 'readCountWords `hasNoType` ''D.ConcatMapUState
476-- | Sum the bytes in a file.
477{-# INLINE readSumBytes #-}
478readSumBytes :: Handle -> IO Word8
479readSumBytes = S.sum . S.unfold FH.read
482inspect $ hasNoTypeClasses 'readSumBytes
483inspect $ 'readSumBytes `hasNoType` ''Step
484inspect $ 'readSumBytes `hasNoType` ''AT.FlattenState
485inspect $ 'readSumBytes `hasNoType` ''D.ConcatMapUState
488-- XXX If we have two benchmarks using S.drain in one benchmark group then
489-- somehow GHC ends up delaying the inlining of readDrain. since S.drain has an
490-- INLINE[2] for proper rule firing, that does not work well because of delyaed
491-- inlining and the code does not fuse. We need some way of propagating the
492-- inline phase information up so that we can expedite inlining of the callers
493-- too automatically. The minimal example for the problem can be created by
494-- using just two benchmarks in a bench group both using "readDrain".
495{-# INLINE[2] readDrain #-}
496readDrain :: Handle -> IO ()
497readDrain inh = S.drain $ S.unfold FH.read inh
499{-# INLINE[2] readDecodeLatin1 #-}
500readDecodeLatin1 :: Handle -> IO ()
501readDecodeLatin1 inh =
504 $ S.unfold FH.read inh
506{-# INLINE[2] readDecodeUtf8Lax #-}
507readDecodeUtf8Lax :: Handle -> IO ()
508readDecodeUtf8Lax inh =
511 $ S.unfold FH.read inh
514inspect $ hasNoTypeClasses 'readDecodeUtf8Lax
515-- inspect $ 'readDecodeUtf8Lax `hasNoType` ''Step
516-- inspect $ 'readDecodeUtf8Lax `hasNoType` ''AT.FlattenState
517-- inspect $ 'readDecodeUtf8Lax `hasNoType` ''D.ConcatMapUState
520o_1_space_reduce_read :: BenchEnv -> [Benchmark]
521o_1_space_reduce_read env =
522 [ bgroup "reduce/read"
523 [ -- read raw bytes without any decoding
524 mkBench "S.drain" env $ \inh _ ->
526 , mkBench "S.last" env $ \inh _ ->
528 , mkBench "S.sum" env $ \inh _ ->
531 -- read with Latin1 decoding
532 , mkBench "SS.decodeLatin1" env $ \inh _ ->
534 , mkBench "S.length" env $ \inh _ ->
536 , mkBench "US.lines . SS.decodeLatin1" env $ \inh _ ->
538 , mkBenchSmall "US.words . SS.decodeLatin1" env $ \inh _ ->
541 -- read with utf8 decoding
542 , mkBenchSmall "SS.decodeUtf8Lax" env $ \inh _ ->
543 readDecodeUtf8Lax inh
547-------------------------------------------------------------------------------
549-------------------------------------------------------------------------------
551-- | Count the number of lines in a file.
552{-# INLINE toChunksConcatUnfoldCountLines #-}
553toChunksConcatUnfoldCountLines :: Handle -> IO Int
554toChunksConcatUnfoldCountLines inh =
558 -- XXX replace with toBytes
559 $ S.concatUnfold A.read (IFH.toChunks inh)
562inspect $ hasNoTypeClasses 'countLinesU
563inspect $ 'countLinesU `hasNoType` ''Step
564inspect $ 'countLinesU `hasNoType` ''D.ConcatMapUState
567o_1_space_reduce_toBytes :: BenchEnv -> [Benchmark]
568o_1_space_reduce_toBytes env =
569 [ bgroup "reduce/toBytes"
570 [ mkBench "US.lines . SS.decodeLatin1" env $ \inh _ ->
571 toChunksConcatUnfoldCountLines inh
575-------------------------------------------------------------------------------
576-- reduce after grouping in chunks
577-------------------------------------------------------------------------------
579{-# INLINE chunksOfSum #-}
580chunksOfSum :: Int -> Handle -> IO Int
581chunksOfSum n inh = S.length $ S.chunksOf n FL.sum (S.unfold FH.read inh)
583{-# INLINE parseManyChunksOfSum #-}
584parseManyChunksOfSum :: Int -> Handle -> IO Int
585parseManyChunksOfSum n inh =
586 S.length $ IP.parseMany (PR.take n FL.sum) (S.unfold FH.read inh)
588-- | Slice in chunks of size n and get the count of chunks.
589{-# INLINE chunksOf #-}
590chunksOf :: Int -> Handle -> IO Int
592 -- writeNUnsafe gives 2.5x boost here over writeN.
593 -- XXX replace with S.arraysOf
594 S.length $ S.chunksOf n (AT.writeNUnsafe n) (S.unfold FH.read inh)
597inspect $ hasNoTypeClasses 'chunksOf
598inspect $ 'chunksOf `hasNoType` ''Step
599inspect $ 'chunksOf `hasNoType` ''AT.FlattenState
600inspect $ 'chunksOf `hasNoType` ''D.ConcatMapUState
601inspect $ 'chunksOf `hasNoType` ''GroupState
604-- This is to make sure that the concatMap in FH.read, groupsOf and foldlM'
607-- | Slice in chunks of size n and get the count of chunks.
608{-# INLINE _chunksOfD #-}
609_chunksOfD :: Int -> Handle -> IO Int
611 D.foldlM' (\i _ -> return $ i + 1) (return 0)
612 $ D.groupsOf n (AT.writeNUnsafe n)
613 $ D.fromStreamK (S.unfold FH.read inh)
616inspect $ hasNoTypeClasses '_chunksOfD
617inspect $ '_chunksOfD `hasNoType` ''Step
618inspect $ '_chunksOfD `hasNoType` ''GroupState
619inspect $ '_chunksOfD `hasNoType` ''AT.FlattenState
620inspect $ '_chunksOfD `hasNoType` ''D.ConcatMapUState
623o_1_space_reduce_read_grouped :: BenchEnv -> [Benchmark]
624o_1_space_reduce_read_grouped env =
625 [ bgroup "reduce/read/chunks"
626 [ mkBench ("S.chunksOf " ++ show (bigSize env) ++ " FL.sum") env $
628 chunksOfSum (bigSize env) inh
629 , mkBench "S.chunksOf 1 FL.sum" env $ \inh _ ->
632 -- Chunk using parsers
633 , mkBenchSmall ("S.parseMany (PR.take " ++ show (bigSize env) ++ " FL.sum)")
635 parseManyChunksOfSum (bigSize env) inh
636 , mkBench "S.parseMany (PR.take 1 FL.sum)" env $ \inh _ ->
637 parseManyChunksOfSum 1 inh
639 -- folding chunks to arrays
640 , mkBenchSmall "S.arraysOf 1" env $ \inh _ ->
642 , mkBench "S.arraysOf 10" env $ \inh _ ->
644 , mkBench "S.arraysOf 1000" env $ \inh _ ->
649-------------------------------------------------------------------------------
651-------------------------------------------------------------------------------
653-- | Send the file contents to /dev/null
654{-# INLINE readWriteNull #-}
655readWriteNull :: Handle -> Handle -> IO ()
656readWriteNull inh devNull = S.fold (FH.write devNull) $ S.unfold FH.read inh
659inspect $ hasNoTypeClasses 'readWriteNull
660inspect $ 'readWriteNull `hasNoType` ''Step
661inspect $ 'readWriteNull `hasNoType` ''AT.FlattenState
662inspect $ 'readWriteNull `hasNoType` ''D.ConcatMapUState
666{-# INLINE copyStream #-}
667copyStream :: Handle -> Handle -> IO ()
668copyStream inh outh = S.fold (FH.write outh) (S.unfold FH.read inh)
671inspect $ hasNoTypeClasses 'copyStream
672inspect $ 'copyStream `hasNoType` ''Step
673inspect $ 'copyStream `hasNoType` ''AT.FlattenState
674inspect $ 'copyStream `hasNoType` ''D.ConcatMapUState
678{-# INLINE copyStreamLatin1 #-}
679copyStreamLatin1 :: Handle -> Handle -> IO ()
680copyStreamLatin1 inh outh =
681 S.fold (FH.write outh)
684 $ S.unfold FH.read inh
687inspect $ hasNoTypeClasses 'copyStreamLatin1
688inspect $ 'copyStreamLatin1 `hasNoType` ''Step
689inspect $ 'copyStreamLatin1 `hasNoType` ''AT.FlattenState
690inspect $ 'copyStreamLatin1 `hasNoType` ''D.ConcatMapUState
694{-# INLINE _copyStreamUtf8 #-}
695_copyStreamUtf8 :: Handle -> Handle -> IO ()
696_copyStreamUtf8 inh outh =
697 S.fold (FH.write outh)
700 $ S.unfold FH.read inh
703inspect $ hasNoTypeClasses '_copyStreamUtf8
704-- inspect $ '_copyStreamUtf8 `hasNoType` ''Step
705-- inspect $ '_copyStreamUtf8 `hasNoType` ''AT.FlattenState
706-- inspect $ '_copyStreamUtf8 `hasNoType` ''D.ConcatMapUState
710{-# INLINE copyStreamUtf8Lax #-}
711copyStreamUtf8Lax :: Handle -> Handle -> IO ()
712copyStreamUtf8Lax inh outh =
713 S.fold (FH.write outh)
716 $ S.unfold FH.read inh
719inspect $ hasNoTypeClasses 'copyStreamUtf8Lax
720-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''Step
721-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''AT.FlattenState
722-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''D.ConcatMapUState
725o_1_space_copy_read :: BenchEnv -> [Benchmark]
726o_1_space_copy_read env =
728 [ mkBench "rawToNull" env $ \inh _ ->
729 readWriteNull inh (nullH env)
730 , mkBench "rawToFile" env $ \inh outh ->
732 -- This needs an ascii file, as decode just errors out.
733 , mkBench "SS.encodeLatin1 . SS.decodeLatin1" env $ \inh outh ->
734 copyStreamLatin1 inh outh
736 , mkBench "copyUtf8" env $ \inh outh ->
737 _copyStreamUtf8 inh outh
739 , mkBenchSmall "SS.encodeUtf8 . SS.decodeUtf8Lax" env $ \inh outh ->
740 copyStreamUtf8Lax inh outh
744-------------------------------------------------------------------------------
746-------------------------------------------------------------------------------
748-- | Send the file contents to /dev/null
749{-# INLINE readFromBytesNull #-}
750readFromBytesNull :: Handle -> Handle -> IO ()
751readFromBytesNull inh devNull = IFH.fromBytes devNull $ S.unfold FH.read inh
754inspect $ hasNoTypeClasses 'catStreamWrite
755inspect $ 'catStreamWrite `hasNoType` ''Step
756inspect $ 'catStreamWrite `hasNoType` ''AT.FlattenState
757inspect $ 'catStreamWrite `hasNoType` ''D.ConcatMapUState
760o_1_space_copy_fromBytes :: BenchEnv -> [Benchmark]
761o_1_space_copy_fromBytes env =
762 [ bgroup "copy/fromBytes"
763 [ mkBench "rawToNull" env $ \inh _ ->
764 readFromBytesNull inh (nullH env)
768-------------------------------------------------------------------------------
770-------------------------------------------------------------------------------
772-- | Send the file contents to /dev/null with exception handling
773{-# INLINE readWriteOnExceptionUnfold #-}
774readWriteOnExceptionUnfold :: Handle -> Handle -> IO ()
775readWriteOnExceptionUnfold inh devNull =
776 let readEx = IUF.onException (\_ -> hClose inh) FH.read
777 in S.fold (FH.write devNull) $ S.unfold readEx inh
780inspect $ hasNoTypeClasses 'readWriteOnExceptionUnfold
781-- inspect $ 'readWriteOnExceptionUnfold `hasNoType` ''Step
782-- inspect $ 'readWriteOnExceptionUnfold `hasNoType` ''AT.FlattenState
783-- inspect $ 'readWriteOnExceptionUnfold `hasNoType` ''D.ConcatMapUState
786-- | Send the file contents to /dev/null with exception handling
787{-# INLINE readWriteHandleExceptionUnfold #-}
788readWriteHandleExceptionUnfold :: Handle -> Handle -> IO ()
789readWriteHandleExceptionUnfold inh devNull =
790 let handler (_e :: SomeException) = hClose inh >> return 10
791 readEx = IUF.handle (IUF.singletonM handler) FH.read
792 in S.fold (FH.write devNull) $ S.unfold readEx inh
795inspect $ hasNoTypeClasses 'readWriteHandleExceptionUnfold
796-- inspect $ 'readWriteHandleExceptionUnfold `hasNoType` ''Step
797-- inspect $ 'readWriteHandleExceptionUnfold `hasNoType` ''AT.FlattenState
798-- inspect $ 'readWriteHandleExceptionUnfold `hasNoType` ''D.ConcatMapUState
801-- | Send the file contents to /dev/null with exception handling
802{-# INLINE readWriteFinallyUnfold #-}
803readWriteFinallyUnfold :: Handle -> Handle -> IO ()
804readWriteFinallyUnfold inh devNull =
805 let readEx = IUF.finally (\_ -> hClose inh) FH.read
806 in S.fold (FH.write devNull) $ S.unfold readEx inh
809inspect $ hasNoTypeClasses 'readWriteFinallyUnfold
810-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''Step
811-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''AT.FlattenState
812-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''D.ConcatMapUState
815{-# INLINE readWriteFinallyIOUnfold #-}
816readWriteFinallyIOUnfold :: Handle -> Handle -> IO ()
817readWriteFinallyIOUnfold inh devNull =
818 let readEx = IUF.finallyIO (\_ -> hClose inh) FH.read
819 in S.fold (FH.write devNull) $ S.unfold readEx inh
821-- | Send the file contents to /dev/null with exception handling
822{-# INLINE readWriteBracketUnfold #-}
823readWriteBracketUnfold :: Handle -> Handle -> IO ()
824readWriteBracketUnfold inh devNull =
825 let readEx = IUF.bracket return (\_ -> hClose inh) FH.read
826 in S.fold (FH.write devNull) $ S.unfold readEx inh
829inspect $ hasNoTypeClasses 'readWriteBracketUnfold
830-- inspect $ 'readWriteBracketUnfold `hasNoType` ''Step
831-- inspect $ 'readWriteBracketUnfold `hasNoType` ''AT.FlattenState
832-- inspect $ 'readWriteBracketUnfold `hasNoType` ''D.ConcatMapUState
835{-# INLINE readWriteBracketIOUnfold #-}
836readWriteBracketIOUnfold :: Handle -> Handle -> IO ()
837readWriteBracketIOUnfold inh devNull =
838 let readEx = IUF.bracketIO return (\_ -> hClose inh) FH.read
839 in S.fold (FH.write devNull) $ S.unfold readEx inh
841o_1_space_copy_read_exceptions :: BenchEnv -> [Benchmark]
842o_1_space_copy_read_exceptions env =
843 [ bgroup "copy/read/exceptions"
844 [ mkBenchSmall "UF.onException" env $ \inh _ ->
845 readWriteOnExceptionUnfold inh (nullH env)
846 , mkBenchSmall "UF.handle" env $ \inh _ ->
847 readWriteHandleExceptionUnfold inh (nullH env)
848 , mkBenchSmall "UF.finally" env $ \inh _ ->
849 readWriteFinallyUnfold inh (nullH env)
850 , mkBenchSmall "UF.finallyIO" env $ \inh _ ->
851 readWriteFinallyIOUnfold inh (nullH env)
852 , mkBenchSmall "UF.bracket" env $ \inh _ ->
853 readWriteBracketUnfold inh (nullH env)
854 , mkBenchSmall "UF.bracketIO" env $ \inh _ ->
855 readWriteBracketIOUnfold inh (nullH env)
859-------------------------------------------------------------------------------
861-------------------------------------------------------------------------------
863-- | Send the file contents to /dev/null with exception handling
864{-# INLINE readWriteOnExceptionStream #-}
865readWriteOnExceptionStream :: Handle -> Handle -> IO ()
866readWriteOnExceptionStream inh devNull =
867 let readEx = S.onException (hClose inh) (S.unfold FH.read inh)
868 in S.fold (FH.write devNull) $ readEx
870-- | Send the file contents to /dev/null with exception handling
871{-# INLINE readWriteHandleExceptionStream #-}
872readWriteHandleExceptionStream :: Handle -> Handle -> IO ()
873readWriteHandleExceptionStream inh devNull =
874 let handler (_e :: SomeException) = S.yieldM (hClose inh >> return 10)
875 readEx = S.handle handler (S.unfold FH.read inh)
876 in S.fold (FH.write devNull) $ readEx
878-- | Send the file contents to /dev/null with exception handling
879{-# INLINE readWriteFinallyStream #-}
880readWriteFinallyStream :: Handle -> Handle -> IO ()
881readWriteFinallyStream inh devNull =
882 let readEx = S.finally (hClose inh) (S.unfold FH.read inh)
883 in S.fold (FH.write devNull) readEx
885{-# INLINE readWriteFinallyIOStream #-}
886readWriteFinallyIOStream :: Handle -> Handle -> IO ()
887readWriteFinallyIOStream inh devNull =
888 let readEx = IP.finallyIO (hClose inh) (S.unfold FH.read inh)
889 in S.fold (FH.write devNull) readEx
891-- | Send the file contents to /dev/null with exception handling
892{-# INLINE fromToBytesBracketStream #-}
893fromToBytesBracketStream :: Handle -> Handle -> IO ()
894fromToBytesBracketStream inh devNull =
895 let readEx = S.bracket (return ()) (\_ -> hClose inh)
896 (\_ -> IFH.toBytes inh)
897 in IFH.fromBytes devNull $ readEx
900inspect $ hasNoTypeClasses 'readWriteBracketStream
901-- inspect $ 'readWriteBracketStream `hasNoType` ''Step
904{-# INLINE fromToBytesBracketIOStream #-}
905fromToBytesBracketIOStream :: Handle -> Handle -> IO ()
906fromToBytesBracketIOStream inh devNull =
907 let readEx = IP.bracketIO (return ()) (\_ -> hClose inh)
908 (\_ -> IFH.toBytes inh)
909 in IFH.fromBytes devNull $ readEx
911o_1_space_copy_stream_exceptions :: BenchEnv -> [Benchmark]
912o_1_space_copy_stream_exceptions env =
913 [ bgroup "copy/read/exceptions"
914 [ mkBenchSmall "S.onException" env $ \inh _ ->
915 readWriteOnExceptionStream inh (nullH env)
916 , mkBenchSmall "S.handle" env $ \inh _ ->
917 readWriteHandleExceptionStream inh (nullH env)
918 , mkBenchSmall "S.finally" env $ \inh _ ->
919 readWriteFinallyStream inh (nullH env)
920 , mkBenchSmall "S.finallyIO" env $ \inh _ ->
921 readWriteFinallyIOStream inh (nullH env)
923 , bgroup "copy/fromToBytes/exceptions"
924 [ mkBenchSmall "S.bracket" env $ \inh _ ->
925 fromToBytesBracketStream inh (nullH env)
926 , mkBenchSmall "S.bracketIO" env $ \inh _ ->
927 fromToBytesBracketIOStream inh (nullH env)
931-------------------------------------------------------------------------------
932-- copy with group/ungroup transformations
933-------------------------------------------------------------------------------
935-- | Lines and unlines
936{-# INLINE copyChunksSplitInterposeSuffix #-}
937copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
938copyChunksSplitInterposeSuffix inh outh =
939 S.fold (IFH.writeWithBufferOf (1024*1024) outh)
940 $ AS.interposeSuffix 10
941 $ AS.splitOnSuffix 10
942 $ IFH.toChunksWithBufferOf (1024*1024) inh
945inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterposeSuffix [''Storable]
946-- inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
949-- | Words and unwords
950{-# INLINE copyChunksSplitInterpose #-}
951copyChunksSplitInterpose :: Handle -> Handle -> IO ()
952copyChunksSplitInterpose inh outh =
953 S.fold (IFH.writeWithBufferOf (1024*1024) outh)
955 -- XXX this is not correct word splitting combinator
957 $ IFH.toChunksWithBufferOf (1024*1024) inh
960inspect $ hasNoTypeClassesExcept 'copyChunksSplitInterpose [''Storable]
961-- inspect $ 'copyChunksSplitInterpose `hasNoType` ''Step
964o_1_space_copy_toChunks_group_ungroup :: BenchEnv -> [Benchmark]
965o_1_space_copy_toChunks_group_ungroup env =
966 [ bgroup "copy/toChunks/group-ungroup"
967 [ mkBench "AS.interposeSuffix . AS.splitOnSuffix" env $ \inh outh ->
968 copyChunksSplitInterposeSuffix inh outh
969 , mkBenchSmall "AS.interpose . AS.splitOn" env $ \inh outh ->
970 copyChunksSplitInterpose inh outh
974-------------------------------------------------------------------------------
975-- copy with group/ungroup transformations
976-------------------------------------------------------------------------------
978{-# INLINE linesUnlinesCopy #-}
979linesUnlinesCopy :: Handle -> Handle -> IO ()
980linesUnlinesCopy inh outh =
981 S.fold (FH.write outh)
983 $ IUS.unlines IUF.fromList
984 $ S.splitOnSuffix (== '\n') FL.toList
986 $ S.unfold FH.read inh
988{-# INLINE linesUnlinesArrayWord8Copy #-}
989linesUnlinesArrayWord8Copy :: Handle -> Handle -> IO ()
990linesUnlinesArrayWord8Copy inh outh =
991 S.fold (FH.write outh)
992 $ IP.interposeSuffix 10 A.read
993 $ S.splitOnSuffix (== 10) A.write
994 $ S.unfold FH.read inh
996-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
997-- | Lines and unlines
998{-# INLINE linesUnlinesArrayCharCopy #-}
999linesUnlinesArrayCharCopy :: Handle -> Handle -> IO ()
1000linesUnlinesArrayCharCopy inh outh =
1001 S.fold (FH.write outh)
1006 $ S.unfold FH.read inh
1009inspect $ hasNoTypeClassesExcept 'linesUnlinesArrayCharCopy [''Storable]
1010-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''Step
1011-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''AT.FlattenState
1012-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''D.ConcatMapUState
1015-- XXX to write this we need to be able to map decodeUtf8 on the A.read fold.
1016-- For that we have to write decodeUtf8 as a Pipe.
1018{-# INLINE linesUnlinesArrayUtf8Copy #-}
1019linesUnlinesArrayUtf8Copy :: Handle -> Handle -> IO ()
1020linesUnlinesArrayUtf8Copy inh outh =
1021 S.fold (FH.write outh)
1023 $ IP.intercalate (A.fromList [10]) (pipe SS.decodeUtf8P A.read)
1024 $ S.splitOnSuffix (== '\n') (IFL.lmap SS.encodeUtf8 A.write)
1026 $ S.unfold FH.read inh
1029foreign import ccall unsafe "u_iswspace"
1030 iswspace :: Int -> Int
1032-- Code copied from base/Data.Char to INLINE it
1033{-# INLINE isSpace #-}
1034isSpace :: Char -> Bool
1035-- isSpace includes non-breaking space
1036-- The magic 0x377 isn't really that magical. As of 2014, all the codepoints
1037-- at or below 0x377 have been assigned, so we shouldn't have to worry about
1038-- any new spaces appearing below there. It would probably be best to
1039-- use branchless ||, but currently the eqLit transformation will undo that,
1040-- so we'll do it like this until there's a way around that.
1042 | uc <= 0x377 = uc == 32 || uc - 0x9 <= 4 || uc == 0xa0
1043 | otherwise = iswspace (ord c) /= 0
1045 uc = fromIntegral (ord c) :: Word
1048isSp :: Word8 -> Bool
1049isSp = isSpace . chr . fromIntegral
1051-- | Word, unwords and copy
1052{-# INLINE wordsUnwordsCopyWord8 #-}
1053wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
1054wordsUnwordsCopyWord8 inh outh =
1055 S.fold (FH.write outh)
1056 $ IP.interposeSuffix 32 IUF.fromList
1057 $ S.wordsBy isSp FL.toList
1058 $ S.unfold FH.read inh
1061inspect $ hasNoTypeClasses 'wordsUnwordsCopyWord8
1062-- inspect $ 'wordsUnwordsCopyWord8 `hasNoType` ''Step
1063-- inspect $ 'wordsUnwordsCopyWord8 `hasNoType` ''D.ConcatMapUState
1066-- | Word, unwords and copy
1067{-# INLINE wordsUnwordsCopy #-}
1068wordsUnwordsCopy :: Handle -> Handle -> IO ()
1069wordsUnwordsCopy inh outh =
1070 S.fold (FH.write outh)
1072 $ IUS.unwords IUF.fromList
1073 -- XXX This pipeline does not fuse with wordsBy but fuses with splitOn
1074 -- with -funfolding-use-threshold=300. With wordsBy it does not fuse
1075 -- even with high limits for inlining and spec-constr ghc options. With
1076 -- -funfolding-use-threshold=400 it performs pretty well and there
1077 -- is no evidence in the core that a join point involving Step
1078 -- constructors is not getting inlined. Not being able to fuse at all in
1079 -- this case could be an unknown issue, need more investigation.
1080 $ S.wordsBy isSpace FL.toList
1081 -- -- $ S.splitOn isSpace FL.toList
1083 $ S.unfold FH.read inh
1086-- inspect $ hasNoTypeClasses 'wordsUnwordsCopy
1087-- inspect $ 'wordsUnwordsCopy `hasNoType` ''Step
1088-- inspect $ 'wordsUnwordsCopy `hasNoType` ''AT.FlattenState
1089-- inspect $ 'wordsUnwordsCopy `hasNoType` ''D.ConcatMapUState
1092{-# INLINE wordsUnwordsCharArrayCopy #-}
1093wordsUnwordsCharArrayCopy :: Handle -> Handle -> IO ()
1094wordsUnwordsCharArrayCopy inh outh =
1095 S.fold (FH.write outh)
1100 $ S.unfold FH.read inh
1102o_1_space_copy_read_group_ungroup :: BenchEnv -> [Benchmark]
1103o_1_space_copy_read_group_ungroup env =
1104 [ bgroup "copy/read/group-ungroup"
1105 [ mkBenchSmall "US.unlines . S.splitOnSuffix ([Word8])" env
1106 $ \inh outh -> linesUnlinesCopy inh outh
1107 , mkBenchSmall "S.interposeSuffix . S.splitOnSuffix(Array Word8)" env
1108 $ \inh outh -> linesUnlinesArrayWord8Copy inh outh
1109 , mkBenchSmall "UA.unlines . UA.lines (Array Char)" env
1110 $ \inh outh -> linesUnlinesArrayCharCopy inh outh
1112 , mkBenchSmall "S.interposeSuffix . S.wordsBy ([Word8])" env
1113 $ \inh outh -> wordsUnwordsCopyWord8 inh outh
1114 , mkBenchSmall "US.unwords . S.wordsBy ([Char])" env
1115 $ \inh outh -> wordsUnwordsCopy inh outh
1116 , mkBenchSmall "UA.unwords . UA.words (Array Char)" env
1117 $ \inh outh -> wordsUnwordsCharArrayCopy inh outh
1121-------------------------------------------------------------------------------
1122-- reduce with splitting transformations
1123-------------------------------------------------------------------------------
1126lf = fromIntegral (ord '\n')
1128toarr :: String -> A.Array Word8
1129toarr = A.fromList . map (fromIntegral . ord)
1131-- | Split on line feed.
1132{-# INLINE splitOn #-}
1133splitOn :: Handle -> IO Int
1135 (S.length $ S.splitOn (== lf) FL.drain
1136 $ S.unfold FH.read inh) -- >>= print
1139inspect $ hasNoTypeClasses 'splitOn
1140inspect $ 'splitOn `hasNoType` ''Step
1141inspect $ 'splitOn `hasNoType` ''AT.FlattenState
1142inspect $ 'splitOn `hasNoType` ''D.ConcatMapUState
1145-- | Split suffix on line feed.
1146{-# INLINE splitOnSuffix #-}
1147splitOnSuffix :: Handle -> IO Int
1149 (S.length $ S.splitOnSuffix (== lf) FL.drain
1150 $ S.unfold FH.read inh) -- >>= print
1153inspect $ hasNoTypeClasses 'splitOnSuffix
1154inspect $ 'splitOnSuffix `hasNoType` ''Step
1155inspect $ 'splitOnSuffix `hasNoType` ''AT.FlattenState
1156inspect $ 'splitOnSuffix `hasNoType` ''D.ConcatMapUState
1159-- | Split on line feed.
1160{-# INLINE parseManySepBy #-}
1161parseManySepBy :: Handle -> IO Int
1163 (S.length $ IP.parseMany (PR.sliceSepBy (== lf) FL.drain)
1164 (S.unfold FH.read inh)) -- >>= print
1167{-# INLINE wordsBy #-}
1168wordsBy :: Handle -> IO Int
1170 (S.length $ S.wordsBy isSp FL.drain
1171 $ S.unfold FH.read inh) -- >>= print
1174inspect $ hasNoTypeClasses 'wordsBy
1175inspect $ 'wordsBy `hasNoType` ''Step
1176inspect $ 'wordsBy `hasNoType` ''AT.FlattenState
1177inspect $ 'wordsBy `hasNoType` ''D.ConcatMapUState
1180-- | Split on a word8 sequence.
1181{-# INLINE splitOnSeq #-}
1182splitOnSeq :: String -> Handle -> IO Int
1184 (S.length $ IP.splitOnSeq (toarr str) FL.drain
1185 $ S.unfold FH.read inh) -- >>= print
1188-- inspect $ hasNoTypeClasses 'splitOnSeq
1189-- inspect $ 'splitOnSeq `hasNoType` ''Step
1190-- inspect $ 'splitOnSeq `hasNoType` ''AT.FlattenState
1191-- inspect $ 'splitOnSeq `hasNoType` ''D.ConcatMapUState
1194-- | Split on suffix sequence.
1195{-# INLINE splitOnSuffixSeq #-}
1196splitOnSuffixSeq :: String -> Handle -> IO Int
1197splitOnSuffixSeq str inh =
1198 (S.length $ IP.splitOnSuffixSeq (toarr str) FL.drain
1199 $ S.unfold FH.read inh) -- >>= print
1202-- inspect $ hasNoTypeClasses 'splitOnSuffixSeq
1203-- inspect $ 'splitOnSuffixSeq `hasNoType` ''Step
1204-- inspect $ 'splitOnSuffixSeq `hasNoType` ''AT.FlattenState
1205-- inspect $ 'splitOnSuffixSeq `hasNoType` ''D.ConcatMapUState
1208o_1_space_reduce_read_split :: BenchEnv -> [Benchmark]
1209o_1_space_reduce_read_split env =
1210 [ bgroup "reduce/read"
1211 [ mkBench "S.parseMany (PR.sliceSepBy (== lf) FL.drain)" env
1212 $ \inh _ -> parseManySepBy inh
1213 , mkBench "S.wordsBy isSpace FL.drain" env $ \inh _ ->
1215 , mkBench "S.splitOn (== lf) FL.drain" env $ \inh _ ->
1217 , mkBench "S.splitOnSuffix (== lf) FL.drain" env $ \inh _ ->
1219 , mkBench "S.splitOnSeq \"\" FL.drain" env $ \inh _ ->
1221 , mkBench "S.splitOnSuffixSeq \"\" FL.drain" env $ \inh _ ->
1222 splitOnSuffixSeq "" inh
1223 , mkBench "S.splitOnSeq \"\\n\" FL.drain" env $ \inh _ ->
1225 , mkBench "S.splitOnSuffixSeq \"\\n\" FL.drain" env $ \inh _ ->
1226 splitOnSuffixSeq "\n" inh
1227 , mkBench "S.splitOnSeq \"a\" FL.drain" env $ \inh _ ->
1229 , mkBench "S.splitOnSeq \"\\r\\n\" FL.drain" env $ \inh _ ->
1230 splitOnSeq "\r\n" inh
1231 , mkBench "S.splitOnSuffixSeq \"\\r\\n\" FL.drain" env $ \inh _ ->
1232 splitOnSuffixSeq "\r\n" inh
1233 , mkBench "S.splitOnSeq \"aa\" FL.drain" env $ \inh _ ->
1235 , mkBench "S.splitOnSeq \"aaaa\" FL.drain" env $ \inh _ ->
1236 splitOnSeq "aaaa" inh
1237 , mkBench "S.splitOnSeq \"abcdefgh\" FL.drain" env $ \inh _ ->
1238 splitOnSeq "abcdefgh" inh
1239 , mkBench "S.splitOnSeq \"abcdefghi\" FL.drain" env $ \inh _ ->
1240 splitOnSeq "abcdefghi" inh
1241 , mkBench "S.splitOnSeq \"catcatcatcatcat\" FL.drain" env $ \inh _ ->
1242 splitOnSeq "catcatcatcatcat" inh
1243 , mkBench "S.splitOnSeq \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
1244 env $ \inh _ -> splitOnSeq "abcdefghijklmnopqrstuvwxyz" inh
1245 , mkBenchSmall "S.splitOnSuffixSeq \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
1246 env $ \inh _ -> splitOnSuffixSeq "abcdefghijklmnopqrstuvwxyz" inh
1250-- | Split on a character sequence.
1251{-# INLINE splitOnSeqUtf8 #-}
1252splitOnSeqUtf8 :: String -> Handle -> IO Int
1253splitOnSeqUtf8 str inh =
1254 (S.length $ IP.splitOnSeq (A.fromList str) FL.drain
1255 $ IUS.decodeUtf8ArraysLenient
1256 $ IFH.toChunks inh) -- >>= print
1258o_1_space_reduce_toChunks_split :: BenchEnv -> [Benchmark]
1259o_1_space_reduce_toChunks_split env =
1260 [ bgroup "reduce/toChunks"
1261 [ mkBenchSmall ("S.splitOnSeqUtf8 \"abcdefgh\" FL.drain "
1262 ++ ". US.decodeUtf8ArraysLenient") env $ \inh _ ->
1263 splitOnSeqUtf8 "abcdefgh" inh
1264 , mkBenchSmall "S.splitOnSeqUtf8 \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
1265 env $ \inh _ -> splitOnSeqUtf8 "abcdefghijklmnopqrstuvwxyz" inh
1269-------------------------------------------------------------------------------
1271-------------------------------------------------------------------------------
1275 (_, cfg, benches) <- parseCLIOpts defaultStreamSize
1276 r <- lookupEnv "Benchmark.FileSystem.Handle.InputFile"
1279 Just inFileName -> return (inFileName, inFileName)
1281 -- XXX will this work on windows/msys?
1282 let cmd infile size =
1283 "mkdir -p " ++ scratchDir
1284 ++ "; test -e " ++ infile
1285 ++ " || { echo \"creating input file " ++ infile
1286 ++ "\" && dd if=/dev/random of=" ++ infile
1287 ++ " bs=" ++ show blockSize
1288 ++ " count=" ++ show (blockCount size)
1290 runProcess_ (shell (cmd inFileSmall smallFileSize))
1291 runProcess_ (shell (cmd inFileBig bigFileSize))
1292 return (inFileSmall, inFileBig)
1294 smallHandle <- openFile small ReadMode
1295 bigHandle <- openFile big ReadMode
1296 outHandle <- openFile outfile WriteMode
1297 devNull <- openFile "/dev/null" WriteMode
1299#if __GLASGOW_HASKELL__ >= 800
1300 ssize <- fromIntegral <$> getFileSize small
1301 bsize <- fromIntegral <$> getFileSize big
1303 let ssize = smallFileSize
1304 let bsize = bigFileSize
1307 ref <- newIORef $ RefHandles
1308 { smallInH = smallHandle
1309 , bigInH = bigHandle
1310 , outputH = outHandle
1320 runMode (mode cfg) cfg benches (allBenchmarks env)
1325 [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
1326 [ o_1_space_read_chunked env
1327 , o_1_space_copy_chunked env
1328 , o_1_space_copy_exceptions_readChunks env
1329 , o_1_space_copy_exceptions_toChunks env
1331 , o_1_space_reduce_read env
1332 , o_1_space_reduce_toBytes env
1333 , o_1_space_reduce_read_grouped env
1334 , o_1_space_reduce_read_split env
1335 , o_1_space_reduce_toChunks_split env
1337 , o_1_space_copy_read env
1338 , o_1_space_copy_fromBytes env
1339 , o_1_space_copy_read_exceptions env
1340 , o_1_space_copy_stream_exceptions env
1341 , o_1_space_copy_toChunks_group_ungroup env
1342 , o_1_space_copy_read_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