Skip to content

Commit

Permalink
test: benchmark with github.com/goccy/go-json (bytedance#23)
Browse files Browse the repository at this point in the history
chore: add benchmark result with go-json

Co-authored-by: duanyi.aster <[email protected]>
  • Loading branch information
AsterDY and AsterDY authored Jun 22, 2021
1 parent 85a0d42 commit 936cee0
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 20 deletions.
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,39 @@ A blazingly fast JSON serializing &amp; deserializing library, accelerated by JI

## Benchmarks
For all sizes of json and all scenes of usage, Sonic performs almost best.
- Small (400B, 11 keys, 3 levels)
- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 levels)
![small benchmarks](bench-400B.png)
- Medium (110KB, 300+ keys, 3 levels, with many quoted-json values)
![medium benchmarks](bench-110KB.png)
- Large (550KB, 10000+ key, 6 levels)
- [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitterescaped.json) (550KB, 10000+ key, 6 levels)
![large benchmarks](bench-550KB.png)

For a 13KB [TwitterJson](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19)(cpu i9-9880H, goarch amd64), Sonic is **1.5x** faster than [json-iterator](https://github.com/json-iterator/go) in decoding, **2.5x** faster in encoding.
For a 13KB [TwitterJson](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19), Sonic is **1.5x** faster than [json-iterator](https://github.com/json-iterator/go) in decoding, **2.5x** faster in encoding.

```powershell
BenchmarkDecoder_Generic_Sonic-16 10000 54309 ns/op 240.01 MB/s 46149 B/op 303 allocs/op
BenchmarkDecoder_Generic_StdLib-16 10000 135268 ns/op 96.36 MB/s 50899 B/op 772 allocs/op
BenchmarkDecoder_Generic_JsonIter-16 10000 96701 ns/op 134.80 MB/s 55791 B/op 1068 allocs/op
BenchmarkDecoder_Binding_Sonic-16 10000 29478 ns/op 442.20 MB/s 26062 B/op 34 allocs/op
BenchmarkDecoder_Binding_StdLib-16 10000 119348 ns/op 109.22 MB/s 10560 B/op 207 allocs/op
BenchmarkDecoder_Binding_JsonIter-16 10000 37646 ns/op 346.25 MB/s 14673 B/op 385 allocs/op
BenchmarkEncoder_Generic_Sonic-16 10000 25894 ns/op 503.39 MB/s 19096 B/op 42 allocs/op
BenchmarkEncoder_Generic_JsonIter-16 10000 50275 ns/op 259.27 MB/s 13432 B/op 77 allocs/op
BenchmarkEncoder_Generic_StdLib-16 10000 154901 ns/op 84.15 MB/s 48173 B/op 827 allocs/op
BenchmarkEncoder_Binding_Sonic-16 10000 7373 ns/op 1768.04 MB/s 13861 B/op 4 allocs/op
BenchmarkEncoder_Binding_JsonIter-16 10000 23223 ns/op 561.31 MB/s 9489 B/op 2 allocs/op
BenchmarkEncoder_Binding_StdLib-16 10000 19512 ns/op 668.07 MB/s 9477 B/op 1 allocs/op
goos: darwin
goarch: amd64
pkg: github.com/bytedance/sonic/encoder
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkEncoder_Generic_Sonic-16 100000 24174 ns/op 539.22 MB/s 17757 B/op 42 allocs/op
BenchmarkEncoder_Generic_JsonIter-16 100000 44613 ns/op 292.18 MB/s 13433 B/op 77 allocs/op
BenchmarkEncoder_Generic_GoJson-16 100000 87898 ns/op 148.30 MB/s 13234 B/op 39 allocs/op
BenchmarkEncoder_Generic_StdLib-16 100000 133512 ns/op 97.63 MB/s 48177 B/op 827 allocs/op
BenchmarkEncoder_Binding_Sonic-16 100000 6058 ns/op 2151.73 MB/s 13481 B/op 4 allocs/op
BenchmarkEncoder_Binding_JsonIter-16 100000 21223 ns/op 614.20 MB/s 9488 B/op 2 allocs/op
BenchmarkEncoder_Binding_GoJson-16 100000 10186 ns/op 1279.74 MB/s 9480 B/op 1 allocs/op
BenchmarkEncoder_Binding_StdLib-16 100000 17741 ns/op 734.75 MB/s 9479 B/op 1 allocs/op
BenchmarkDecoder_Generic_Sonic-16 100000 53344 ns/op 244.36 MB/s 50158 B/op 313 allocs/op
BenchmarkDecoder_Generic_StdLib-16 100000 141006 ns/op 92.44 MB/s 50898 B/op 772 allocs/op
BenchmarkDecoder_Generic_JsonIter-16 100000 106386 ns/op 122.53 MB/s 55785 B/op 1068 allocs/op
BenchmarkDecoder_Generic_GoJson-16 100000 107184 ns/op 121.61 MB/s 65678 B/op 944 allocs/op
BenchmarkDecoder_Binding_Sonic-16 100000 30039 ns/op 433.94 MB/s 25259 B/op 34 allocs/op
BenchmarkDecoder_Binding_StdLib-16 100000 131088 ns/op 99.44 MB/s 10560 B/op 207 allocs/op
BenchmarkDecoder_Binding_JsonIter-16 100000 37988 ns/op 343.13 MB/s 14674 B/op 385 allocs/op
BenchmarkDecoder_Binding_GoJson-16 100000 33741 ns/op 386.33 MB/s 22047 B/op 49 allocs/op
```
More detail see [ast/search_test.go](https://github.com/bytedance/sonic/blob/main/ast/search_test.go), [decoder/decoder_test.go](https://github.com/bytedance/sonic/blob/main/decoder/decoder_test.go), [encoder/encoder_test.go](https://github.com/bytedance/sonic/blob/main/encoder/encoder_test.go),
More detail see [decoder/decoder_test.go](https://github.com/bytedance/sonic/blob/main/decoder/decoder_test.go), [encoder/encoder_test.go](https://github.com/bytedance/sonic/blob/main/encoder/encoder_test.go), [ast/search_test.go](https://github.com/bytedance/sonic/blob/main/ast/search_test.go), [ast/parser_test.go](https://github.com/bytedance/sonic/blob/main/ast/parser_test.go)

## Usage

Expand Down Expand Up @@ -119,7 +128,7 @@ For alignment to encoding/json, we provide API to pass `[]byte` as arguement, bu
```go
import "github.com/bytedance/sonic"

root, err := sonic.GetByString(_TwitterJson, "statuses", 3, "user")
root, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
a = root.GetByPath( "entities","description")
b = root.GetByPath( "entities","url")
c = root.GetByPath( "created_at")
Expand All @@ -130,7 +139,7 @@ In most cases of fully-load generic json, `Unmarshal()` performs better than `as
```go
import "github.com/bytedance/sonic"

node, err := sonic.GetByString(_TwitterJson, "statuses", 3, "user")
node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user")
var user interface{}
err = sonic.UnmarshalString(node.Raw(), &user)
```
Binary file removed bench-110KB.png
Binary file not shown.
Binary file modified bench-400B.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified bench-550KB.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions decoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
`github.com/json-iterator/go`
`github.com/stretchr/testify/assert`
`github.com/stretchr/testify/require`
gojson `github.com/goccy/go-json`
)

var _BindingValue TwitterStruct
Expand Down Expand Up @@ -111,6 +112,18 @@ func BenchmarkDecoder_Generic_JsonIter(b *testing.B) {
}
}

func BenchmarkDecoder_Generic_GoJson(b *testing.B) {
var w interface{}
m := []byte(TwitterJson)
_ = gojson.Unmarshal(m, &w)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var v interface{}
_ = gojson.Unmarshal(m, &v)
}
}

func BenchmarkDecoder_Binding_Sonic(b *testing.B) {
var w TwitterStruct
_, _ = decode(TwitterJson, &w)
Expand Down Expand Up @@ -146,6 +159,18 @@ func BenchmarkDecoder_Binding_JsonIter(b *testing.B) {
}
}

func BenchmarkDecoder_Binding_GoJson(b *testing.B) {
var w TwitterStruct
m := []byte(TwitterJson)
_ = gojson.Unmarshal(m, &w)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var v TwitterStruct
_ = gojson.Unmarshal(m, &v)
}
}

