]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/gob: Speedup map decoding by reducing the allocations.
authorFilip Gruszczyński <gruszczy@gmail.com>
Thu, 16 Mar 2017 03:11:30 +0000 (20:11 -0700)
committerRob Pike <r@golang.org>
Fri, 24 Mar 2017 19:36:14 +0000 (19:36 +0000)
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>

src/encoding/gob/codec_test.go
src/encoding/gob/decode.go
src/encoding/gob/timing_test.go

index d4002cbccab3d38c84086cb2cb72d025a2606329..31c6aa6dd701206543a4d342ad781d999e6d6a59 100644 (file)
@@ -545,11 +545,16 @@ func TestEndToEnd(t *testing.T) {
        type T2 struct {
                T string
        }
+       type T3 struct {
+               X float64
+               Z *int
+       }
        s1 := "string1"
        s2 := "string2"
        type T1 struct {
                A, B, C  int
                M        map[string]*float64
+               M2       map[int]T3
                EmptyMap map[string]int // to check that we receive a non-nil map.
                N        *[3]float64
                Strs     *[2]string
@@ -561,11 +566,14 @@ func TestEndToEnd(t *testing.T) {
        }
        pi := 3.14159
        e := 2.71828
+       meaning := 42
+       fingers := 5
        t1 := &T1{
                A:        17,
                B:        18,
                C:        -5,
                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),
                N:        &[3]float64{1.5, 2.5, 3.5},
                Strs:     &[2]string{s1, s2},
index 92d9d3ef8761b9fe920dff63cf444ae68b1f2df1..645aa71c3896068aee7b17768e07faf6d8725a8d 100644 (file)
@@ -542,12 +542,12 @@ func (dec *Decoder) decodeArray(state *decoderState, value reflect.Value, elemOp
 }
 
 // decodeIntoValue is a helper for map decoding.
-func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, ovfl error) reflect.Value {
-       instr := &decInstr{op, 0, nil, ovfl}
+func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, instr *decInstr) reflect.Value {
        v := value
        if isPtr {
                v = decAlloc(value)
        }
+
        op(instr, state, v)
        return value
 }
@@ -564,9 +564,11 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl
        n := int(state.decodeUint())
        keyIsPtr := mtyp.Key().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++ {
-               key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), ovfl)
-               elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), ovfl)
+               key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), keyInstr)
+               elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), elemInstr)
                value.SetMapIndex(key, elem)
        }
 }
index a7e7e683cc38734025dfe0cb20e8f61996f2eb3e..e3578992fcf148581c298934d83b1fcba71b08b9 100644 (file)
@@ -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)
+               }
+       }
+}