Skip to content

Instantly share code, notes, and snippets.

@edsrzf
Last active August 29, 2015 13:56
Show Gist options
  • Save edsrzf/9314832 to your computer and use it in GitHub Desktop.
Save edsrzf/9314832 to your computer and use it in GitHub Desktop.
Fair serialization benchmarks
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
"io"
"io/ioutil"
"math"
"testing"
"time"
"github.com/ugorji/go/codec"
)
type AnonInTestStruc struct {
AS string
AI64 int64
AI16 int16
AUi64 uint64
ASslice []string
AI64slice []int64
}
type TestStruc struct {
S string
I64 int64
I16 int16
Ui64 uint64
Ui8 uint8
B bool
By byte
Sslice []string
I64slice []int64
I16slice []int16
Ui64slice []uint64
Ui8slice []uint8
Bslice []bool
Byslice []byte
Islice []interface{}
Iptrslice []*int64
AnonInTestStruc
//M map[interface{}]interface{} `json:"-",bson:"-"`
Ms map[string]interface{}
Msi64 map[string]int64
Nintf interface{} //don't set this, so we can test for nil
T time.Time
Nmap map[string]bool //don't set this, so we can test for nil
Nslice []byte //don't set this, so we can test for nil
Nint64 *int64 //don't set this, so we can test for nil
Mtsptr map[string]*TestStruc
Mts map[string]TestStruc
Its []*TestStruc
Nteststruc *TestStruc
}
var timeLoc = time.FixedZone("", -8*60*60) // UTC-08:00 //time.UTC-8
var timeToCompare1 = time.Date(2012, 2, 2, 2, 2, 2, 2000, timeLoc)
func newTestStruc(depth int, bench bool) (ts *TestStruc) {
ts = &TestStruc{
S: "some string",
I64: math.MaxInt64 * 2 / 3, // 64,
I16: 16,
Ui64: uint64(int64(math.MaxInt64 * 2 / 3)), // 64, //don't use MaxUint64, as bson can't write it
Ui8: 160,
B: true,
By: 5,
Sslice: []string{"one", "two", "three"},
I64slice: []int64{1, 2, 3},
I16slice: []int16{4, 5, 6},
Ui64slice: []uint64{137, 138, 139},
Ui8slice: []uint8{210, 211, 212},
Bslice: []bool{true, false, true, false},
Byslice: []byte{13, 14, 15},
Islice: []interface{}{"true", true, "no", false, uint64(288), float64(0.4)},
Ms: map[string]interface{}{
"true": "true",
"int64(9)": false,
},
Msi64: map[string]int64{
"one": 1,
"two": 2,
},
T: timeToCompare1,
AnonInTestStruc: AnonInTestStruc{
AS: "A-String",
AI64: 64,
AI16: 16,
AUi64: 64,
ASslice: []string{"Aone", "Atwo", "Athree"},
AI64slice: []int64{1, 2, 3},
},
}
if depth > 0 {
depth--
if ts.Mtsptr == nil {
ts.Mtsptr = make(map[string]*TestStruc)
}
if ts.Mts == nil {
ts.Mts = make(map[string]TestStruc)
}
ts.Mtsptr["0"] = newTestStruc(depth, bench)
ts.Mts["0"] = *(ts.Mtsptr["0"])
ts.Its = append(ts.Its, ts.Mtsptr["0"])
}
return
}
const benchDepth = 1
var benchTs = newTestStruc(benchDepth, true)
type Encoder interface {
Encode(v interface{}) error
}
func benchEncode(b *testing.B, enc Encoder) {
var ts interface{} = benchTs
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := enc.Encode(ts)
if err != nil {
b.Fatal("benchEncode error:", err)
}
}
}
func BenchmarkGobEncode(b *testing.B) {
enc := gob.NewEncoder(ioutil.Discard)
benchEncode(b, enc)
}
func BenchmarkJSONEncode(b *testing.B) {
enc := json.NewEncoder(ioutil.Discard)
benchEncode(b, enc)
}
func BenchmarkMsgpackEncode(b *testing.B) {
enc := codec.NewEncoder(ioutil.Discard, &codec.MsgpackHandle{})
benchEncode(b, enc)
}
type Decoder interface {
Decode(v interface{}) error
}
type loopReader struct {
buf []byte
repeating int
i int
}
func (r *loopReader) Read(b []byte) (int, error) {
n := copy(b, r.buf[r.i:])
r.i += n
if r.i >= len(r.buf) {
r.i = r.repeating
}
return n, nil
}
func loadReader(buf *bytes.Buffer, enc Encoder) io.Reader {
err := enc.Encode(benchTs)
if err != nil {
panic("error encoding decode benchmark")
}
return &loopReader{buf: buf.Bytes()}
}
func benchDecode(b *testing.B, dec Decoder) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var ts TestStruc
err := dec.Decode(&ts)
if err != nil {
b.Fatal("benchEncode error:", err)
}
}
}
func BenchmarkGobDecode(b *testing.B) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
enc.Encode(benchTs)
r := &loopReader{repeating: buf.Len()}
r.buf = append(r.buf, buf.Bytes()...)
buf.Reset()
enc.Encode(benchTs)
r.buf = append(r.buf, buf.Bytes()...)
dec := gob.NewDecoder(r)
benchDecode(b, dec)
}
func BenchmarkJSONDecode(b *testing.B) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
dec := json.NewDecoder(loadReader(&buf, enc))
benchDecode(b, dec)
}
func BenchmarkMsgpackDecode(b *testing.B) {
var buf bytes.Buffer
enc := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
dec := codec.NewDecoder(loadReader(&buf, enc), &codec.MsgpackHandle{})
benchDecode(b, dec)
}
@edsrzf
Copy link
Author

edsrzf commented Mar 2, 2014

Results on my machine:

testing: warning: no tests to run
PASS
BenchmarkGobEncode     20000         80347 ns/op
BenchmarkJSONEncode    50000         65073 ns/op
BenchmarkMsgpackEncode     50000         64529 ns/op
BenchmarkGobDecode     20000         91653 ns/op
BenchmarkJSONDecode    10000        256693 ns/op
BenchmarkMsgpackDecode     10000        134442 ns/op
ok      _/home/evan/ironio/serbench 16.976s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment