diff options
author | Aliaksandr Valialkin <valyala@gmail.com> | 2015-08-15 13:04:46 +0300 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2015-11-25 17:01:25 +0000 |
commit | a48de745b28a39d58dcd916f410704f0f7d75d7c (patch) | |
tree | c482aae87a2dfa7bd0fb1936170524900f52f585 /src/encoding/gob/decode.go | |
parent | c4be790c0e20bfa4def3103392f404de201b3487 (diff) | |
download | go-a48de745b28a39d58dcd916f410704f0f7d75d7c.tar.gz go-a48de745b28a39d58dcd916f410704f0f7d75d7c.zip |
encoding/gob: reduce the amount of memory allocations.
Benchmark results:
benchmark old ns/op new ns/op delta
BenchmarkEndToEndPipe-4 7547 7294 -3.35%
BenchmarkEndToEndByteBuffer-4 5146 5092 -1.05%
BenchmarkEndToEndSliceByteBuffer-4 552779 439768 -20.44%
BenchmarkEncodeComplex128Slice-4 266370 266184 -0.07%
BenchmarkEncodeFloat64Slice-4 111891 110258 -1.46%
BenchmarkEncodeInt32Slice-4 74482 74080 -0.54%
BenchmarkEncodeStringSlice-4 84404 84279 -0.15%
BenchmarkEncodeInterfaceSlice-4 3942925 3045995 -22.75%
BenchmarkDecodeComplex128Slice-4 451837 415282 -8.09%
BenchmarkDecodeFloat64Slice-4 283584 262558 -7.41%
BenchmarkDecodeInt32Slice-4 246571 237383 -3.73%
BenchmarkDecodeStringSlice-4 734210 479625 -34.67%
BenchmarkDecodeInterfaceSlice-4 4778225 4160935 -12.92%
benchmark old allocs new allocs delta
BenchmarkEndToEndPipe-4 3 2 -33.33%
BenchmarkEndToEndByteBuffer-4 3 2 -33.33%
BenchmarkEndToEndSliceByteBuffer-4 1002 402 -59.88%
BenchmarkEncodeComplex128Slice-4 1 1 +0.00%
BenchmarkEncodeFloat64Slice-4 1 1 +0.00%
BenchmarkEncodeInt32Slice-4 1 1 +0.00%
BenchmarkEncodeStringSlice-4 1 1 +0.00%
BenchmarkEncodeInterfaceSlice-4 3001 1 -99.97%
BenchmarkDecodeComplex128Slice-4 188 185 -1.60%
BenchmarkDecodeFloat64Slice-4 188 185 -1.60%
BenchmarkDecodeInt32Slice-4 188 185 -1.60%
BenchmarkDecodeStringSlice-4 2188 1185 -45.84%
BenchmarkDecodeInterfaceSlice-4 6197 4194 -32.32%
benchmark old bytes new bytes delta
BenchmarkEndToEndPipe-4 64 48 -25.00%
BenchmarkEndToEndByteBuffer-4 64 48 -25.00%
BenchmarkEndToEndSliceByteBuffer-4 34551 10554 -69.45%
BenchmarkEncodeComplex128Slice-4 55 55 +0.00%
BenchmarkEncodeFloat64Slice-4 33 33 +0.00%
BenchmarkEncodeInt32Slice-4 32 32 +0.00%
BenchmarkEncodeStringSlice-4 36 36 +0.00%
BenchmarkEncodeInterfaceSlice-4 144555 347 -99.76%
BenchmarkDecodeComplex128Slice-4 28240 28097 -0.51%
BenchmarkDecodeFloat64Slice-4 11840 11697 -1.21%
BenchmarkDecodeInt32Slice-4 10817 10673 -1.33%
BenchmarkDecodeStringSlice-4 56128 39985 -28.76%
BenchmarkDecodeInterfaceSlice-4 132565 100421 -24.25%
Change-Id: Ief7c7706b1f2916486ab7190b81aafbb16b70f1e
Reviewed-on: https://go-review.googlesource.com/13660
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/encoding/gob/decode.go')
-rw-r--r-- | src/encoding/gob/decode.go | 62 |
1 files changed, 34 insertions, 28 deletions
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index ef536b32b2..3b0dca86f3 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -29,8 +29,7 @@ type decoderState struct { // The buffer is stored with an extra indirection because it may be replaced // if we load a type during decode (when reading an interface value). b *decBuffer - fieldnum int // the last field number read. - buf []byte + fieldnum int // the last field number read. next *decoderState // for free list } @@ -97,7 +96,6 @@ func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState { if d == nil { d = new(decoderState) d.dec = dec - d.buf = make([]byte, uint64Size) } else { dec.freeList = d.next } @@ -160,15 +158,16 @@ func (state *decoderState) decodeUint() (x uint64) { if n > uint64Size { error_(errBadUint) } - width, err := state.b.Read(state.buf[0:n]) - if err != nil { - error_(err) + buf := state.b.Bytes() + if len(buf) < n { + errorf("invalid uint data length %d: exceeds input size %d", n, len(buf)) } // Don't need to check error; it's safe to loop regardless. // Could check that the high byte is zero but it's not worth it. - for _, b := range state.buf[0:width] { + for _, b := range buf[0:n] { x = x<<8 | uint64(b) } + state.b.Drop(n) return x } @@ -397,11 +396,13 @@ func decString(i *decInstr, state *decoderState, value reflect.Value) { errorf("bad %s slice length: %d", value.Type(), n) } // Read the data. - data := make([]byte, n) - if _, err := state.b.Read(data); err != nil { - errorf("error decoding string: %s", err) + data := state.b.Bytes() + if len(data) < n { + errorf("invalid string length %d: exceeds input size %d", n, len(data)) } - value.SetString(string(data)) + s := string(data[:n]) + state.b.Drop(n) + value.SetString(s) } // ignoreUint8Array skips over the data for a byte slice value with no destination. @@ -410,8 +411,11 @@ func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) { if !ok { errorf("slice length too large") } - b := make([]byte, n) - state.b.Read(b) + bn := state.b.Len() + if bn < n { + errorf("invalid slice length %d: exceeds input size %d", n, bn) + } + state.b.Drop(n) } // Execution engine @@ -640,9 +644,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu if nr > uint64(state.b.Len()) { errorf("invalid type name length %d: exceeds input size", nr) } - b := make([]byte, nr) - state.b.Read(b) - name := string(b) + n := int(nr) + name := string(state.b.Bytes()[:n]) + state.b.Drop(n) // Allocate the destination interface value. if name == "" { // Copy the nil interface value to the target. @@ -689,11 +693,11 @@ func (dec *Decoder) ignoreInterface(state *decoderState) { if !ok { errorf("bad interface encoding: name too large for buffer") } - b := make([]byte, n) - _, err := state.b.Read(b) - if err != nil { - error_(err) + bn := state.b.Len() + if bn < n { + errorf("invalid interface value length %d: exceeds input size %d", n, bn) } + state.b.Drop(n) id := dec.decodeTypeSequence(true) if id < 0 { error_(dec.err) @@ -714,11 +718,13 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu if !ok { errorf("GobDecoder: length too large for buffer") } - b := make([]byte, n) - _, err := state.b.Read(b) - if err != nil { - error_(err) + b := state.b.Bytes() + if len(b) < n { + errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, len(b)) } + b = b[:n] + state.b.Drop(n) + var err error // We know it's one of these. switch ut.externalDec { case xGob: @@ -740,11 +746,11 @@ func (dec *Decoder) ignoreGobDecoder(state *decoderState) { if !ok { errorf("GobDecoder: length too large for buffer") } - b := make([]byte, n) - _, err := state.b.Read(b) - if err != nil { - error_(err) + bn := state.b.Len() + if bn < n { + errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, bn) } + state.b.Drop(n) } // Index by Go types. |