on master help sign in
Set up a good default buffer size.

--HG-- extra : convert_revision : aff9f9c0e9911bdfe71d32067c112378cc2c328d

commita9885a91ad6a185df0ca59e3c61073d1add91b3a authorBryan O'Sullivan <bos@serpentine.com> dateSun 15 Aug 2010, 17:44 (16 years ago) parentd6c3180
3 files changed+42−10
Data/Text/IO.hs+27−5 Data/Text/Lazy/IO.hs+15−4 tests/benchmarks/FileRead.hs−1
Data/Text/IO.hs+27−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}
1+{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
22-- |
33-- Module : Data.Text.IO
44-- Copyright : (c) Bryan O'Sullivan 2009,
@@ -32,15 +32,16 @@ module Data.Text.IO
3232 ) where
3333
3434import Data.Text (Text)
35−import Prelude hiding (appendFile, getContents, getLine, interact, putStr,
36− putStrLn, readFile, writeFile)
35+import Prelude hiding (appendFile, catch, getContents, getLine, interact,
36+ putStr, putStrLn, readFile, writeFile)
3737import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
3838 withFile)
3939#if __GLASGOW_HASKELL__ <= 610
4040import qualified Data.ByteString.Char8 as B
4141import Data.Text.Encoding (decodeUtf8, encodeUtf8)
4242#else
43−import Control.Exception (throw)
43+import Control.Exception (catch, throw)
44+import Control.Monad (liftM2, when)
4445import Data.IORef (readIORef, writeIORef)
4546import qualified Data.Text as T
4647import Data.Text.Fusion (stream)
@@ -49,11 +50,13 @@ import Data.Text.IO.Internal (hGetLineWith, readChunk)
4950import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
5051 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
5152 writeCharBuf)
53+import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
5254import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
5355 wantWritableHandle)
5456import GHC.IO.Handle.Text (commitBuffer')
5557import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
5658 Newline(..))
59+import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
5760import System.IO.Error (isEOFError)
5861#endif
5962
@@ -87,7 +90,9 @@ hGetContents :: Handle -> IO Text
8790#if __GLASGOW_HASKELL__ <= 610
8891hGetContents = fmap decodeUtf8 . B.hGetContents
8992#else
90−hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
93+hGetContents h = do
94+ chooseGoodBuffering h
95+ wantReadableHandle "hGetContents" h $ \hh -> do
9196 (hh',ts) <- readAll hh
9297 return (hh',T.concat ts)
9398 where
@@ -106,6 +111,23 @@ hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
106111 else throw (augmentIOError e "hGetContents" h)
107112#endif
108113
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+
109131-- | Read a single line from a handle.
110132hGetLine :: Handle -> IO Text
111133#if __GLASGOW_HASKELL__ <= 610
Data/Text/Lazy/IO.hs+15−4
@@ -44,6 +44,7 @@ import qualified Data.ByteString.Char8 as S8
4444import qualified Data.ByteString.Lazy.Char8 as L8
4545#else
4646import Control.Exception (throw)
47+import Control.Monad (when)
4748import Data.IORef (readIORef)
4849import Data.Text.IO.Internal (hGetLineWith, readChunk)
4950import Data.Text.Lazy.Internal (chunk, empty)
@@ -52,6 +53,7 @@ import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)
5253import GHC.IO.Handle.Internals (augmentIOError, hClose_help,
5354 wantReadableHandle, withHandle)
5455import GHC.IO.Handle.Types (Handle__(..), HandleType(..))
56+import System.IO (BufferMode(..), hGetBuffering, hSetBuffering)
5557import System.IO.Error (isEOFError)
5658import System.IO.Unsafe (unsafeInterleaveIO)
5759#endif
@@ -76,10 +78,19 @@ hGetContents :: Handle -> IO Text
7678#if __GLASGOW_HASKELL__ <= 610
7779hGetContents = fmap decodeUtf8 . L8.hGetContents
7880#else
79−hGetContents h =
80− wantReadableHandle "hGetContents" h $ \hh -> do
81− ts <- lazyRead h
82− return (hh{haType=SemiClosedHandle}, ts)
81+hGetContents h = do
82+ chooseGoodBuffering h
83+ wantReadableHandle "hGetContents" h $ \hh -> do
84+ ts <- lazyRead h
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))
8394
8495lazyRead :: Handle -> IO Text
8596lazyRead h = unsafeInterleaveIO $
tests/benchmarks/FileRead.hs−1
@@ -47,7 +47,6 @@ bytestring h = do
4747main = do
4848 (name : file : _) <- getArgs
4949 h <- openFile file ReadMode
50− hSetBuffering h (BlockBuffering (Just 16384))
5150 case name of
5251 "bs" -> bytestring h
5352 "lbs" -> lbytestring h