mirror of
https://github.com/golang/go
synced 2024-11-26 11:38:01 -07:00
encoding/gob: Speedup map decoding by reducing the allocations.
The improvementis achieved in encoding/gob/decode.go decodeMap by allocate keyInstr and elemInstr only once and pass it to decodeIntoValue, instead of allocating a new instance on every loop cycle. name old time/op new time/op delta DecodeComplex128Slice-8 64.2µs ±10% 62.2µs ± 8% ~ (p=0.686 n=4+4) DecodeFloat64Slice-8 37.1µs ± 3% 36.5µs ± 5% ~ (p=0.343 n=4+4) DecodeInt32Slice-8 33.7µs ± 3% 32.7µs ± 4% ~ (p=0.200 n=4+4) DecodeStringSlice-8 59.7µs ± 5% 57.3µs ± 1% ~ (p=0.114 n=4+4) DecodeInterfaceSlice-8 543µs ± 7% 497µs ± 3% ~ (p=0.057 n=4+4) DecodeMap-8 3.78ms ± 8% 2.66ms ± 2% -29.69% (p=0.029 n=4+4) Updates #19525 Change-Id: Iec5fa4530de76f0a70da5de8a129a567b4aa096e Reviewed-on: https://go-review.googlesource.com/38317 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
f1e880386b
commit
0b9607d1d6
@ -545,11 +545,16 @@ func TestEndToEnd(t *testing.T) {
|
|||||||
type T2 struct {
|
type T2 struct {
|
||||||
T string
|
T string
|
||||||
}
|
}
|
||||||
|
type T3 struct {
|
||||||
|
X float64
|
||||||
|
Z *int
|
||||||
|
}
|
||||||
s1 := "string1"
|
s1 := "string1"
|
||||||
s2 := "string2"
|
s2 := "string2"
|
||||||
type T1 struct {
|
type T1 struct {
|
||||||
A, B, C int
|
A, B, C int
|
||||||
M map[string]*float64
|
M map[string]*float64
|
||||||
|
M2 map[int]T3
|
||||||
EmptyMap map[string]int // to check that we receive a non-nil map.
|
EmptyMap map[string]int // to check that we receive a non-nil map.
|
||||||
N *[3]float64
|
N *[3]float64
|
||||||
Strs *[2]string
|
Strs *[2]string
|
||||||
@ -561,11 +566,14 @@ func TestEndToEnd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
pi := 3.14159
|
pi := 3.14159
|
||||||
e := 2.71828
|
e := 2.71828
|
||||||
|
meaning := 42
|
||||||
|
fingers := 5
|
||||||
t1 := &T1{
|
t1 := &T1{
|
||||||
A: 17,
|
A: 17,
|
||||||
B: 18,
|
B: 18,
|
||||||
C: -5,
|
C: -5,
|
||||||
M: map[string]*float64{"pi": &pi, "e": &e},
|
M: map[string]*float64{"pi": &pi, "e": &e},
|
||||||
|
M2: map[int]T3{4: T3{X: pi, Z: &meaning}, 10: T3{X: e, Z: &fingers}},
|
||||||
EmptyMap: make(map[string]int),
|
EmptyMap: make(map[string]int),
|
||||||
N: &[3]float64{1.5, 2.5, 3.5},
|
N: &[3]float64{1.5, 2.5, 3.5},
|
||||||
Strs: &[2]string{s1, s2},
|
Strs: &[2]string{s1, s2},
|
||||||
|
@ -542,12 +542,12 @@ func (dec *Decoder) decodeArray(state *decoderState, value reflect.Value, elemOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decodeIntoValue is a helper for map decoding.
|
// decodeIntoValue is a helper for map decoding.
|
||||||
func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, ovfl error) reflect.Value {
|
func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, instr *decInstr) reflect.Value {
|
||||||
instr := &decInstr{op, 0, nil, ovfl}
|
|
||||||
v := value
|
v := value
|
||||||
if isPtr {
|
if isPtr {
|
||||||
v = decAlloc(value)
|
v = decAlloc(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
op(instr, state, v)
|
op(instr, state, v)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -564,9 +564,11 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl
|
|||||||
n := int(state.decodeUint())
|
n := int(state.decodeUint())
|
||||||
keyIsPtr := mtyp.Key().Kind() == reflect.Ptr
|
keyIsPtr := mtyp.Key().Kind() == reflect.Ptr
|
||||||
elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr
|
elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr
|
||||||
|
keyInstr := &decInstr{keyOp, 0, nil, ovfl}
|
||||||
|
elemInstr := &decInstr{elemOp, 0, nil, ovfl}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), ovfl)
|
key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), keyInstr)
|
||||||
elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), ovfl)
|
elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), elemInstr)
|
||||||
value.SetMapIndex(key, elem)
|
value.SetMapIndex(key, elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,3 +364,28 @@ func BenchmarkDecodeInterfaceSlice(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeMap(b *testing.B) {
|
||||||
|
count := 10000
|
||||||
|
m := make(map[int]int, count)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
m[i] = i
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
enc := NewEncoder(&buf)
|
||||||
|
err := enc.Encode(m)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
bbuf := benchmarkBuf{data: buf.Bytes()}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
rm := make(map[int]int, 0)
|
||||||
|
bbuf.reset()
|
||||||
|
dec := NewDecoder(&bbuf)
|
||||||
|
err := dec.Decode(&rm)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user