As we did with encoding, provide a trivial byte reader for
faster decoding. We can also reduce some of the copying
by doing the allocation all at once using a slightly different
interface from byte buffers.
benchmark old ns/op new ns/op delta
BenchmarkEndToEndPipe 13368 12902 -3.49%
BenchmarkEndToEndByteBuffer 5969 5642 -5.48%
BenchmarkEndToEndSliceByteBuffer 479485 470798 -1.81%
BenchmarkEncodeComplex128Slice 92367 92201 -0.18%
BenchmarkEncodeFloat64Slice 39990 38960 -2.58%
BenchmarkEncodeInt32Slice 30510 27938 -8.43%
BenchmarkEncodeStringSlice 33753 33365 -1.15%
BenchmarkDecodeComplex128Slice 232278 196704 -15.32%
BenchmarkDecodeFloat64Slice 150258 128191 -14.69%
BenchmarkDecodeInt32Slice 133806 115748 -13.50%
BenchmarkDecodeStringSlice 335117 300534 -10.32%
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/154360049
Bytes buffers have more API and are a little slower. Since appending
is a key part of the path in encode, using a faster implementation
speeds things up measurably.
The couple of positive swings are likely garbage-collection related
since memory allocation looks different in the benchmark now.
I am not concerned by them.
benchmark old ns/op new ns/op delta
BenchmarkEndToEndPipe 6620 6388 -3.50%
BenchmarkEndToEndByteBuffer 3548 3600 +1.47%
BenchmarkEndToEndSliceByteBuffer 336678 367980 +9.30%
BenchmarkEncodeComplex128Slice 78199 71297 -8.83%
BenchmarkEncodeFloat64Slice 37731 32258 -14.51%
BenchmarkEncodeInt32Slice 26780 22977 -14.20%
BenchmarkEncodeStringSlice 35882 26492 -26.17%
BenchmarkDecodeComplex128Slice 194819 185126 -4.98%
BenchmarkDecodeFloat64Slice 120538 120102 -0.36%
BenchmarkDecodeInt32Slice 106442 107275 +0.78%
BenchmarkDecodeStringSlice 272902 269866 -1.11%
LGTM=ruiu
R=golang-codereviews, ruiu
CC=golang-codereviews
https://golang.org/cl/160990043
Use go generate to write better loops for decoding arrays,
just as we did for encoding. It doesn't help as much,
relatively speaking, but it's still noticeable.
benchmark old ns/op new ns/op delta
BenchmarkDecodeComplex128Slice 202348 184529 -8.81%
BenchmarkDecodeFloat64Slice 135800 120979 -10.91%
BenchmarkDecodeInt32Slice 121200 105149 -13.24%
BenchmarkDecodeStringSlice 288129 278214 -3.44%
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/154420044
We borrow a trick from the fmt package and avoid reflection
to walk the elements when possible. We could push further with
unsafe (and we may) but this is a good start.
Decode can benefit similarly; it will be done separately.
Use go generate (engen.go) to produce the helper functions
(enc_helpers.go).
benchmark old ns/op new ns/op delta
BenchmarkEndToEndPipe 6593 6482 -1.68%
BenchmarkEndToEndByteBuffer 3662 3684 +0.60%
BenchmarkEndToEndSliceByteBuffer 350306 351693 +0.40%
BenchmarkComplex128Slice 96347 80045 -16.92%
BenchmarkInt32Slice 42484 26008 -38.78%
BenchmarkFloat64Slice 51143 36265 -29.09%
BenchmarkStringSlice 53402 35077 -34.32%
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/156310043
FieldByIndex never returns an invalid Value, so the validity
test can be avoided if the field is not indirect.
BenchmarkGobEncode 12768642 12424022 -2.70%
BenchmarkGobEncode 60.11 61.78 1.03x
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/158890045