func BenchmarkDecoder_Parallel_Generic_Sonic(b *testing.B) {
var w interface{}
_, _ = decode(TwitterJson, &w)
Expand Down Expand Up @@ -187,6 +212,20 @@ func BenchmarkDecoder_Parallel_Generic_JsonIter(b *testing.B) {
})
}

func BenchmarkDecoder_Parallel_Generic_GoJson(b *testing.B) {
var w interface{}
m := []byte(TwitterJson)
_ = gojson.Unmarshal(m, &w)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var v interface{}
_ = gojson.Unmarshal(m, &v)
}
})
}

func BenchmarkDecoder_Parallel_Binding_Sonic(b *testing.B) {
var w TwitterStruct
_, _ = decode(TwitterJson, &w)
Expand Down Expand Up @@ -227,3 +266,18 @@ func BenchmarkDecoder_Parallel_Binding_JsonIter(b *testing.B) {
}
})
}

func BenchmarkDecoder_Parallel_Binding_GoJson(b *testing.B) {
var w TwitterStruct
m := []byte(TwitterJson)
_ = gojson.Unmarshal(m, &w)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var v TwitterStruct
_ = gojson.Unmarshal(m, &v)
}
})
}

41 changes: 41 additions & 0 deletions encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
`testing`

`github.com/json-iterator/go`
gojson `github.com/goccy/go-json`
`github.com/stretchr/testify/assert`
)

