Skip to content

hSetBuffering appears to do nothing

Summary

It seems that hSetBuffering has almost none of the expected effects.

Sample code:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.ByteString (hPut)
import Data.Foldable (for_)
import System.IO

main = do
  withBinaryFile "myfile" WriteMode $ \h -> do
    hSetBuffering h (BlockBuffering (Just (1024 * 1024))) -- unexpectedly makes write syscalls smaller than 1 MiB
    -- hSetBuffering h (BlockBuffering (Just (1024))) -- unexpectedly makes write syscalls larger than 1 KiB
    -- hSetBuffering h LineBuffering -- unexpectedly flushes every `hPut
    for_ [1..10000] $ \_ -> do
      hPut h "abcdefghijklmn123456789"

On GHC 9.0.2 and 9.5.20220921 respectively on NixOS Linux, as described in the code comments:

  • When I set a 1 MiB buffer, I continue to observe write() syscalls in strace that are too small (8188 Bytes):
    write(4</home/niklas/src/haskell/hSetBuffering/myfile>, "abcdefghijklmn123456789abcdefghi"..., 8188) = 8188
    write(4</home/niklas/src/haskell/hSetBuffering/myfile>, "abcdefghijklmn123456789abcdefghi"..., 8188) = 8188
  • When I set a 1 KiB buffer, the same (now the writes are larger than desired).
  • When I set LineBuffering, I observe that write syscalls are being done even though no \n is encountered:
    write(4</home/niklas/src/haskell/hSetBuffering/myfile>, "abcdefghijklmn123456789", 23) = 23
    write(4</home/niklas/src/haskell/hSetBuffering/myfile>, "abcdefghijklmn123456789", 23) = 23

Am I missing something?

Edited by Niklas Hambüchen
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information