mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
* test: add generic benchmark * test: add ci * chore: adjust generic benchmark variable name * ci: fix compare bug in bench.py * build: adjust CI yaml * test: use sonic.Config * chore: generic test * test: add interface type bench Co-authored-by: liuqiang <liuqiang.06@bytedance.com> Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
268 lines
No EOL
8.6 KiB
Go
268 lines
No EOL
8.6 KiB
Go
// +build go1.18
|
|
|
|
/*
|
|
* Copyright 2022 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 generic_test
|
|
|
|
import (
|
|
`os`
|
|
`testing`
|
|
`reflect`
|
|
`fmt`
|
|
`github.com/bytedance/sonic`
|
|
`encoding/json`
|
|
gojson `github.com/goccy/go-json`
|
|
jsoniter `github.com/json-iterator/go`
|
|
jsonv2 `github.com/go-json-experiment/json`
|
|
)
|
|
|
|
var (
|
|
validFlag = os.Getenv("SONIC_VALID_GENERIC_BENCH") != ""
|
|
pretouchFlag = os.Getenv("SONIC_NO_PRETOUCH_BENCH") == ""
|
|
)
|
|
|
|
type jsonLibEntry struct {
|
|
name string
|
|
marshal func(any) ([]byte, error)
|
|
unmarshal func([]byte, any) error
|
|
}
|
|
|
|
var jsonLibs = []jsonLibEntry {
|
|
{"Std", json.Marshal, json.Unmarshal},
|
|
{"StdV2", jsonv2.Marshal, jsonv2.Unmarshal},
|
|
{"Sonic", sonic.Marshal, sonic.Unmarshal},
|
|
{"SonicStd", sonic.ConfigStd.Marshal, sonic.ConfigStd.Unmarshal},
|
|
{"GoJson", gojson.Marshal, gojson.Unmarshal},
|
|
{"JsonIter", jsoniter.Marshal, jsoniter.Unmarshal},
|
|
{"JsonIterStd", jsoniter.ConfigCompatibleWithStandardLibrary.Marshal, jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal},
|
|
}
|
|
|
|
func BenchmarkUnmarshalConcrete(b *testing.B) {
|
|
runUnmarshalC(b)
|
|
}
|
|
|
|
func BenchmarkUnmarshalInterface(b *testing.B) {
|
|
runUnmarshalI(b)
|
|
}
|
|
|
|
func BenchmarkMarshalConcrete(b *testing.B) {
|
|
runMarshalC(b)
|
|
}
|
|
|
|
func BenchmarkMarshalInterface(b *testing.B) {
|
|
runMarshalI(b)
|
|
}
|
|
|
|
func runUnmarshalC(b *testing.B) {
|
|
for _, tt := range jsonTestdata() {
|
|
for _, lib := range jsonLibs {
|
|
var val any = tt.new()
|
|
pretouch := func() {
|
|
_ = lib.unmarshal(tt.data, val)
|
|
}
|
|
|
|
run := func(b *testing.B) {
|
|
val = tt.new()
|
|
if err := lib.unmarshal(tt.data, val); err != nil {
|
|
b.Fatalf("%s Unmarshal error: %v", lib.name, err)
|
|
}
|
|
}
|
|
|
|
valid := func(b *testing.B) {
|
|
val1, val2 := tt.new(), tt.new()
|
|
if err := json.Unmarshal(tt.data, val1); err != nil {
|
|
panic(err)
|
|
}
|
|
if err := lib.unmarshal(tt.data, val2); err != nil {
|
|
panic(err)
|
|
}
|
|
if !reflect.DeepEqual(val1, val2) {
|
|
b.Fatalf("%s Unmarshal output mismatch:\ngot %v\nwant %v", lib.name, val2, val1)
|
|
}
|
|
}
|
|
|
|
name := fmt.Sprintf("%s_%s", tt.name, lib.name)
|
|
b.Run(name, func(b *testing.B) {
|
|
if pretouchFlag {
|
|
pretouch()
|
|
}
|
|
valid(b)
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(tt.data)))
|
|
for i := 0; i < b.N; i++ {
|
|
run(b)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func runUnmarshalI(b *testing.B) {
|
|
for _, tt := range jsonTestdata() {
|
|
for _, lib := range jsonLibs {
|
|
var val any = tt.newI()
|
|
pretouch := func() {
|
|
_ = lib.unmarshal(tt.data, val)
|
|
}
|
|
|
|
run := func(b *testing.B) {
|
|
val = tt.newI()
|
|
if err := lib.unmarshal(tt.data, val); err != nil {
|
|
b.Fatalf("%s Unmarshal error: %v", lib.name, err)
|
|
}
|
|
}
|
|
|
|
valid := func(b *testing.B) {
|
|
val1, val2 := tt.newI(), tt.newI()
|
|
if err := json.Unmarshal(tt.data, val1); err != nil {
|
|
panic(err)
|
|
}
|
|
if err := lib.unmarshal(tt.data, val2); err != nil {
|
|
panic(err)
|
|
}
|
|
if !reflect.DeepEqual(val1, val2) {
|
|
b.Fatalf("%s Unmarshal output mismatch:\ngot %v\nwant %v", lib.name, val2, val1)
|
|
}
|
|
}
|
|
|
|
name := fmt.Sprintf("%s_%s", tt.name, lib.name)
|
|
b.Run(name, func(b *testing.B) {
|
|
if pretouchFlag {
|
|
pretouch()
|
|
}
|
|
valid(b)
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(tt.data)))
|
|
for i := 0; i < b.N; i++ {
|
|
run(b)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func runMarshalC(b *testing.B) {
|
|
for _, tt := range jsonTestdata() {
|
|
for _, lib := range jsonLibs {
|
|
pretouch := func() {
|
|
_, _ = lib.marshal(tt.val)
|
|
}
|
|
|
|
run := func(b *testing.B) {
|
|
if _, err := lib.marshal(tt.val); err != nil {
|
|
b.Fatalf("%s Marshal error: %v", lib.name, err)
|
|
}
|
|
}
|
|
|
|
valid := func(b *testing.B) {
|
|
// some details are different with encoding/json, so we compare the unmarshal results from marshaled buffer
|
|
var buf1, buf2 []byte
|
|
buf1, err := json.Marshal(tt.val)
|
|
if err != nil {
|
|
b.Fatalf("encoding/json Marshal error: %v", err)
|
|
}
|
|
buf2, err = lib.marshal(tt.val);
|
|
if err != nil {
|
|
b.Fatalf("%s Marshal error: %v", lib.name, err)
|
|
}
|
|
var val1, val2 = tt.new(), tt.new()
|
|
if err := json.Unmarshal(buf1, val1); err != nil {
|
|
b.Fatalf("encoding/json Unmarshal again error: %v", err)
|
|
}
|
|
if err := lib.unmarshal(buf2, val2); err != nil {
|
|
b.Fatalf("%s Unmarshal again error: %v", lib.name, err)
|
|
}
|
|
if !reflect.DeepEqual(val1, val2) {
|
|
b.Fatalf("Unmarshal again output mismatch\n")
|
|
}
|
|
}
|
|
|
|
name := fmt.Sprintf("%s_%s", tt.name, lib.name)
|
|
b.Run(name, func(b *testing.B) {
|
|
if pretouchFlag {
|
|
pretouch()
|
|
}
|
|
if (validFlag) {
|
|
valid(b)
|
|
}
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(tt.data)))
|
|
for i := 0; i < b.N; i++ {
|
|
run(b)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func runMarshalI(b *testing.B) {
|
|
for _, tt := range jsonTestdata() {
|
|
for _, lib := range jsonLibs {
|
|
pretouch := func() {
|
|
_, _ = lib.marshal(tt.valI)
|
|
}
|
|
|
|
run := func(b *testing.B) {
|
|
if _, err := lib.marshal(tt.valI); err != nil {
|
|
b.Fatalf("%s Marshal error: %v", lib.name, err)
|
|
}
|
|
}
|
|
|
|
valid := func(b *testing.B) {
|
|
// some details are different with encoding/json, so we compare the unmarshal results from marshaled buffer
|
|
var buf1, buf2 []byte
|
|
buf1, err := json.Marshal(tt.valI)
|
|
if err != nil {
|
|
b.Fatalf("encoding/json Marshal error: %v", err)
|
|
}
|
|
buf2, err = lib.marshal(tt.valI);
|
|
if err != nil {
|
|
b.Fatalf("%s Marshal error: %v", lib.name, err)
|
|
}
|
|
var val1, val2 = tt.new(), tt.new()
|
|
if err := json.Unmarshal(buf1, val1); err != nil {
|
|
b.Fatalf("encoding/json Unmarshal again error: %v", err)
|
|
}
|
|
if err := lib.unmarshal(buf2, val2); err != nil {
|
|
b.Fatalf("%s Unmarshal again error: %v", lib.name, err)
|
|
}
|
|
if !reflect.DeepEqual(val1, val2) {
|
|
b.Fatalf("Unmarshal again output mismatch\n")
|
|
}
|
|
}
|
|
|
|
name := fmt.Sprintf("%s_%s", tt.name, lib.name)
|
|
b.Run(name, func(b *testing.B) {
|
|
if pretouchFlag {
|
|
pretouch()
|
|
}
|
|
if (validFlag) {
|
|
valid(b)
|
|
}
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(tt.data)))
|
|
for i := 0; i < b.N; i++ {
|
|
run(b)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
} |