Try to use ffjson with custom encoder, but it's even slower?!
Stop/start benchmark around code that massages vecs into custom structs for encoding.
This commit is contained in:
parent
68088ceb3f
commit
05b8898d9f
3
go.sum
3
go.sum
@ -15,6 +15,7 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
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=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
@ -69,6 +70,7 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
|
||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
||||
@ -104,6 +106,7 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
|
||||
7
src/ffjsonvec3/vec3.go
Normal file
7
src/ffjsonvec3/vec3.go
Normal file
@ -0,0 +1,7 @@
|
||||
package ffjsonvec3
|
||||
|
||||
type Vec3 struct {
|
||||
X float32 `json:"x"`
|
||||
Y float32 `json:"y"`
|
||||
Z float32 `json:"z"`
|
||||
}
|
||||
315
src/ffjsonvec3/vec3_ffjson.go
Normal file
315
src/ffjsonvec3/vec3_ffjson.go
Normal file
@ -0,0 +1,315 @@
|
||||
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
|
||||
// source: vec3.go
|
||||
|
||||
package ffjsonvec3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
fflib "github.com/pquerna/ffjson/fflib/v1"
|
||||
)
|
||||
|
||||
// MarshalJSON marshal bytes to json - template
|
||||
func (j *Vec3) MarshalJSON() ([]byte, error) {
|
||||
var buf fflib.Buffer
|
||||
if j == nil {
|
||||
buf.WriteString("null")
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
err := j.MarshalJSONBuf(&buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// MarshalJSONBuf marshal buff to json - template
|
||||
func (j *Vec3) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
|
||||
if j == nil {
|
||||
buf.WriteString("null")
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
var obj []byte
|
||||
_ = obj
|
||||
_ = err
|
||||
buf.WriteString(`{"x":`)
|
||||
fflib.AppendFloat(buf, float64(j.X), 'g', -1, 32)
|
||||
buf.WriteString(`,"y":`)
|
||||
fflib.AppendFloat(buf, float64(j.Y), 'g', -1, 32)
|
||||
buf.WriteString(`,"z":`)
|
||||
fflib.AppendFloat(buf, float64(j.Z), 'g', -1, 32)
|
||||
buf.WriteByte('}')
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
ffjtVec3base = iota
|
||||
ffjtVec3nosuchkey
|
||||
|
||||
ffjtVec3X
|
||||
|
||||
ffjtVec3Y
|
||||
|
||||
ffjtVec3Z
|
||||
)
|
||||
|
||||
var ffjKeyVec3X = []byte("x")
|
||||
|
||||
var ffjKeyVec3Y = []byte("y")
|
||||
|
||||
var ffjKeyVec3Z = []byte("z")
|
||||
|
||||
// UnmarshalJSON umarshall json - template of ffjson
|
||||
func (j *Vec3) UnmarshalJSON(input []byte) error {
|
||||
fs := fflib.NewFFLexer(input)
|
||||
return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
|
||||
}
|
||||
|
||||
// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
|
||||
func (j *Vec3) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
|
||||
var err error
|
||||
currentKey := ffjtVec3base
|
||||
_ = currentKey
|
||||
tok := fflib.FFTok_init
|
||||
wantedTok := fflib.FFTok_init
|
||||
|
||||
mainparse:
|
||||
for {
|
||||
tok = fs.Scan()
|
||||
// println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
|
||||
if tok == fflib.FFTok_error {
|
||||
goto tokerror
|
||||
}
|
||||
|
||||
switch state {
|
||||
|
||||
case fflib.FFParse_map_start:
|
||||
if tok != fflib.FFTok_left_bracket {
|
||||
wantedTok = fflib.FFTok_left_bracket
|
||||
goto wrongtokenerror
|
||||
}
|
||||
state = fflib.FFParse_want_key
|
||||
continue
|
||||
|
||||
case fflib.FFParse_after_value:
|
||||
if tok == fflib.FFTok_comma {
|
||||
state = fflib.FFParse_want_key
|
||||
} else if tok == fflib.FFTok_right_bracket {
|
||||
goto done
|
||||
} else {
|
||||
wantedTok = fflib.FFTok_comma
|
||||
goto wrongtokenerror
|
||||
}
|
||||
|
||||
case fflib.FFParse_want_key:
|
||||
// json {} ended. goto exit. woo.
|
||||
if tok == fflib.FFTok_right_bracket {
|
||||
goto done
|
||||
}
|
||||
if tok != fflib.FFTok_string {
|
||||
wantedTok = fflib.FFTok_string
|
||||
goto wrongtokenerror
|
||||
}
|
||||
|
||||
kn := fs.Output.Bytes()
|
||||
if len(kn) <= 0 {
|
||||
// "" case. hrm.
|
||||
currentKey = ffjtVec3nosuchkey
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
} else {
|
||||
switch kn[0] {
|
||||
|
||||
case 'x':
|
||||
|
||||
if bytes.Equal(ffjKeyVec3X, kn) {
|
||||
currentKey = ffjtVec3X
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
case 'y':
|
||||
|
||||
if bytes.Equal(ffjKeyVec3Y, kn) {
|
||||
currentKey = ffjtVec3Y
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
case 'z':
|
||||
|
||||
if bytes.Equal(ffjKeyVec3Z, kn) {
|
||||
currentKey = ffjtVec3Z
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if fflib.SimpleLetterEqualFold(ffjKeyVec3Z, kn) {
|
||||
currentKey = ffjtVec3Z
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
if fflib.SimpleLetterEqualFold(ffjKeyVec3Y, kn) {
|
||||
currentKey = ffjtVec3Y
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
if fflib.SimpleLetterEqualFold(ffjKeyVec3X, kn) {
|
||||
currentKey = ffjtVec3X
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
currentKey = ffjtVec3nosuchkey
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
case fflib.FFParse_want_colon:
|
||||
if tok != fflib.FFTok_colon {
|
||||
wantedTok = fflib.FFTok_colon
|
||||
goto wrongtokenerror
|
||||
}
|
||||
state = fflib.FFParse_want_value
|
||||
continue
|
||||
case fflib.FFParse_want_value:
|
||||
|
||||
if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
|
||||
switch currentKey {
|
||||
|
||||
case ffjtVec3X:
|
||||
goto handle_X
|
||||
|
||||
case ffjtVec3Y:
|
||||
goto handle_Y
|
||||
|
||||
case ffjtVec3Z:
|
||||
goto handle_Z
|
||||
|
||||
case ffjtVec3nosuchkey:
|
||||
err = fs.SkipField(tok)
|
||||
if err != nil {
|
||||
return fs.WrapErr(err)
|
||||
}
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
}
|
||||
} else {
|
||||
goto wantedvalue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle_X:
|
||||
|
||||
/* handler: j.X type=float32 kind=float32 quoted=false*/
|
||||
|
||||
{
|
||||
if tok != fflib.FFTok_double && tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
|
||||
return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for float32", tok))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
if tok == fflib.FFTok_null {
|
||||
|
||||
} else {
|
||||
|
||||
tval, err := fflib.ParseFloat(fs.Output.Bytes(), 32)
|
||||
|
||||
if err != nil {
|
||||
return fs.WrapErr(err)
|
||||
}
|
||||
|
||||
j.X = float32(tval)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
|
||||
handle_Y:
|
||||
|
||||
/* handler: j.Y type=float32 kind=float32 quoted=false*/
|
||||
|
||||
{
|
||||
if tok != fflib.FFTok_double && tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
|
||||
return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for float32", tok))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
if tok == fflib.FFTok_null {
|
||||
|
||||
} else {
|
||||
|
||||
tval, err := fflib.ParseFloat(fs.Output.Bytes(), 32)
|
||||
|
||||
if err != nil {
|
||||
return fs.WrapErr(err)
|
||||
}
|
||||
|
||||
j.Y = float32(tval)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
|
||||
handle_Z:
|
||||
|
||||
/* handler: j.Z type=float32 kind=float32 quoted=false*/
|
||||
|
||||
{
|
||||
if tok != fflib.FFTok_double && tok != fflib.FFTok_integer && tok != fflib.FFTok_null {
|
||||
return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for float32", tok))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
if tok == fflib.FFTok_null {
|
||||
|
||||
} else {
|
||||
|
||||
tval, err := fflib.ParseFloat(fs.Output.Bytes(), 32)
|
||||
|
||||
if err != nil {
|
||||
return fs.WrapErr(err)
|
||||
}
|
||||
|
||||
j.Z = float32(tval)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
|
||||
wantedvalue:
|
||||
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
|
||||
wrongtokenerror:
|
||||
return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
|
||||
tokerror:
|
||||
if fs.BigError != nil {
|
||||
return fs.WrapErr(fs.BigError)
|
||||
}
|
||||
err = fs.Error.ToError()
|
||||
if err != nil {
|
||||
return fs.WrapErr(err)
|
||||
}
|
||||
panic("ffjson-generated: unreachable, please report bug.")
|
||||
done:
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -8,32 +8,51 @@ import (
|
||||
"github.com/francoispqt/gojay"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/pquerna/ffjson/ffjson"
|
||||
"xinu.tv/rustperf/src/ffjsonvec3"
|
||||
)
|
||||
|
||||
type testFunc struct {
|
||||
name string
|
||||
f func([]Vec3) ([]byte, error)
|
||||
f func(start, stop func(), vs []Vec3) ([]byte, error)
|
||||
}
|
||||
|
||||
var encodeFuncs = []testFunc{
|
||||
{"HandRolled", HandRolled},
|
||||
{"stdlib", func(vs []Vec3) ([]byte, error) {
|
||||
{"HandRolled", func(_, _ func(), vs []Vec3) ([]byte, error) {
|
||||
return HandRolled(vs)
|
||||
}},
|
||||
{"stdlib", func(_, _ func(), vs []Vec3) ([]byte, error) {
|
||||
return json.Marshal(vs)
|
||||
}},
|
||||
{"ffjson", func(vs []Vec3) ([]byte, error) {
|
||||
{"ffjsonvec3", func(start, stop func(), vs []Vec3) ([]byte, error) {
|
||||
stop()
|
||||
var vecs []ffjsonvec3.Vec3
|
||||
for _, v := range vs {
|
||||
v := ffjsonvec3.Vec3{
|
||||
X: v.X,
|
||||
Y: v.Y,
|
||||
Z: v.Z,
|
||||
}
|
||||
vecs = append(vecs, v)
|
||||
}
|
||||
start()
|
||||
|
||||
return ffjson.Marshal(vecs)
|
||||
}},
|
||||
{"ffjson", func(_, _ func(), vs []Vec3) ([]byte, error) {
|
||||
return ffjson.Marshal(vs)
|
||||
}},
|
||||
{"iterator", func(vs []Vec3) ([]byte, error) {
|
||||
{"iterator", func(_, _ func(), vs []Vec3) ([]byte, error) {
|
||||
var js = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
return js.Marshal(vs)
|
||||
}},
|
||||
{"gojay", func(vs []Vec3) ([]byte, error) {
|
||||
{"gojay", func(start, stop func(), vs []Vec3) ([]byte, error) {
|
||||
stop()
|
||||
var vecs Vec3Slice
|
||||
for _, v := range vs {
|
||||
v := v
|
||||
vecs = append(vecs, &v)
|
||||
}
|
||||
|
||||
start()
|
||||
return gojay.Marshal(&vecs)
|
||||
}},
|
||||
}
|
||||
@ -46,7 +65,9 @@ func TestVec3ToJSON(t *testing.T) {
|
||||
|
||||
for _, ts := range encodeFuncs {
|
||||
t.Run(ts.name, func(t *testing.T) {
|
||||
got, err := ts.f(vecs)
|
||||
stop := func() {}
|
||||
start := func() {}
|
||||
got, err := ts.f(start, stop, vecs)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal: %v", err)
|
||||
}
|
||||
@ -69,8 +90,10 @@ func BenchmarkVec3ToJSON(b *testing.B) {
|
||||
}
|
||||
for _, ts := range encodeFuncs {
|
||||
b.Run(ts.name, func(b *testing.B) {
|
||||
stop := func() { b.StopTimer() }
|
||||
start := func() { b.StartTimer() }
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := ts.f(vecs); err != nil {
|
||||
if _, err := ts.f(start, stop, vecs); err != nil {
|
||||
b.Fatalf("Failed to marshal: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user