Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add benchmark with fastjson #760

Merged
merged 1 commit into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading