Skip to content

Commit

Permalink
chore: add benchmark with fastjson
Browse files Browse the repository at this point in the history
  • Loading branch information
liuq19 committed Feb 27, 2025
1 parent 86fae91 commit 51dbf8c
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 13 deletions.
136 changes: 136 additions & 0 deletions external_jsonlib_test/benchmark_test/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ package benchmark_test
import (
`testing`

`github.com/bytedance/sonic/ast`
jsoniter `github.com/json-iterator/go`
`github.com/tidwall/gjson`
fastjson `github.com/valyala/fastjson`
)

func BenchmarkParser_Gjson(b *testing.B) {
Expand Down Expand Up @@ -234,3 +236,137 @@ func BenchmarkParseSeven_Parallel_Jsoniter(b *testing.B) {
}
})
}


func BenchmarkParseSeven_Sonic(b *testing.B) {
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
ast, _ := ast.NewParser(TwitterJson).Parse()
node := ast.GetByPath("statuses", 3, "id")
node = ast.GetByPath("statuses", 3, "user", "entities","description")
node = ast.GetByPath("statuses", 3, "user", "entities","url","urls")
node = ast.GetByPath("statuses", 3, "user", "entities","url")
node = ast.GetByPath("statuses", 3, "user", "created_at")
node = ast.GetByPath("statuses", 3, "user", "name")
node = ast.GetByPath("statuses", 3, "text")
if node.Check() != nil {
b.Fail()
}
}
}

func BenchmarkParseSeven_Parallel_Sonic(b *testing.B) {
b.SetBytes(int64(len(TwitterJson)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
ast, _ := ast.NewParser(TwitterJson).Parse()
node := ast.GetByPath("statuses", 3, "id")
node = ast.GetByPath("statuses", 3, "user", "entities","description")
node = ast.GetByPath("statuses", 3, "user", "entities","url","urls")
node = ast.GetByPath("statuses", 3, "user", "entities","url")
node = ast.GetByPath("statuses", 3, "user", "created_at")
node = ast.GetByPath("statuses", 3, "user", "name")
node = ast.GetByPath("statuses", 3, "text")
if node.Check() != nil {
b.Fail()
}
}
})
}

func BenchmarkParseOne_Fastjson(b *testing.B) {
data := []byte(TwitterJson)
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
b.Fatal(err)
}
id := v.Get("statuses").GetArray()[2].GetInt64("id")
if id != 249289491129438208 {
b.Fatal("value mismatch")
}

b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var p fastjson.Parser
v, _ := p.ParseBytes(data)
_ = v.Get("statuses").GetArray()[2].GetInt64("id")
}
}


func BenchmarkParseOne_Parallel_Fastjson(b *testing.B) {
data := []byte(TwitterJson)
b.SetBytes(int64(len(data)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var p fastjson.Parser
v, _ := p.ParseBytes(data)
_ = v.Get("statuses").GetArray()[2].GetInt64("id")
}
})
}

func BenchmarkParseSeven_Fastjson(b *testing.B) {
data := []byte(TwitterJson)
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
b.Fatal(err)
}

statuses := v.GetArray("statuses")
if len(statuses) < 4 {
b.Fatal("insufficient statuses")
}
status := statuses[3]

checks := []func(*fastjson.Value){
func(v *fastjson.Value) { v.GetInt64("id") },
func(v *fastjson.Value) { v.Get("user").Get("entities").GetStringBytes("description") },
func(v *fastjson.Value) { v.Get("user").Get("entities").Get("url").GetArray("urls") },
func(v *fastjson.Value) { v.Get("user").Get("entities").Get("url") },
func(v *fastjson.Value) { v.Get("user").GetStringBytes("created_at") },
func(v *fastjson.Value) { v.Get("user").GetStringBytes("name") },
func(v *fastjson.Value) { v.GetStringBytes("text") },
}

for _, check := range checks {
check(status)
}

b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var p fastjson.Parser
v, _ := p.ParseBytes(data)
status := v.GetArray("statuses")[3]
for _, check := range checks {
check(status)
}
}
}

func BenchmarkParseSeven_Parallel_Fastjson(b *testing.B) {
data := []byte(TwitterJson)
b.SetBytes(int64(len(data)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var p fastjson.Parser
v, _ := p.ParseBytes(data)
status := v.GetArray("statuses")[3]
status.GetInt64("id")
status.Get("user").Get("entities").GetStringBytes("description")
status.Get("user").Get("entities").Get("url").GetArray("urls")
status.Get("user").Get("entities").Get("url")
status.Get("user").GetStringBytes("created_at")
status.Get("user").GetStringBytes("name")
status.GetStringBytes("text")
}
})
}
74 changes: 64 additions & 10 deletions external_jsonlib_test/benchmark_test/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ import (
jsoniter `github.com/json-iterator/go`
`github.com/tidwall/gjson`
`github.com/tidwall/sjson`
fastjson "github.com/valyala/fastjson"
)


