aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
authorkwakubiney <kwakubiney@gmail.com>2024-03-11 22:53:08 +0000
committerGopher Robot <gobot@golang.org>2024-03-13 18:32:53 +0000
commit381ba9f64cce0e40889d0eec3efef4ca9bb0cf26 (patch)
treeee62ccfac652266d7f8c0450ab0bda944ed22b1d /src/encoding
parent4f07bb39539725dfff56b4f2a1b7ce05464a0e9b (diff)
downloadgo-381ba9f64cce0e40889d0eec3efef4ca9bb0cf26.tar.xz
encoding/binary: cache struct sizes to speed up Read and Write for slice of structs.
A lot of allocations happen in dataSize due to reflection. Cache the result of the function when encoding a slice of structs similar to what is done for struct types so that subsequent calls to dataSize can avoid allocations. │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ WriteSlice1000Structs-2 846.7µ ± 4% 856.4µ ± 3% ~ (p=0.602 n=20) │ old.txt │ new.txt │ │ B/s │ B/s vs base │ WriteSlice1000Structs-2 84.48Mi ± 4% 83.52Mi ± 3% ~ (p=0.602 n=20) │ old.txt │ new.txt │ │ B/op │ B/op vs base │ WriteSlice1000Structs-2 80.18Ki ± 0% 80.06Ki ± 0% -0.15% (p=0.000 n=20) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ WriteSlice1000Structs-2 16.000 ± 0% 1.000 ± 0% -93.75% (p=0.000 n=2 │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ ReadSlice1000Structs-2 847.4µ ± 4% 821.1µ ± 3% -3.10% (p=0.012 n=20) │ old.txt │ new.txt │ │ B/s │ B/s vs base │ ReadSlice1000Structs-2 84.40Mi ± 4% 87.11Mi ± 3% +3.20% (p=0.012 n=20) │ old.txt │ new.txt │ │ B/op │ B/op vs base │ ReadSlice1000Structs-2 80.12Ki ± 0% 80.00Ki ± 0% -0.15% (p=0.000 n=20) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ ReadSlice1000Structs-2 16.000 ± 0% 1.000 ± 0% -93.75% (p=0.000 n=20) Fixes #66253 Change-Id: I8227e61306db1fe103489ea4fee2429247c3debc Reviewed-on: https://go-review.googlesource.com/c/go/+/570855 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/binary/binary.go13
-rw-r--r--src/encoding/binary/binary_test.go25
2 files changed, 36 insertions, 2 deletions
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 59a6c654d2..634995a5bd 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -480,8 +480,17 @@ var structSize sync.Map // map[reflect.Type]int
func dataSize(v reflect.Value) int {
switch v.Kind() {
case reflect.Slice:
- if s := sizeof(v.Type().Elem()); s >= 0 {
- return s * v.Len()
+ t := v.Type().Elem()
+ if size, ok := structSize.Load(t); ok {
+ return size.(int) * v.Len()
+ }
+
+ size := sizeof(t)
+ if size >= 0 {
+ if t.Kind() == reflect.Struct {
+ structSize.Store(t, size)
+ }
+ return size * v.Len()
}
case reflect.Struct:
diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go
index 4b22b28843..6cd0b92fa3 100644
--- a/src/encoding/binary/binary_test.go
+++ b/src/encoding/binary/binary_test.go
@@ -631,6 +631,31 @@ func BenchmarkWriteStruct(b *testing.B) {
}
}
+func BenchmarkWriteSlice1000Structs(b *testing.B) {
+ slice := make([]Struct, 1000)
+ buf := new(bytes.Buffer)
+ var w io.Writer = buf
+ b.SetBytes(int64(Size(slice)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Write(w, BigEndian, slice)
+ }
+ b.StopTimer()
+}
+
+func BenchmarkReadSlice1000Structs(b *testing.B) {
+ bsr := &byteSliceReader{}
+ slice := make([]Struct, 1000)
+ buf := make([]byte, Size(slice))
+ b.SetBytes(int64(len(buf)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bsr.remain = buf
+ Read(bsr, BigEndian, slice)
+ }
+}
+
func BenchmarkReadInts(b *testing.B) {
var ls Struct
bsr := &byteSliceReader{}