diff options
| author | Daniel Martí <mvdan@mvdan.cc> | 2018-07-07 21:40:28 +0100 |
|---|---|---|
| committer | Daniel Martí <mvdan@mvdan.cc> | 2018-08-21 09:05:51 +0000 |
| commit | 30d3ebe36701b16678a51144eb3c5e958f382bd7 (patch) | |
| tree | dede29092f9bc790c21eb52b2b0ba494e5071439 /src/encoding/json/bench_test.go | |
| parent | 2d3599e57daf5816ee5b74553afd11decc611d44 (diff) | |
| download | go-30d3ebe36701b16678a51144eb3c5e958f382bd7.tar.xz | |
encoding/json: remove alloc when encoding short byte slices
If the encoded bytes fit in the bootstrap array encodeState.scratch, use
that instead of allocating a new byte slice.
Also tweaked the Encoding vs Encoder heuristic to use the length of the
encoded bytes, not the length of the input bytes. Encoding is used for
allocations of up to 1024 bytes, as we measured 2048 to be the point
where it no longer provides a noticeable advantage.
Also added some benchmarks. Only the first case changes in behavior.
name old time/op new time/op delta
MarshalBytes/32-4 420ns ± 1% 383ns ± 1% -8.69% (p=0.002 n=6+6)
MarshalBytes/256-4 913ns ± 1% 915ns ± 0% ~ (p=0.580 n=5+6)
MarshalBytes/4096-4 7.72µs ± 0% 7.74µs ± 0% ~ (p=0.340 n=5+6)
name old alloc/op new alloc/op delta
MarshalBytes/32-4 112B ± 0% 64B ± 0% -42.86% (p=0.002 n=6+6)
MarshalBytes/256-4 736B ± 0% 736B ± 0% ~ (all equal)
MarshalBytes/4096-4 7.30kB ± 0% 7.30kB ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
MarshalBytes/32-4 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.002 n=6+6)
MarshalBytes/256-4 2.00 ± 0% 2.00 ± 0% ~ (all equal)
MarshalBytes/4096-4 2.00 ± 0% 2.00 ± 0% ~ (all equal)
Updates #5683.
Change-Id: I5fa55c27bd7728338d770ae7c0756885ba9a5724
Reviewed-on: https://go-review.googlesource.com/122462
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/encoding/json/bench_test.go')
| -rw-r--r-- | src/encoding/json/bench_test.go | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go index bd322db2e6..72cb349062 100644 --- a/src/encoding/json/bench_test.go +++ b/src/encoding/json/bench_test.go @@ -114,6 +114,34 @@ func BenchmarkCodeMarshal(b *testing.B) { b.SetBytes(int64(len(codeJSON))) } +func benchMarshalBytes(n int) func(*testing.B) { + sample := []byte("hello world") + // Use a struct pointer, to avoid an allocation when passing it as an + // interface parameter to Marshal. + v := &struct { + Bytes []byte + }{ + bytes.Repeat(sample, (n/len(sample))+1)[:n], + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + if _, err := Marshal(v); err != nil { + b.Fatal("Marshal:", err) + } + } + } +} + +func BenchmarkMarshalBytes(b *testing.B) { + // 32 fits within encodeState.scratch. + b.Run("32", benchMarshalBytes(32)) + // 256 doesn't fit in encodeState.scratch, but is small enough to + // allocate and avoid the slower base64.NewEncoder. + b.Run("256", benchMarshalBytes(256)) + // 4096 is large enough that we want to avoid allocating for it. + b.Run("4096", benchMarshalBytes(4096)) +} + func BenchmarkCodeDecoder(b *testing.B) { if codeJSON == nil { b.StopTimer() |
