From b85433975aedc2be2971093b6bbb0a7dc264c8fd Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 5 Mar 2018 07:40:14 -0800 Subject: [PATCH] encoding/binary: use an offset instead of slicing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While running make.bash, over 5% of all pointer writes come from encoding/binary doing struct reads. This change replaces slicing during such reads with an offset. This avoids updating the slice pointer with every struct field read or write. This has no impact when the write barrier is off. Running the benchmarks with GOGC=1, however, shows significant improvement: name old time/op new time/op delta ReadStruct-8 13.2µs ± 6% 10.1µs ± 5% -23.24% (p=0.000 n=10+10) name old speed new speed delta ReadStruct-8 5.69MB/s ± 6% 7.40MB/s ± 5% +30.18% (p=0.000 n=10+10) Change-Id: I22904263196bfeddc38abe8989428e263aee5253 Reviewed-on: https://go-review.googlesource.com/98757 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/encoding/binary/binary.go | 56 ++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index 2d01a3cb287..22fd7f2a800 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -419,70 +419,71 @@ func sizeof(t reflect.Type) int { } type coder struct { - order ByteOrder - buf []byte + order ByteOrder + buf []byte + offset int } type decoder coder type encoder coder func (d *decoder) bool() bool { - x := d.buf[0] - d.buf = d.buf[1:] + x := d.buf[d.offset] + d.offset++ return x != 0 } func (e *encoder) bool(x bool) { if x { - e.buf[0] = 1 + e.buf[e.offset] = 1 } else { - e.buf[0] = 0 + e.buf[e.offset] = 0 } - e.buf = e.buf[1:] + e.offset++ } func (d *decoder) uint8() uint8 { - x := d.buf[0] - d.buf = d.buf[1:] + x := d.buf[d.offset] + d.offset++ return x } func (e *encoder) uint8(x uint8) { - e.buf[0] = x - e.buf = e.buf[1:] + e.buf[e.offset] = x + e.offset++ } func (d *decoder) uint16() uint16 { - x := d.order.Uint16(d.buf[0:2]) - d.buf = d.buf[2:] + x := d.order.Uint16(d.buf[d.offset : d.offset+2]) + d.offset += 2 return x } func (e *encoder) uint16(x uint16) { - e.order.PutUint16(e.buf[0:2], x) - e.buf = e.buf[2:] + e.order.PutUint16(e.buf[e.offset:e.offset+2], x) + e.offset += 2 } func (d *decoder) uint32() uint32 { - x := d.order.Uint32(d.buf[0:4]) - d.buf = d.buf[4:] + x := d.order.Uint32(d.buf[d.offset : d.offset+4]) + d.offset += 4 return x } func (e *encoder) uint32(x uint32) { - e.order.PutUint32(e.buf[0:4], x) - e.buf = e.buf[4:] + e.order.PutUint32(e.buf[e.offset:e.offset+4], x) + e.offset += 4 } func (d *decoder) uint64() uint64 { - x := d.order.Uint64(d.buf[0:8]) - d.buf = d.buf[8:] + x := d.order.Uint64(d.buf[d.offset : d.offset+8]) + d.offset += 8 return x } func (e *encoder) uint64(x uint64) { - e.order.PutUint64(e.buf[0:8], x) - e.buf = e.buf[8:] + e.order.PutUint64(e.buf[e.offset:e.offset+8], x) + e.offset += 8 } func (d *decoder) int8() int8 { return int8(d.uint8()) } @@ -646,15 +647,16 @@ func (e *encoder) value(v reflect.Value) { } func (d *decoder) skip(v reflect.Value) { - d.buf = d.buf[dataSize(v):] + d.offset += dataSize(v) } func (e *encoder) skip(v reflect.Value) { n := dataSize(v) - for i := range e.buf[0:n] { - e.buf[i] = 0 + zero := e.buf[e.offset : e.offset+n] + for i := range zero { + zero[i] = 0 } - e.buf = e.buf[n:] + e.offset += n } // intDataSize returns the size of the data required to represent the data when encoded.