From 2d026a4ea5b28680c1ed7660f720c4cb028c5b35 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Tue, 14 Sep 2021 14:26:11 -0700 Subject: bytes: rely on runtime.growslice for growing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than naively making a slice of capacity 2*c+n, rely on the append(..., make(...)) pattern to allocate a slice that aligns up to the closest size class. Performance: name old time/op new time/op delta BufferWriteBlock/N4096 3.03µs ± 6% 2.04µs ± 6% -32.60% (p=0.000 n=10+10) BufferWriteBlock/N65536 47.8µs ± 6% 28.1µs ± 2% -41.32% (p=0.000 n=9+8) BufferWriteBlock/N1048576 844µs ± 7% 510µs ± 5% -39.59% (p=0.000 n=8+9) name old alloc/op new alloc/op delta BufferWriteBlock/N4096 12.3kB ± 0% 7.2kB ± 0% -41.67% (p=0.000 n=10+10) BufferWriteBlock/N65536 258kB ± 0% 130kB ± 0% -49.60% (p=0.000 n=10+10) BufferWriteBlock/N1048576 4.19MB ± 0% 2.10MB ± 0% -49.98% (p=0.000 n=10+8) name old allocs/op new allocs/op delta BufferWriteBlock/N4096 3.00 ± 0% 3.00 ± 0% ~ (all equal) BufferWriteBlock/N65536 7.00 ± 0% 7.00 ± 0% ~ (all equal) BufferWriteBlock/N1048576 11.0 ± 0% 11.0 ± 0% ~ (all equal) The performance is faster since the growth rate is capped at 2x, while previously it could grow by amounts potentially much greater than 2x, leading to significant amounts of memory waste and extra copying. Credit goes to Martin Möhrmann for suggesting the append(b, make([]T, n)...) pattern. Fixes #42984 Updates #51462 Change-Id: I7b23f75dddbf53f8b8b93485bb1a1fff9649b96b Reviewed-on: https://go-review.googlesource.com/c/go/+/349994 Trust: Joseph Tsai Trust: Josh Bleecher Snyder Reviewed-by: Bryan Mills Reviewed-by: Ian Lance Taylor Reviewed-by: Josh Bleecher Snyder --- src/bytes/buffer_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/bytes/buffer_test.go') diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index 9c9b7440ff..c0855007c1 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -672,3 +672,18 @@ func BenchmarkBufferFullSmallReads(b *testing.B) { } } } + +func BenchmarkBufferWriteBlock(b *testing.B) { + block := make([]byte, 1024) + for _, n := range []int{1 << 12, 1 << 16, 1 << 20} { + b.Run(fmt.Sprintf("N%d", n), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + var bb Buffer + for bb.Len() < n { + bb.Write(block) + } + } + }) + } +} -- cgit v1.3