From 4a812c1b614a80a85170c96839bbaa6800443d5f Mon Sep 17 00:00:00 2001 From: Alexey Sharov Date: Thu, 27 Aug 2026 13:30:56 +0700 Subject: [PATCH] db/etl: stop the bufio read benchmarks allocating per field readFieldBufioU16 and U32 read the length prefix into a local array and hand it to io.ReadFull, which takes an io.Reader - so the array escapes and every field read costs an allocation. The mmap readers next to them slice the mapping directly and pay nothing, so the comparison the file exists to make was handing the bufio side a penalty that is not about buffered I/O at all. The caller owns lenBuf now. BenchmarkSequentialRead/val32/bufio_u16, two alternating rounds each: 57.3ms and 59.5ms before, 42.8ms and 42.0ms after - 8.4MB over 3947589 allocations becomes 525KB over 7. --- db/etl/read_bench_test.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/db/etl/read_bench_test.go b/db/etl/read_bench_test.go index ef2630fcbc6..8ed366bb1bb 100644 --- a/db/etl/read_bench_test.go +++ b/db/etl/read_bench_test.go @@ -204,12 +204,13 @@ func benchBufioU16(b *testing.B, fname string, bufSize int) { defer f.Close() r := bufio.NewReaderSize(f, bufSize) + lenBuf := make([]byte, 2) var buf []byte for { - if buf, err = readFieldBufioU16(r, buf); err != nil { + if buf, err = readFieldBufioU16(r, lenBuf, buf); err != nil { break } - if buf, err = readFieldBufioU16(r, buf); err != nil { + if buf, err = readFieldBufioU16(r, lenBuf, buf); err != nil { break } } @@ -224,20 +225,22 @@ func benchBufioU32(b *testing.B, fname string, bufSize int) { defer f.Close() r := bufio.NewReaderSize(f, bufSize) + lenBuf := make([]byte, 4) var buf []byte for { - if buf, err = readFieldBufioU32(r, buf); err != nil { + if buf, err = readFieldBufioU32(r, lenBuf, buf); err != nil { break } - if buf, err = readFieldBufioU32(r, buf); err != nil { + if buf, err = readFieldBufioU32(r, lenBuf, buf); err != nil { break } } } -func readFieldBufioU16(r *bufio.Reader, buf []byte) ([]byte, error) { - var lenBuf [2]byte - if _, err := io.ReadFull(r, lenBuf[:]); err != nil { +func readFieldBufioU16(r *bufio.Reader, lenBuf, buf []byte) ([]byte, error) { + // lenBuf comes from the caller: io.ReadFull takes an io.Reader, so a local + // array escapes and costs an allocation on every field read. + if _, err := io.ReadFull(r, lenBuf); err != nil { return buf, err } n := int(*(*uint16)(unsafe.Pointer(&lenBuf[0]))) @@ -255,9 +258,10 @@ func readFieldBufioU16(r *bufio.Reader, buf []byte) ([]byte, error) { return buf, nil } -func readFieldBufioU32(r *bufio.Reader, buf []byte) ([]byte, error) { - var lenBuf [4]byte - if _, err := io.ReadFull(r, lenBuf[:]); err != nil { +func readFieldBufioU32(r *bufio.Reader, lenBuf, buf []byte) ([]byte, error) { + // lenBuf comes from the caller: io.ReadFull takes an io.Reader, so a local + // array escapes and costs an allocation on every field read. + if _, err := io.ReadFull(r, lenBuf); err != nil { return buf, err } n := int(*(*uint32)(unsafe.Pointer(&lenBuf[0])))