on master help sign in
Set up a good default buffer size.
a9885a9Bryan O'Sullivan
Data/Text/IO.hs+27−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}
1+{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
2-- |
2-- |
3-- Module : Data.Text.IO
3-- Module : Data.Text.IO
4-- Copyright : (c) Bryan O'Sullivan 2009,
4-- Copyright : (c) Bryan O'Sullivan 2009,
@@ -32,15 +32,16 @@ module Data.Text.IO
32 ) where
32 ) where
33
33
34import Data.Text (Text)
34import Data.Text (Text)
35−import Prelude hiding (appendFile, getContents, getLine, interact, putStr,
35+import Prelude hiding (appendFile, catch, getContents, getLine, interact,
36− putStrLn, readFile, writeFile)
36+ putStr, putStrLn, readFile, writeFile)
37import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
37import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
38 withFile)
38 withFile)
39#if __GLASGOW_HASKELL__ <= 610
39#if __GLASGOW_HASKELL__ <= 610
40import qualified Data.ByteString.Char8 as B
40import qualified Data.ByteString.Char8 as B
41import Data.Text.Encoding (decodeUtf8, encodeUtf8)
41import Data.Text.Encoding (decodeUtf8, encodeUtf8)
42#else
42#else
43−import Control.Exception (throw)
43+import Control.Exception (catch, throw)
44+import Control.Monad (liftM2, when)
44import Data.IORef (readIORef, writeIORef)
45import Data.IORef (readIORef, writeIORef)
45import qualified Data.Text as T
46import qualified Data.Text as T
46import Data.Text.Fusion (stream)
47import Data.Text.Fusion (stream)
@@ -49,11 +50,13 @@ import Data.Text.IO.Internal (hGetLineWith, readChunk)
49import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
50import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
50 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
51 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
51 writeCharBuf)
52 writeCharBuf)
53+import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
52import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
54import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
53 wantWritableHandle)
55 wantWritableHandle)
54import GHC.IO.Handle.Text (commitBuffer')
56import GHC.IO.Handle.Text (commitBuffer')
55import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
57import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
56 Newline(..))
58 Newline(..))
59+import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
57import System.IO.Error (isEOFError)
60import System.IO.Error (isEOFError)
58#endif
61#endif
59
62
@@ -87,7 +90,9 @@ hGetContents :: Handle -> IO Text
87#if __GLASGOW_HASKELL__ <= 610
90#if __GLASGOW_HASKELL__ <= 610
88hGetContents = fmap decodeUtf8 . B.hGetContents
91hGetContents = fmap decodeUtf8 . B.hGetContents
89#else
92#else
93+hGetContents h = do
94+ chooseGoodBuffering h
90−hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
95+ wantReadableHandle "hGetContents" h $ \hh -> do
91 (hh',ts) <- readAll hh
96 (hh',ts) <- readAll hh
92 return (hh',T.concat ts)
97 return (hh',T.concat ts)
93 where
98 where
@@ -106,6 +111,23 @@ hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
106 else throw (augmentIOError e "hGetContents" h)
111 else throw (augmentIOError e "hGetContents" h)
107#endif
112#endif
108
113
114+-- | Use a more efficient buffer size if we're reading in
115+-- block-buffered mode with the default buffer size. When we can
116+-- determine the size of the handle we're reading, set the buffer size
117+-- to that, so that we can read the entire file in one chunk.
118+-- Otherwise, use a buffer size of at least 16KB.
119+chooseGoodBuffering :: Handle -> IO ()
120+chooseGoodBuffering h = do
121+ bufMode <- hGetBuffering h
122+ case bufMode of
123+ BlockBuffering Nothing -> do
124+ d <- catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->
125+ if ioe_type e == InappropriateType
126+ then return 16384 -- faster than the 2KB default
127+ else throw e
128+ when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d
129+ _ -> return ()
130+
109-- | Read a single line from a handle.
131-- | Read a single line from a handle.
110hGetLine :: Handle -> IO Text
132hGetLine :: Handle -> IO Text
111#if __GLASGOW_HASKELL__ <= 610
133#if __GLASGOW_HASKELL__ <= 610
Data/Text/Lazy/IO.hs+15−4
@@ -44,6 +44,7 @@ import qualified Data.ByteString.Char8 as S8
44import qualified Data.ByteString.Lazy.Char8 as L8
44import qualified Data.ByteString.Lazy.Char8 as L8
45#else
45#else
46import Control.Exception (throw)
46import Control.Exception (throw)
47+import Control.Monad (when)
47import Data.IORef (readIORef)
48import Data.IORef (readIORef)
48import Data.Text.IO.Internal (hGetLineWith, readChunk)
49import Data.Text.IO.Internal (hGetLineWith, readChunk)
49import Data.Text.Lazy.Internal (chunk, empty)
50import Data.Text.Lazy.Internal (chunk, empty)
@@ -52,6 +53,7 @@ import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)
52import GHC.IO.Handle.Internals (augmentIOError, hClose_help,
53import GHC.IO.Handle.Internals (augmentIOError, hClose_help,
53 wantReadableHandle, withHandle)
54 wantReadableHandle, withHandle)
54import GHC.IO.Handle.Types (Handle__(..), HandleType(..))
55import GHC.IO.Handle.Types (Handle__(..), HandleType(..))
56+import System.IO (BufferMode(..), hGetBuffering, hSetBuffering)
55import System.IO.Error (isEOFError)
57import System.IO.Error (isEOFError)
56import System.IO.Unsafe (unsafeInterleaveIO)
58import System.IO.Unsafe (unsafeInterleaveIO)
57#endif
59#endif
@@ -76,10 +78,19 @@ hGetContents :: Handle -> IO Text
76#if __GLASGOW_HASKELL__ <= 610
78#if __GLASGOW_HASKELL__ <= 610
77hGetContents = fmap decodeUtf8 . L8.hGetContents
79hGetContents = fmap decodeUtf8 . L8.hGetContents
78#else
80#else
79−hGetContents h =
81+hGetContents h = do
82+ chooseGoodBuffering h
80− wantReadableHandle "hGetContents" h $ \hh -> do
83+ wantReadableHandle "hGetContents" h $ \hh -> do
81− ts <- lazyRead h
84+ ts <- lazyRead h
82− return (hh{haType=SemiClosedHandle}, ts)
85+ return (hh{haType=SemiClosedHandle}, ts)
86+
87+-- | Use a more efficient buffer size if we're reading in
88+-- block-buffered mode with the default buffer size.
89+chooseGoodBuffering :: Handle -> IO ()
90+chooseGoodBuffering h = do
91+ bufMode <- hGetBuffering h
92+ when (bufMode == BlockBuffering Nothing) $
93+ hSetBuffering h (BlockBuffering (Just 16384))
83
94
84lazyRead :: Handle -> IO Text
95lazyRead :: Handle -> IO Text
85lazyRead h = unsafeInterleaveIO $
96lazyRead h = unsafeInterleaveIO $
tests/benchmarks/FileRead.hs−1
@@ -47,7 +47,6 @@ bytestring h = do
47main = do
47main = do
48 (name : file : _) <- getArgs
48 (name : file : _) <- getArgs
49 h <- openFile file ReadMode
49 h <- openFile file ReadMode
50− hSetBuffering h (BlockBuffering (Just 16384))
51 case name of
50 case name of
52 "bs" -> bytestring h
51 "bs" -> bytestring h
53 "lbs" -> lbytestring h
52 "lbs" -> lbytestring h