Skip to content

Wonky performance numbers when encoding the same thing through different interfaces #45

Open
@karalabe

Description

@karalabe

I've tried a few different combinations of types and interfaces to encode the same thing. Interestingly, there's a 30% speed variation depending on what I'm calling, which seems extreme. I'd expect the same performance, independent of where the data enters into the encoder.

BenchmarkMarshal2String-12     	     232	   5220942 ns/op
BenchmarkMarshal2RawJSON-12    	     283	   4093803 ns/op
BenchmarkMarshal2Texter-12     	     222	   5399327 ns/op
BenchmarkMarshal2Jsoner-12     	     265	   4748703 ns/op
BenchmarkMarshal2Jsoner2-12    	     271	   4422361 ns/op
package test 

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"testing"

	json2 "github.com/go-json-experiment/json"
	"github.com/go-json-experiment/json/jsontext"
)

func BenchmarkMarshalString(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	str := hex.EncodeToString(src)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json.Marshal(str)
	}
}

func BenchmarkMarshal2String(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	str := hex.EncodeToString(src)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json2.Marshal(str)
	}
}

func BenchmarkMarshalRawJSON(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	msg := json.RawMessage(`"` + hex.EncodeToString(src) + `"`)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json.Marshal(msg)
	}
}

func BenchmarkMarshal2RawJSON(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	msg := json.RawMessage(`"` + hex.EncodeToString(src) + `"`)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json2.Marshal(msg)
	}
}

func BenchmarkMarshalTexter(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	txt := &Texter{str: hex.EncodeToString(src)}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json.Marshal(txt)
	}
}

func BenchmarkMarshal2Texter(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	txt := &Texter{str: hex.EncodeToString(src)}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json2.Marshal(txt)
	}
}

func BenchmarkMarshalJsoner(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	jsn := &Jsoner{str: hex.EncodeToString(src)}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json.Marshal(jsn)
	}
}

func BenchmarkMarshal2Jsoner(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	jsn := &Jsoner{str: hex.EncodeToString(src)}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json2.Marshal(jsn)
	}
}

func BenchmarkMarshal2Jsoner2(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	jsn := &Jsoner2{str: hex.EncodeToString(src)}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		json2.Marshal(jsn)
	}
}

func BenchmarkMarshalCopyString(b *testing.B) {
	src := bytes.Repeat([]byte{'0'}, 4194304)
	str := hex.EncodeToString(src)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		buf := make([]byte, len(str)+2)
		buf[0] = '"'
		copy(buf[1:], str)
		buf[len(buf)-1] = '"'
	}
}

type Texter struct {
	str string
}

func (t Texter) MarshalText() ([]byte, error) {
	return []byte(t.str), nil
}

type Jsoner struct {
	str string
}

func (j Jsoner) MarshalJSON() ([]byte, error) {
	return []byte(`"` + j.str + `"`), nil
}

type Jsoner2 struct {
	str string
}

func (j Jsoner2) MarshalJSONV2(enc *jsontext.Encoder, opts json2.Options) error {
	return enc.WriteValue([]byte(`"` + j.str + `"`))
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions