2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00
sonic/generic_test/benchmark_test.go
liu 3717c62ec2
test: add generic benchmark (#239)
* 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>
2022-06-07 13:26:28 +08:00

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)
}
})
}
}
}