diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2018-03-05 07:40:14 -0800 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2018-03-06 18:59:03 +0000 |
commit | b85433975aedc2be2971093b6bbb0a7dc264c8fd (patch) | |
tree | 961c9a4338f1d84cd30c8ec6e24cfb4b7fd6d168 /src/encoding/binary | |
parent | f7739c07c8f6ef9bfa28e8c4a4527b01cf3991bc (diff) | |
download | go-b85433975aedc2be2971093b6bbb0a7dc264c8fd.tar.gz go-b85433975aedc2be2971093b6bbb0a7dc264c8fd.zip |
encoding/binary: use an offset instead of slicing
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 <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/encoding/binary')
-rw-r--r-- | src/encoding/binary/binary.go | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index 2d01a3cb28..22fd7f2a80 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. |