encoding/gob: optimize decoding of []byte

The reflect.Value.Slice method unfortunately allocates every time
since it needs to place the slice header on the heap.
This is silly since gob immediately stores the result back into slice.
Instead, use the reflect.Value.SetLen method.

DecodeBytesSlice  75.0µs ± 2%  35.2µs ± 6%  -53.02%

Change-Id: I3ca0529d01bf978f2b76e215f52d369f458951ef
Reviewed-on: https://go-review.googlesource.com/c/go/+/345572
Trust: Joe Tsai <joetsai@digital-static.net>
Run-TryBot: Joe Tsai <joetsai@digital-static.net>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Joe Tsai 2021-08-26 20:26:32 -07:00
parent 2c60a99f72
commit 67f7e16bcc
2 changed files with 9 additions and 1 deletions

View file

@ -376,7 +376,7 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
if value.Cap() < n {
value.Set(reflect.MakeSlice(value.Type(), n, n))
} else {
value.Set(value.Slice(0, n))
value.SetLen(n)
}
if _, err := state.b.Read(value.Bytes()); err != nil {
errorf("error decoding []byte: %s", err)

View file

@ -280,6 +280,14 @@ func BenchmarkDecodeStringSlice(b *testing.B) {
benchmarkDecodeSlice(b, a)
}
func BenchmarkDecodeBytesSlice(b *testing.B) {
a := make([][]byte, 1000)
for i := range a {
a[i] = []byte("now is the time")
}
benchmarkDecodeSlice(b, a)
}
func BenchmarkDecodeInterfaceSlice(b *testing.B) {
a := make([]interface{}, 1000)
for i := range a {