mirror of https://github.com/golang/go.git
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>
This commit is contained in:
parent
4f07bb3953
commit
381ba9f64c
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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{}
|
||||
|
|
|
|||
Loading…
Reference in New Issue