Skip to content

Instantly share code, notes, and snippets.

@tommyo
Last active February 1, 2022 17:35
Show Gist options
  • Save tommyo/849e9fb8db0310ea14ba2f07ab2c25f1 to your computer and use it in GitHub Desktop.
Save tommyo/849e9fb8db0310ea14ba2f07ab2c25f1 to your computer and use it in GitHub Desktop.
Benchmark Generics when running json.Marshal and json.Unmarshal with a nested unknown
package benchmark
import (
"encoding/json"
"testing"
)
var innerJson []byte = []byte(`{ "foo": "bar" }`)
var fullJson []byte = []byte(`{ "name": "foo", "value": { "foo": "bar" }}`)
var fin []byte
type Inner struct {
Foo string `json:"foo"`
}
type Wrapped struct {
Name string `json:"name"`
Value interface{} `json:"value"`
}
type UnWrapped struct {
Name string `json:"name"`
Value json.RawMessage `json:"value"`
}
type Generic[T any] struct {
Name string `json:"name"`
Value T `json:"value"`
}
func BenchmarkMarshalInner(b *testing.B) {
inner := Inner{"bar"}
var res []byte
b.ResetTimer()
for n := 0; n < b.N; n++ {
res, _ = json.Marshal(inner)
}
fin = res
}
func BenchmarkMarshalWrapped(b *testing.B) {
wrapped := Wrapped{
Name: "foo",
Value: Inner{"bar"},
}
var res []byte
b.ResetTimer()
for n := 0; n < b.N; n++ {
res, _ = json.Marshal(wrapped)
}
fin = res
}
func BenchmarkMarshalGeneric(b *testing.B) {
generic := Generic[Inner]{
Name: "foo",
Value: Inner{"bar"},
}
var res []byte
b.ResetTimer()
for n := 0; n < b.N; n++ {
res, _ = json.Marshal(generic)
}
fin = res
}
// Unmarshal the inner part only, as a baseline metric
func BenchmarkUnmarshalInner(b *testing.B) {
var inner Inner
b.ResetTimer()
for n := 0; n < b.N; n++ {
json.Unmarshal(innerJson, &inner)
}
}
// The Inner is a map[string]interface{}, not type aligned
func BenchmarkUnmarshalWrapped(b *testing.B) {
var wrapped Wrapped
b.ResetTimer()
for n := 0; n < b.N; n++ {
json.Unmarshal(fullJson, &wrapped)
}
}
// The inner is []byte, ready to be Unmarshalled
func BenchmarkUnmarshalUnwrapped(b *testing.B) {
var unwrapped UnWrapped
b.ResetTimer()
for n := 0; n < b.N; n++ {
json.Unmarshal(fullJson, &unwrapped)
}
}
// Inner is the proper type
func BenchmarkUnmarshalUnwrappedFull(b *testing.B) {
var unwrapped UnWrapped
var inner Inner
b.ResetTimer()
for n := 0; n < b.N; n++ {
json.Unmarshal(fullJson, &unwrapped)
json.Unmarshal(unwrapped.Value, &inner)
}
}
// Inner is the proper type
func BenchmarkUnmarshalGeneric(b *testing.B) {
var generic Generic[Inner]
b.ResetTimer()
for n := 0; n < b.N; n++ {
json.Unmarshal(fullJson, &generic)
}
}
goos: darwin
goarch: amd64
pkg: github.com/huffduff/go-indexeddb/benchmark
cpu: VirtualApple @ 2.50GHz
BenchmarkMarshalInner-8 8437233 140.0 ns/op 32 B/op 2 allocs/op
BenchmarkMarshalWrapped-8 4984962 240.4 ns/op 80 B/op 2 allocs/op
BenchmarkMarshalGeneric-8 5740166 206.3 ns/op 80 B/op 2 allocs/op
BenchmarkUnmarshalInner-8 2776051 427.7 ns/op 224 B/op 5 allocs/op
BenchmarkUnmarshalWrapped-8 1331446 889.6 ns/op 600 B/op 11 allocs/op
BenchmarkUnmarshalUnwrapped-8 1613664 752.5 ns/op 240 B/op 6 allocs/op
BenchmarkUnmarshalUnwrappedFull-8 968174 1203 ns/op 464 B/op 11 allocs/op
BenchmarkUnmarshalGeneric-8 1359284 881.4 ns/op 272 B/op 8 allocs/op
PASS
ok github.com/huffduff/go-indexeddb/benchmark 13.372s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment