mirror of https://github.com/goccy/go-json.git
Add benchmark data
This commit is contained in:
parent
796f23fb0d
commit
753dc64dff
|
@ -7,6 +7,7 @@ replace github.com/goccy/go-json => ../../../
|
|||
require (
|
||||
github.com/goccy/go-json v0.0.0-00010101000000-000000000000
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||
golang.org/x/tools v0.1.1
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
google.golang.org/api v0.47.0
|
||||
)
|
||||
|
|
|
@ -351,6 +351,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -9,10 +9,12 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/tools/benchmark/parse"
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/sheets/v4"
|
||||
|
@ -23,6 +25,81 @@ const (
|
|||
benchgraphToken = "benchgraph-token.json"
|
||||
)
|
||||
|
||||
type BenchmarkCodec string
|
||||
|
||||
const (
|
||||
UnknownCodec BenchmarkCodec = "Unknown"
|
||||
Encoder BenchmarkCodec = "Encode"
|
||||
Decoder BenchmarkCodec = "Decode"
|
||||
)
|
||||
|
||||
func (c BenchmarkCodec) String() string {
|
||||
return string(c)
|
||||
}
|
||||
|
||||
type BenchmarkKind string
|
||||
|
||||
const (
|
||||
UnknownKind BenchmarkKind = "Unknown"
|
||||
SmallStruct BenchmarkKind = "SmallStruct"
|
||||
SmallStructCached BenchmarkKind = "SmallStructCached"
|
||||
MediumStruct BenchmarkKind = "MediumStruct"
|
||||
MediumStructCached BenchmarkKind = "MediumStructCached"
|
||||
LargeStruct BenchmarkKind = "LargeStruct"
|
||||
LargeStructCached BenchmarkKind = "LargeStructCached"
|
||||
)
|
||||
|
||||
func (k BenchmarkKind) String() string {
|
||||
return string(k)
|
||||
}
|
||||
|
||||
type BenchmarkTarget string
|
||||
|
||||
const (
|
||||
UnknownTarget BenchmarkTarget = "Unknown"
|
||||
EncodingJson BenchmarkTarget = "EncodingJson"
|
||||
GoJson BenchmarkTarget = "GoJson"
|
||||
GoJsonNoEscape BenchmarkTarget = "GoJsonNoEscape"
|
||||
GoJsonColored BenchmarkTarget = "GoJsonColored"
|
||||
FFJson BenchmarkTarget = "FFJson"
|
||||
JsonIter BenchmarkTarget = "JsonIter"
|
||||
EasyJson BenchmarkTarget = "EasyJson"
|
||||
Jettison BenchmarkTarget = "Jettison"
|
||||
GoJay BenchmarkTarget = "GoJay"
|
||||
SegmentioJson BenchmarkTarget = "SegmentioJson"
|
||||
)
|
||||
|
||||
func (t BenchmarkTarget) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func (t BenchmarkTarget) DisplayName() string {
|
||||
switch t {
|
||||
case EncodingJson:
|
||||
return "encoding/json"
|
||||
case GoJson:
|
||||
return "goccy/go-json"
|
||||
case GoJsonNoEscape:
|
||||
return "goccy/go-json (noescape)"
|
||||
case GoJsonColored:
|
||||
return "goccy/go-json (colored)"
|
||||
case FFJson:
|
||||
return "pquerna/ffjson"
|
||||
case JsonIter:
|
||||
return "json-iterator/go"
|
||||
case EasyJson:
|
||||
return "mailru/easyjson"
|
||||
case Jettison:
|
||||
return "wl2L/jettison"
|
||||
case GoJay:
|
||||
return "francoispqt/gojay"
|
||||
case SegmentioJson:
|
||||
return "segmentio/encoding/json"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
var credFile string
|
||||
|
||||
func init() {
|
||||
|
@ -45,7 +122,7 @@ func createClient(ctx context.Context) (*http.Client, error) {
|
|||
}
|
||||
|
||||
// If modifying these scopes, delete your previously saved token.json.
|
||||
config, err := google.ConfigFromJSON(b, sheets.SpreadsheetsScope, slides.PresentationsScope) //"https://spreadsheets.google.com/feeds"
|
||||
config, err := google.ConfigFromJSON(b, sheets.SpreadsheetsScope, slides.PresentationsScope)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create config from scope: %w", err)
|
||||
}
|
||||
|
@ -158,7 +235,7 @@ func createSpreadsheet(svc *sheets.Service, title string, headers []string, targ
|
|||
return spreadSheet, nil
|
||||
}
|
||||
|
||||
func generateChart(svc *sheets.Service, spreadSheet *sheets.Spreadsheet, title string) (int64, error) {
|
||||
func generateChart(svc *sheets.Service, spreadSheet *sheets.Spreadsheet, title string) (*sheets.EmbeddedChart, error) {
|
||||
sheet := spreadSheet.Sheets[0]
|
||||
rows := sheet.Data[0].RowData
|
||||
rowSize := int64(len(rows))
|
||||
|
@ -194,7 +271,7 @@ func generateChart(svc *sheets.Service, spreadSheet *sheets.Spreadsheet, title s
|
|||
Title: title,
|
||||
BasicChart: &sheets.BasicChartSpec{
|
||||
ChartType: "BAR",
|
||||
LegendPosition: "RIGHT_LEGEND",
|
||||
LegendPosition: "TOP_LEGEND",
|
||||
Domains: []*sheets.BasicChartDomain{
|
||||
{
|
||||
Domain: &sheets.ChartData{
|
||||
|
@ -222,16 +299,16 @@ func generateChart(svc *sheets.Service, spreadSheet *sheets.Spreadsheet, title s
|
|||
},
|
||||
}).Do()
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to generate chart: %w", err)
|
||||
return nil, xerrors.Errorf("failed to generate chart: %w", err)
|
||||
}
|
||||
|
||||
for _, rep := range res.Replies {
|
||||
if rep.AddChart == nil {
|
||||
continue
|
||||
}
|
||||
return rep.AddChart.Chart.ChartId, nil
|
||||
return rep.AddChart.Chart, nil
|
||||
}
|
||||
return 0, xerrors.Errorf("failed to find chartID")
|
||||
return nil, xerrors.Errorf("failed to find chartID")
|
||||
}
|
||||
|
||||
func createPresentationWithEmptySlide(presentationService *slides.PresentationsService) (*slides.Presentation, string, error) {
|
||||
|
@ -260,19 +337,19 @@ func createPresentationWithEmptySlide(presentationService *slides.PresentationsS
|
|||
return nil, "", xerrors.Errorf("failed to find slide objectID")
|
||||
}
|
||||
|
||||
func addChartToPresentation(presentationService *slides.PresentationsService, presentation *slides.Presentation, slideID string, spreadSheetID string, chartID int64) error {
|
||||
func addChartToPresentation(presentationService *slides.PresentationsService, presentation *slides.Presentation, slideID string, spreadSheetID string, chart *sheets.EmbeddedChart) error {
|
||||
if _, err := presentationService.BatchUpdate(presentation.PresentationId, &slides.BatchUpdatePresentationRequest{
|
||||
Requests: []*slides.Request{
|
||||
{
|
||||
CreateSheetsChart: &slides.CreateSheetsChartRequest{
|
||||
LinkingMode: "LINKED",
|
||||
SpreadsheetId: spreadSheetID,
|
||||
ChartId: chartID,
|
||||
ChartId: chart.ChartId,
|
||||
ElementProperties: &slides.PageElementProperties{
|
||||
PageObjectId: slideID,
|
||||
Size: &slides.Size{
|
||||
Width: &slides.Dimension{
|
||||
Magnitude: 1024,
|
||||
Magnitude: 1200,
|
||||
Unit: "PT",
|
||||
},
|
||||
Height: &slides.Dimension{
|
||||
|
@ -325,32 +402,164 @@ func downloadImage(url, path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func _main(args []string) error {
|
||||
ctx := context.Background()
|
||||
client, err := createClient(ctx)
|
||||
type BenchmarkData struct {
|
||||
*parse.Benchmark
|
||||
Codec BenchmarkCodec
|
||||
Kind BenchmarkKind
|
||||
Target BenchmarkTarget
|
||||
}
|
||||
|
||||
func toBenchmarkCodec(name string) (BenchmarkCodec, error) {
|
||||
switch {
|
||||
case strings.Contains(name, "_Encode_"):
|
||||
return Encoder, nil
|
||||
case strings.Contains(name, "_Decoder_"):
|
||||
return Decoder, nil
|
||||
default:
|
||||
return UnknownCodec, xerrors.Errorf("cannot find codec from %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func toBenchmarkKind(name string) (BenchmarkKind, error) {
|
||||
switch {
|
||||
case strings.Contains(name, "_SmallStruct_"):
|
||||
return SmallStruct, nil
|
||||
case strings.Contains(name, "_MediumStruct_"):
|
||||
return MediumStruct, nil
|
||||
case strings.Contains(name, "_LargeStruct_"):
|
||||
return LargeStruct, nil
|
||||
case strings.Contains(name, "_SmallStructCached_"):
|
||||
return SmallStructCached, nil
|
||||
case strings.Contains(name, "_MediumStructCached_"):
|
||||
return MediumStructCached, nil
|
||||
case strings.Contains(name, "_LargeStructCached_"):
|
||||
return LargeStructCached, nil
|
||||
default:
|
||||
return UnknownKind, xerrors.Errorf("cannot find kind from %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func toBenchmarkTarget(name string) (BenchmarkTarget, error) {
|
||||
v := strings.ToLower(name)
|
||||
switch {
|
||||
case strings.Contains(v, strings.ToLower("EncodingJson")):
|
||||
return EncodingJson, nil
|
||||
case strings.Contains(v, strings.ToLower("GoJson")):
|
||||
switch {
|
||||
case strings.Contains(v, strings.ToLower("NoEscape")):
|
||||
return GoJsonNoEscape, nil
|
||||
case strings.Contains(v, strings.ToLower("Colored")):
|
||||
return GoJsonColored, nil
|
||||
}
|
||||
return GoJson, nil
|
||||
case strings.Contains(v, strings.ToLower("FFJson")):
|
||||
return FFJson, nil
|
||||
case strings.Contains(v, strings.ToLower("JsonIter")):
|
||||
return JsonIter, nil
|
||||
case strings.Contains(v, strings.ToLower("EasyJson")):
|
||||
return EasyJson, nil
|
||||
case strings.Contains(v, strings.ToLower("Jettison")):
|
||||
return Jettison, nil
|
||||
case strings.Contains(v, strings.ToLower("GoJay")):
|
||||
return GoJay, nil
|
||||
case strings.Contains(v, strings.ToLower("SegmentioJson")):
|
||||
return SegmentioJson, nil
|
||||
default:
|
||||
return UnknownTarget, xerrors.Errorf("cannot find target from %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func createBenchmarkData(bench *parse.Benchmark) (*BenchmarkData, error) {
|
||||
codec, err := toBenchmarkCodec(bench.Name)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create client: %w", err)
|
||||
return nil, xerrors.Errorf("failed to convert benchmark codec: %w", err)
|
||||
}
|
||||
kind, err := toBenchmarkKind(bench.Name)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to convert benchmark kind: %w", err)
|
||||
}
|
||||
target, err := toBenchmarkTarget(bench.Name)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to convert benchmark target: %w", err)
|
||||
}
|
||||
return &BenchmarkData{
|
||||
Benchmark: bench,
|
||||
Codec: codec,
|
||||
Kind: kind,
|
||||
Target: target,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createAllBenchmarkData(data string) ([]*BenchmarkData, error) {
|
||||
allBenchData := []*BenchmarkData{}
|
||||
for _, line := range strings.Split(data, "\n") {
|
||||
if !strings.HasPrefix(line, "Benchmark") {
|
||||
continue
|
||||
}
|
||||
bench, err := parse.ParseLine(line)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse line: %w", err)
|
||||
}
|
||||
benchData, err := createBenchmarkData(bench)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create benchmark data: %w", err)
|
||||
}
|
||||
allBenchData = append(allBenchData, benchData)
|
||||
}
|
||||
return allBenchData, nil
|
||||
}
|
||||
|
||||
type Graph struct {
|
||||
Title string
|
||||
Codec BenchmarkCodec
|
||||
Kinds []BenchmarkKind
|
||||
}
|
||||
|
||||
func (g *Graph) existsKind(target BenchmarkKind) bool {
|
||||
for _, kind := range g.Kinds {
|
||||
if kind == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func generateBenchmarkGraph(ctx context.Context, client *http.Client, g *Graph, data []*BenchmarkData) error {
|
||||
headers := []string{}
|
||||
for _, kind := range g.Kinds {
|
||||
headers = append(headers, kind.String())
|
||||
}
|
||||
targetMap := map[string][]*BenchmarkData{}
|
||||
targetToData := map[string][]float64{}
|
||||
for _, v := range data {
|
||||
if g.Codec != v.Codec {
|
||||
continue
|
||||
}
|
||||
if !g.existsKind(v.Kind) {
|
||||
continue
|
||||
}
|
||||
name := v.Target.DisplayName()
|
||||
targetMap[name] = append(targetMap[name], v)
|
||||
targetToData[name] = append(targetToData[name], v.NsPerOp)
|
||||
}
|
||||
targets := []string{}
|
||||
for k := range targetMap {
|
||||
targets = append(targets, k)
|
||||
}
|
||||
|
||||
sheetService, err := sheets.NewService(ctx, option.WithHTTPClient(client))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create service for sheet: %w", err)
|
||||
}
|
||||
headers := []string{"TypeA", "TypeB", "TypeC"}
|
||||
targets := []string{"targetA", "targetB"}
|
||||
data := map[string][]float64{
|
||||
targets[0]: []float64{10, 100, 1000},
|
||||
targets[1]: []float64{20, 200, 2000},
|
||||
}
|
||||
spreadSheet, err := createSpreadsheet(sheetService, "go-json benchmark results", headers, targets, data)
|
||||
spreadSheet, err := createSpreadsheet(sheetService, g.Title, headers, targets, targetToData)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create spreadsheet: %w", err)
|
||||
}
|
||||
chartID, err := generateChart(sheetService, spreadSheet, "Benchmark Result")
|
||||
chart, err := generateChart(sheetService, spreadSheet, g.Title)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to generate chart: %w", err)
|
||||
}
|
||||
log.Println("spreadSheetID = ", spreadSheet.SpreadsheetId, "chartID = ", chartID)
|
||||
log.Println("spreadSheetID = ", spreadSheet.SpreadsheetId, "chartID = ", chart.ChartId)
|
||||
|
||||
slideService, err := slides.NewService(ctx, option.WithHTTPClient(client))
|
||||
if err != nil {
|
||||
|
@ -361,7 +570,7 @@ func _main(args []string) error {
|
|||
if err != nil {
|
||||
return xerrors.Errorf("failed to create presentation with slide: %w", err)
|
||||
}
|
||||
if err := addChartToPresentation(presentationService, presentation, slideID, spreadSheet.SpreadsheetId, chartID); err != nil {
|
||||
if err := addChartToPresentation(presentationService, presentation, slideID, spreadSheet.SpreadsheetId, chart); err != nil {
|
||||
return xerrors.Errorf("failed to add chart to presentation: %w", err)
|
||||
}
|
||||
if err := downloadChartImage(presentationService, presentation, "bench.png"); err != nil {
|
||||
|
@ -370,8 +579,62 @@ func _main(args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func run(args []string) error {
|
||||
benchData, err := createAllBenchmarkData(`
|
||||
goos: darwin
|
||||
goarch: amd64
|
||||
pkg: benchmark
|
||||
Benchmark_Encode_SmallStruct_EncodingJson-16 2135164 555 ns/op 256 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_FFJson-16 1348426 935 ns/op 584 B/op 9 allocs/op
|
||||
Benchmark_Encode_SmallStruct_JsonIter-16 1970002 598 ns/op 264 B/op 3 allocs/op
|
||||
Benchmark_Encode_SmallStruct_EasyJson-16 2202872 547 ns/op 720 B/op 4 allocs/op
|
||||
Benchmark_Encode_SmallStruct_Jettison-16 2610375 461 ns/op 256 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_GoJay-16 2763138 428 ns/op 624 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_SegmentioJson-16 4124536 291 ns/op 256 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_GoJsonColored-16 2530636 475 ns/op 432 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_GoJson-16 4308301 282 ns/op 256 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStruct_GoJsonNoEscape-16 5406490 215 ns/op 144 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_EncodingJson-16 2386401 510 ns/op 144 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_FFJson-16 1450132 829 ns/op 472 B/op 8 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_JsonIter-16 2279529 526 ns/op 152 B/op 2 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_EasyJson-16 2225763 543 ns/op 720 B/op 4 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_Jettison-16 3059923 387 ns/op 144 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_GoJay-16 3187108 372 ns/op 512 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_SegmentioJson-16 5128329 229 ns/op 144 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_GoJsonColored-16 3028646 403 ns/op 320 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_GoJson-16 5458942 215 ns/op 144 B/op 1 allocs/op
|
||||
Benchmark_Encode_SmallStructCached_GoJsonNoEscape-16 5725311 210 ns/op 144 B/op 1 allocs/op
|
||||
PASS
|
||||
ok benchmark 33.928s
|
||||
`)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse benchmark data: %w", err)
|
||||
}
|
||||
if benchData == nil {
|
||||
return nil
|
||||
}
|
||||
ctx := context.Background()
|
||||
client, err := createClient(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
graphs := []*Graph{
|
||||
{
|
||||
Title: "Encoding Benchmark ( Small / Medium Struct )",
|
||||
Codec: Encoder,
|
||||
Kinds: []BenchmarkKind{SmallStruct, MediumStruct},
|
||||
},
|
||||
}
|
||||
for _, graph := range graphs {
|
||||
if err := generateBenchmarkGraph(ctx, client, graph, benchData); err != nil {
|
||||
return xerrors.Errorf("failed to generate benchmark graph: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := _main(os.Args); err != nil {
|
||||
if err := run(os.Args); err != nil {
|
||||
log.Fatalf("%+v", err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue