From 67f7e16bcce0a3e68bf92e233ea16c8a9d2ac07a Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Thu, 26 Aug 2021 20:26:32 -0700 Subject: encoding/gob: optimize decoding of []byte MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Run-TryBot: Joe Tsai TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/encoding/gob/decode.go | 2 +- src/encoding/gob/timing_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index d2f6c749b1..4ef9ef7243 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -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) diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go index 3478bd247e..ceb21c4107 100644 --- a/src/encoding/gob/timing_test.go +++ b/src/encoding/gob/timing_test.go @@ -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 { -- cgit v1.2.3-54-g00ecf