Expand Down Expand Up @@ -128,6 +129,15 @@ func BenchmarkEncoder_Generic_JsonIter(b *testing.B) {
}
}

func BenchmarkEncoder_Generic_GoJson(b *testing.B) {
_, _ = gojson.Marshal(_GenericValue)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = gojson.Marshal(_GenericValue)
}
}

func BenchmarkEncoder_Generic_StdLib(b *testing.B) {
_, _ = json.Marshal(_GenericValue)
b.SetBytes(int64(len(TwitterJson)))
Expand Down Expand Up @@ -155,6 +165,15 @@ func BenchmarkEncoder_Binding_JsonIter(b *testing.B) {
}
}

func BenchmarkEncoder_Binding_GoJson(b *testing.B) {
_, _ = gojson.Marshal(&_BindingValue)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = gojson.Marshal(&_BindingValue)
}
}

func BenchmarkEncoder_Binding_StdLib(b *testing.B) {
_, _ = json.Marshal(&_BindingValue)
b.SetBytes(int64(len(TwitterJson)))
Expand Down Expand Up @@ -186,6 +205,17 @@ func BenchmarkEncoder_Parallel_Generic_JsonIter(b *testing.B) {
})
}

func BenchmarkEncoder_Parallel_Generic_GoJson(b *testing.B) {
_, _ = gojson.Marshal(_GenericValue)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = gojson.Marshal(_GenericValue)
}
})
}

func BenchmarkEncoder_Parallel_Generic_StdLib(b *testing.B) {
_, _ = json.Marshal(_GenericValue)
b.SetBytes(int64(len(TwitterJson)))
Expand Down Expand Up @@ -219,6 +249,17 @@ func BenchmarkEncoder_Parallel_Binding_JsonIter(b *testing.B) {
})
}

func BenchmarkEncoder_Parallel_Binding_GoJson(b *testing.B) {
_, _ = gojson.Marshal(&_BindingValue)
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = gojson.Marshal(&_BindingValue)
}
})
}

func BenchmarkEncoder_Parallel_Binding_StdLib(b *testing.B) {
_, _ = json.Marshal(&_BindingValue)
b.SetBytes(int64(len(TwitterJson)))
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.15
require (
github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5
github.com/davecgh/go-spew v1.1.1
github.com/goccy/go-json v0.7.1 // indirect
github.com/json-iterator/go v1.1.10
github.com/klauspost/cpuid/v2 v2.0.6
github.com/stretchr/testify v1.7.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5/go.mod h1:NfDzX
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/goccy/go-json v0.7.1 h1:VMhnh5gcc8De8f6m2DLvSqY1x8Jwl3btet+EqMP0QNs=
github.com/goccy/go-json v0.7.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
Expand Down
64 changes: 64 additions & 0 deletions testdata/small.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package testdata

// ffjson: skip
// easyjson:skip
type Book struct {
BookId int `json:"id"`
BookIds []int `json:"ids"`
Title string `json:"title"`
Titles []string `json:"titles"`
Price float64 `json:"price"`
Prices []float64 `json:"prices"`
Hot bool `json:"hot"`
Hots []bool `json:"hots"`
Author Author `json:"author"`
Authors []Author `json:"authors"`
Weights []int `json:"weights"`
}

// ffjson: skip
// easyjson:skip
type Author struct {
Name string `json:"name"`
Age int `json:"age"`
Male bool `json:"male"`
}

var book = Book{
BookId: 12125925,
BookIds: []int{-2147483648, 2147483647},
Title: "未来简史-从智人到智神",
Titles: []string{"hello", "world"},
Price: 40.8,
Prices: []float64{-0.1, 0.1},
Hot: true,
Hots: []bool{true, true, true},
Author: author,
Authors: []Author{author, author, author},
Weights: nil,
}

var author = Author{
Name: "json",
Age: 99,
Male: true,
}

var data = []byte(`{"id":12125925,"ids":[-2147483648,2147483647],"title":"未来简史-从智人到智神","titles":["hello","world"],"price":40.8,"prices":[-0.1,0.1],"hot":true,"hots":[true,true,true],"author":{"name":"json","age":99,"male":true},"authors":[{"name":"json","age":99,"male":true},{"name":"json","age":99,"male":true},{"name":"json","age":99,"male":true}],"weights":[]}`)

0 comments on commit 936cee0

Please sign in to comment.