Created
November 11, 2016 17:05
-
-
Save FZambia/e0026ecc2fc7d7a4d62015e7bc7252c4 to your computer and use it in GitHub Desktop.
Jsonparser GJSON Benchmarks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package apiv1 | |
| import ( | |
| "encoding/json" | |
| "testing" | |
| "github.com/buger/jsonparser" | |
| "github.com/centrifugal/centrifugo/libcentrifugo/proto" | |
| "github.com/centrifugal/centrifugo/libcentrifugo/raw" | |
| "github.com/tidwall/gjson" | |
| ) | |
| var ( | |
| arrayJSONPrefix byte = '[' | |
| objectJSONPrefix byte = '{' | |
| ) | |
| func apiCommandsFromJSON(msg []byte) ([]proto.ApiCommand, error) { | |
| var cmds []proto.ApiCommand | |
| if len(msg) == 0 { | |
| return cmds, nil | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| // single command request | |
| var command proto.ApiCommand | |
| err := json.Unmarshal(msg, &command) | |
| if err != nil { | |
| return nil, err | |
| } | |
| cmds = append(cmds, command) | |
| case arrayJSONPrefix: | |
| // array of commands received | |
| err := json.Unmarshal(msg, &cmds) | |
| if err != nil { | |
| return nil, err | |
| } | |
| default: | |
| return nil, proto.ErrInvalidMessage | |
| } | |
| return cmds, nil | |
| } | |
| func apiCommandsFromGJSON(msg []byte) ([]proto.ApiCommand, error) { | |
| if len(msg) == 0 { | |
| return nil, nil | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmds = make([]proto.ApiCommand, 1) | |
| var cmd proto.ApiCommand | |
| cmd.Method = gjson.GetBytes(msg, "method").String() | |
| cmd.Params = raw.Raw(gjson.GetBytes(msg, "params").Raw) | |
| cmds[0] = cmd | |
| return cmds, nil | |
| case arrayJSONPrefix: | |
| res := gjson.Parse(string(msg)) | |
| cs := res.Array() | |
| var cmds = make([]proto.ApiCommand, len(cs)) | |
| for i, r := range cs { | |
| var cmd proto.ApiCommand | |
| cmd.Method = r.Get("method").String() | |
| cmd.Params = raw.Raw(r.Get("params").Raw) | |
| cmds[i] = cmd | |
| } | |
| return cmds, nil | |
| default: | |
| return nil, proto.ErrInvalidMessage | |
| } | |
| } | |
| var testJSONObject = `{"method": "publish", "params": {"channel": "channel", "data": "hello"}}` | |
| var testJSONArraySingle = `[ | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}} | |
| ]` | |
| var testJSONArrayMany = `[ | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}}, | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}}, | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}}, | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}}, | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}}, | |
| {"method": "publish", "params": {"channel": "channel", "data": "hello"}} | |
| ]` | |
| func BenchmarkJSONObject(b *testing.B) { | |
| msg := []byte(testJSONObject) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| var cmd proto.PublishAPICommand | |
| err = json.Unmarshal(command.Params, &cmd) | |
| if err != nil { | |
| panic(err) | |
| } | |
| if cmd.Channel != "channel" { | |
| panic("wrong channel") | |
| } | |
| } | |
| } | |
| } | |
| func BenchmarkJSONObjectGJSON(b *testing.B) { | |
| msg := []byte(testJSONObject) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromGJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| handlePublish(&command) | |
| } | |
| } | |
| } | |
| func BenchmarkJSONObjectGJSONFast(b *testing.B) { | |
| msg := []byte(testJSONObject) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| cmd.Method = gjson.GetBytes(msg, "method").String() | |
| cmd.Params = raw.Raw(gjson.GetBytes(msg, "params").Raw) | |
| handlePublish(&cmd) | |
| case arrayJSONPrefix: | |
| res := gjson.Parse(string(msg)) | |
| cs := res.Array() | |
| for _, r := range cs { | |
| var cmd proto.ApiCommand | |
| cmd.Method = r.Get("method").String() | |
| cmd.Params = raw.Raw(r.Get("params").Raw) | |
| handlePublish(&cmd) | |
| } | |
| default: | |
| } | |
| } | |
| } | |
| func BenchmarkJSONObjectJsonparser(b *testing.B) { | |
| msg := []byte(testJSONObject) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(msg, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| case arrayJSONPrefix: | |
| jsonparser.ArrayEach(msg, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(value, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| }) | |
| default: | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArraySingle(b *testing.B) { | |
| msg := []byte(testJSONArraySingle) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| var cmd proto.PublishAPICommand | |
| err = json.Unmarshal(command.Params, &cmd) | |
| if err != nil { | |
| panic(err) | |
| } | |
| if cmd.Channel != "channel" { | |
| panic("wrong channel") | |
| } | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArraySingleGJSON(b *testing.B) { | |
| msg := []byte(testJSONArraySingle) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromGJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| handlePublish(&command) | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArraySingleGJSONFast(b *testing.B) { | |
| msg := []byte(testJSONArraySingle) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| cmd.Method = gjson.GetBytes(msg, "method").String() | |
| cmd.Params = raw.Raw(gjson.GetBytes(msg, "params").Raw) | |
| handlePublish(&cmd) | |
| case arrayJSONPrefix: | |
| res := gjson.Parse(string(msg)) | |
| cs := res.Array() | |
| for _, r := range cs { | |
| var cmd proto.ApiCommand | |
| cmd.Method = r.Get("method").String() | |
| cmd.Params = raw.Raw(r.Get("params").Raw) | |
| handlePublish(&cmd) | |
| } | |
| default: | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArraySingleJsonparser(b *testing.B) { | |
| msg := []byte(testJSONArraySingle) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(msg, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| case arrayJSONPrefix: | |
| jsonparser.ArrayEach(msg, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(value, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| }) | |
| default: | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArrayMany(b *testing.B) { | |
| msg := []byte(testJSONArrayMany) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| var cmd proto.PublishAPICommand | |
| err = json.Unmarshal(command.Params, &cmd) | |
| if err != nil { | |
| panic(err) | |
| } | |
| if cmd.Channel != "channel" { | |
| panic("wrong channel") | |
| } | |
| } | |
| } | |
| } | |
| func BenchmarkJSONArrayManyGJSON(b *testing.B) { | |
| msg := []byte(testJSONArrayMany) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| commands, err := apiCommandsFromGJSON(msg) | |
| if err != nil { | |
| panic(err) | |
| } | |
| for _, command := range commands { | |
| handlePublish(&command) | |
| } | |
| } | |
| } | |
| func handlePublish(command *proto.ApiCommand) error { | |
| var cmd proto.PublishAPICommand | |
| params := string(command.Params) | |
| cmd.Channel = gjson.Get(params, "channel").String() | |
| cmd.Data = raw.Raw(gjson.Get(params, "data").Raw) | |
| cmd.Client = gjson.Get(params, "client").String() | |
| if cmd.Channel != "channel" { | |
| panic("wrong channel") | |
| } | |
| return nil | |
| } | |
| func handlePublishJsonparser(command *proto.ApiCommand) error { | |
| var cmd proto.PublishAPICommand | |
| jsonparser.EachKey(command.Params, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.Channel = string(val) | |
| case 1: | |
| cmd.Data = raw.Raw(val) | |
| case 2: | |
| cmd.Client = string(val) | |
| } | |
| }, publishPaths...) | |
| if cmd.Channel != "channel" { | |
| panic("wrong channel") | |
| } | |
| return nil | |
| } | |
| func BenchmarkJSONArrayManyGJSONFast(b *testing.B) { | |
| msg := []byte(testJSONArrayMany) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| cmd.Method = gjson.GetBytes(msg, "method").String() | |
| cmd.Params = raw.Raw(gjson.GetBytes(msg, "params").Raw) | |
| handlePublish(&cmd) | |
| case arrayJSONPrefix: | |
| res := gjson.Parse(string(msg)) | |
| cs := res.Array() | |
| for _, r := range cs { | |
| var cmd proto.ApiCommand | |
| cmd.Method = r.Get("method").String() | |
| cmd.Params = raw.Raw(r.Get("params").Raw) | |
| handlePublish(&cmd) | |
| } | |
| default: | |
| } | |
| } | |
| } | |
| var paths = [][]string{ | |
| []string{"uid"}, | |
| []string{"method"}, | |
| []string{"params"}, | |
| } | |
| var publishPaths = [][]string{ | |
| []string{"channel"}, | |
| []string{"data"}, | |
| []string{"client"}, | |
| } | |
| func BenchmarkJSONArrayManyJsonparser(b *testing.B) { | |
| msg := []byte(testJSONArrayMany) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if len(msg) == 0 { | |
| panic(1) | |
| } | |
| firstByte := msg[0] | |
| switch firstByte { | |
| case objectJSONPrefix: | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(msg, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| case arrayJSONPrefix: | |
| jsonparser.ArrayEach(msg, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { | |
| var cmd proto.ApiCommand | |
| jsonparser.EachKey(value, func(idx int, val []byte, vt jsonparser.ValueType, err error) { | |
| switch idx { | |
| case 0: | |
| cmd.UID = string(val) | |
| case 1: | |
| cmd.Method = string(val) | |
| case 2: | |
| cmd.Params = raw.Raw(val) | |
| } | |
| }, paths...) | |
| handlePublishJsonparser(&cmd) | |
| }) | |
| default: | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment