Skip to content

Commit 381ba9f

Browse files
kwakuegyirbineygopherbot
authored andcommitted
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 <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent 4f07bb3 commit 381ba9f

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/encoding/binary/binary.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,17 @@ var structSize sync.Map // map[reflect.Type]int
480480
func dataSize(v reflect.Value) int {
481481
switch v.Kind() {
482482
case reflect.Slice:
483-
if s := sizeof(v.Type().Elem()); s >= 0 {
484-
return s * v.Len()
483+
t := v.Type().Elem()
484+
if size, ok := structSize.Load(t); ok {
485+
return size.(int) * v.Len()
486+
}
487+
488+
size := sizeof(t)
489+
if size >= 0 {
490+
if t.Kind() == reflect.Struct {
491+
structSize.Store(t, size)
492+
}
493+
return size * v.Len()
485494
}
486495

487496
case reflect.Struct:

src/encoding/binary/binary_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,31 @@ func BenchmarkWriteStruct(b *testing.B) {
631631
}
632632
}
633633

634+
func BenchmarkWriteSlice1000Structs(b *testing.B) {
635+
slice := make([]Struct, 1000)
636+
buf := new(bytes.Buffer)
637+
var w io.Writer = buf
638+
b.SetBytes(int64(Size(slice)))
639+
b.ResetTimer()
640+
for i := 0; i < b.N; i++ {
641+
buf.Reset()
642+
Write(w, BigEndian, slice)
643+
}
644+
b.StopTimer()
645+
}
646+
647+
func BenchmarkReadSlice1000Structs(b *testing.B) {
648+
bsr := &byteSliceReader{}
649+
slice := make([]Struct, 1000)
650+
buf := make([]byte, Size(slice))
651+
b.SetBytes(int64(len(buf)))
652+
b.ResetTimer()
653+
for i := 0; i < b.N; i++ {
654+
bsr.remain = buf
655+
Read(bsr, BigEndian, slice)
656+
}
657+
}
658+
634659
func BenchmarkReadInts(b *testing.B) {
635660
var ls Struct
636661
bsr := &byteSliceReader{}

0 commit comments

Comments
 (0)