const (
expectedID = 249279667666817024
expectMetaCount = 4
)

func BenchmarkGetOne_Gjson(b *testing.B) {
b.SetBytes(int64(len(TwitterJson)))
for i := 0; i < b.N; i++ {
ast := gjson.Get(TwitterJson, "statuses.3.id")
node := ast.Int()
if node != 249279667666817024 {
if node != expectedID {
b.Fail()
}
}
Expand All @@ -45,7 +52,7 @@ func BenchmarkGetOne_Jsoniter(b *testing.B) {
for i := 0; i < b.N; i++ {
ast := jsoniter.Get(data, "statuses", 3, "id")
node := ast.ToInt()
if node != 249279667666817024 {
if node != expectedID {
b.Fail()
}
}
Expand All @@ -60,7 +67,7 @@ func BenchmarkGetOne_Sonic(b *testing.B) {
b.Fatal(err)
}
x, _ := node.Int64()
if x != 249279667666817024 {
if x != expectedID {
b.Fatal(node.Interface())
}
}
Expand All @@ -77,7 +84,7 @@ func BenchmarkGetOne_Parallel_Sonic(b *testing.B) {
b.Fatal(err)
}
x, _ := node.Int64()
if x != 249279667666817024 {
if x != expectedID {
b.Fatal(node.Interface())
}
}
Expand All @@ -90,7 +97,7 @@ func BenchmarkGetOne_Parallel_Gjson(b *testing.B) {
for pb.Next() {
ast := gjson.Get(TwitterJson, "statuses.3.id")
node := ast.Int()
if node != 249279667666817024 {
if node != expectedID {
b.Fail()
}
}
Expand All @@ -104,7 +111,7 @@ func BenchmarkGetOne_Parallel_Jsoniter(b *testing.B) {
for pb.Next() {
ast := jsoniter.Get(data, "statuses", 3, "id")
node := ast.ToInt()
if node != 249279667666817024 {
if node != expectedID {
b.Fail()
}
}
Expand Down Expand Up @@ -179,14 +186,13 @@ func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) {
func BenchmarkGetByKeys_Sonic(b *testing.B) {
b.SetBytes(int64(len(TwitterJson)))
ast := ast.NewSearcher(TwitterJson)
const _count = 4
for i := 0; i < b.N; i++ {
node, err := ast.GetByPath("search_metadata", "count")
if err != nil {
b.Fatal(err)
}
x, _ := node.Int64()
if x != _count {
if x != expectMetaCount {
b.Fatal(node.Interface())
}
}
Expand All @@ -196,14 +202,62 @@ func BenchmarkGetByKeys_Sonic(b *testing.B) {
func BenchmarkGetByKeys_JsonParser(b *testing.B) {
b.SetBytes(int64(len(TwitterJson)))
data := []byte(TwitterJson)
const _count = 4
for i := 0; i < b.N; i++ {
value, err := jsonparser.GetInt(data, "search_metadata", "count")
if err != nil {
b.Fatal(err)
}
if value != _count {
if value != expectMetaCount {
b.Fatal(value)
}
}
}

func BenchmarkGetOne_FastJson(b *testing.B) {
data := []byte(TwitterJson)
b.ResetTimer()
b.SetBytes(int64(len(data)))

for i := 0; i < b.N; i++ {
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
b.Fatal(err)
}

statuses := v.GetArray("statuses")
if len(statuses) < 4 {
b.Fatal("array too short")
}
id := statuses[3].GetInt64("id")
if id != expectedID {
b.Fatalf("expected %d, got %d", expectedID, id)
}
}
}


func BenchmarkGetOne_Parallel_FastJson(b *testing.B) {
data := []byte(TwitterJson)
b.SetBytes(int64(len(data)))
b.ResetTimer()

b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
b.Fatal(err)
}

statuses := v.GetArray("statuses")
if len(statuses) < 4 {
b.Fatal("array too short")
}
id := statuses[3].GetInt64("id")
if id != expectedID {
b.Fatalf("expected %d, got %d", expectedID, id)
}
}
})
}
1 change: 1 addition & 0 deletions external_jsonlib_test/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/stretchr/testify v1.8.1
github.com/tidwall/gjson v1.14.3
github.com/tidwall/sjson v1.2.5
github.com/valyala/fastjson v1.6.4
)

require (
Expand Down
2 changes: 2 additions & 0 deletions external_jsonlib_test/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
2 changes: 1 addition & 1 deletion generic_test/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (

require (
github.com/bytedance/sonic/loader v0.2.2 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions generic_test/go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
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=
Expand Down

0 comments on commit 51dbf8c

Please sign in to comment.