123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
- // Use of this source code is governed by a MIT license found in the LICENSE file.
- package codec
- import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "encoding/xml"
- "reflect"
- "runtime"
- "testing"
- "time"
- )
- // Sample way to run:
- // go test -bi -bv -bd=1 -benchmem -bench=.
- func init() {
- testPreInitFns = append(testPreInitFns, benchPreInit)
- testPostInitFns = append(testPostInitFns, benchPostInit)
- }
- var (
- benchTs *TestStruc
- approxSize int
- benchCheckers []benchChecker
- )
- type benchEncFn func(interface{}, []byte) ([]byte, error)
- type benchDecFn func([]byte, interface{}) error
- type benchIntfFn func() interface{}
- type benchChecker struct {
- name string
- encodefn benchEncFn
- decodefn benchDecFn
- }
- func benchReinit() {
- benchCheckers = nil
- }
- func benchPreInit() {
- benchTs = newTestStruc(benchDepth, testNumRepeatString, true, !testSkipIntf, benchMapStringKeyOnly)
- approxSize = approxDataSize(reflect.ValueOf(benchTs)) * 3 / 2 // multiply by 1.5 to appease msgp, and prevent alloc
- // bytesLen := 1024 * 4 * (benchDepth + 1) * (benchDepth + 1)
- // if bytesLen < approxSize {
- // bytesLen = approxSize
- // }
- benchCheckers = append(benchCheckers,
- benchChecker{"msgpack", fnMsgpackEncodeFn, fnMsgpackDecodeFn},
- benchChecker{"binc", fnBincEncodeFn, fnBincDecodeFn},
- benchChecker{"simple", fnSimpleEncodeFn, fnSimpleDecodeFn},
- benchChecker{"cbor", fnCborEncodeFn, fnCborDecodeFn},
- benchChecker{"json", fnJsonEncodeFn, fnJsonDecodeFn},
- benchChecker{"std-json", fnStdJsonEncodeFn, fnStdJsonDecodeFn},
- benchChecker{"gob", fnGobEncodeFn, fnGobDecodeFn},
- benchChecker{"std-xml", fnStdXmlEncodeFn, fnStdXmlDecodeFn},
- )
- }
- func benchPostInit() {
- if benchDoInitBench {
- runBenchInit()
- }
- }
- func runBenchInit() {
- // logT(nil, "..............................................")
- logT(nil, "BENCHMARK INIT: %v", time.Now())
- // logT(nil, "To run full benchmark comparing encodings, use: \"go test -bench=.\"")
- logT(nil, "Benchmark: ")
- logT(nil, "\tStruct recursive Depth: %d", benchDepth)
- if approxSize > 0 {
- logT(nil, "\tApproxDeepSize Of benchmark Struct: %d bytes", approxSize)
- }
- if benchUnscientificRes {
- logT(nil, "Benchmark One-Pass Run (with Unscientific Encode/Decode times): ")
- } else {
- logT(nil, "Benchmark One-Pass Run:")
- }
- for _, bc := range benchCheckers {
- doBenchCheck(bc.name, bc.encodefn, bc.decodefn)
- }
- logT(nil, "..............................................")
- if benchInitDebug {
- logT(nil, "<<<<====>>>> depth: %v, ts: %#v\n", benchDepth, benchTs)
- }
- runtime.GC()
- time.Sleep(100 * time.Millisecond)
- }
- var vBenchTs = TestStruc{}
- func fnBenchNewTs() interface{} {
- vBenchTs = TestStruc{}
- return &vBenchTs
- // return new(TestStruc)
- }
- // const benchCheckDoDeepEqual = false
- func benchRecoverPanic(t interface{}) {
- if r := recover(); r != nil {
- logT(t, "panic: %v\n", r)
- }
- }
- func doBenchCheck(name string, encfn benchEncFn, decfn benchDecFn) {
- // if benchUnscientificRes {
- // logT(nil, "-------------- %s ----------------", name)
- // }
- defer benchRecoverPanic(nil)
- runtime.GC()
- tnow := time.Now()
- buf, err := encfn(benchTs, nil)
- if err != nil {
- logT(nil, "\t%10s: **** Error encoding benchTs: %v", name, err)
- return
- }
- encDur := time.Since(tnow)
- encLen := len(buf)
- runtime.GC()
- if !benchUnscientificRes {
- logT(nil, "\t%10s: len: %d bytes\n", name, encLen)
- return
- }
- tnow = time.Now()
- var ts2 TestStruc
- if err = decfn(buf, &ts2); err != nil {
- logT(nil, "\t%10s: **** Error decoding into new TestStruc: %v", name, err)
- return
- }
- decDur := time.Since(tnow)
- // if benchCheckDoDeepEqual {
- if benchVerify {
- err = deepEqual(benchTs, &ts2)
- if err == nil {
- logT(nil, "\t%10s: len: %d bytes,\t encode: %v,\t decode: %v,\tencoded = decoded", name, encLen, encDur, decDur)
- } else {
- logT(nil, "\t%10s: len: %d bytes,\t encode: %v,\t decode: %v,\tencoded != decoded: %v", name, encLen, encDur, decDur, err)
- // if strings.Contains(name, "json") {
- // println(">>>>>")
- // f1, _ := os.Create("1.out")
- // f2, _ := os.Create("2.out")
- // f3, _ := os.Create("3.json")
- // buf3, _ := json.MarshalIndent(&ts2, "", "\t")
- // spew.Config.SortKeys = true
- // spew.Config.SpewKeys = true
- // println("^^^^^^^^^^^^^^")
- // spew.Fdump(f1, benchTs)
- // println("^^^^^^^^^^^^^^")
- // spew.Fdump(f2, &ts2)
- // println("^^^^^^^^^^^^^^")
- // f3.Write(buf3)
- // f1.Close()
- // f2.Close()
- // f3.Close()
- // }
- // logT(nil, "\t: err: %v,\n benchTs: %#v\n\n, ts2: %#v\n\n", err, benchTs, ts2) // TODO: remove
- // logT(nil, "BenchVerify: Error comparing en|decoded TestStruc: %v", err)
- // return
- // logT(nil, "BenchVerify: Error comparing benchTs: %v\n--------\n%v\n--------\n%v", err, benchTs, ts2)
- // if strings.Contains(name, "json") {
- // logT(nil, "\n\tDECODED FROM\n--------\n%s", buf)
- // }
- }
- } else {
- logT(nil, "\t%10s: len: %d bytes,\t encode: %v,\t decode: %v", name, encLen, encDur, decDur)
- }
- return
- }
- func fnBenchmarkEncode(b *testing.B, encName string, ts interface{}, encfn benchEncFn) {
- defer benchRecoverPanic(b)
- testOnce.Do(testInitAll)
- var err error
- bs := make([]byte, 0, approxSize)
- runtime.GC()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- if _, err = encfn(ts, bs); err != nil {
- break
- }
- }
- if err != nil {
- logT(b, "Error encoding benchTs: %s: %v", encName, err)
- b.FailNow()
- }
- }
- func fnBenchmarkDecode(b *testing.B, encName string, ts interface{},
- encfn benchEncFn, decfn benchDecFn, newfn benchIntfFn,
- ) {
- defer benchRecoverPanic(b)
- testOnce.Do(testInitAll)
- bs := make([]byte, 0, approxSize)
- buf, err := encfn(ts, bs)
- if err != nil {
- logT(b, "Error encoding benchTs: %s: %v", encName, err)
- b.FailNow()
- }
- if false && benchVerify { // do not do benchVerify during decode
- // ts2 := newfn()
- ts1 := ts.(*TestStruc)
- ts2 := new(TestStruc)
- if err = decfn(buf, ts2); err != nil {
- logT(b, "BenchVerify: Error decoding benchTs: %s: %v", encName, err)
- b.FailNow()
- }
- if err = deepEqual(ts1, ts2); err != nil {
- logT(b, "BenchVerify: Error comparing benchTs: %s: %v", encName, err)
- b.FailNow()
- }
- }
- runtime.GC()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- ts = newfn()
- if err = decfn(buf, ts); err != nil {
- break
- }
- }
- if err != nil {
- logT(b, "Error decoding into new TestStruc: %s: %v", encName, err)
- b.FailNow()
- }
- }
- // ------------ tests below
- func fnMsgpackEncodeFn(ts interface{}, bsIn []byte) (bs []byte, err error) {
- return sTestCodecEncode(ts, bsIn, fnBenchmarkByteBuf, testMsgpackH, &testMsgpackH.BasicHandle)
- }
- func fnMsgpackDecodeFn(buf []byte, ts interface{}) error {
- return sTestCodecDecode(buf, ts, testMsgpackH, &testMsgpackH.BasicHandle)
- }
- func fnBincEncodeFn(ts interface{}, bsIn []byte) (bs []byte, err error) {
- return sTestCodecEncode(ts, bsIn, fnBenchmarkByteBuf, testBincH, &testBincH.BasicHandle)
- }
- func fnBincDecodeFn(buf []byte, ts interface{}) error {
- return sTestCodecDecode(buf, ts, testBincH, &testBincH.BasicHandle)
- }
- func fnSimpleEncodeFn(ts interface{}, bsIn []byte) (bs []byte, err error) {
- return sTestCodecEncode(ts, bsIn, fnBenchmarkByteBuf, testSimpleH, &testSimpleH.BasicHandle)
- }
- func fnSimpleDecodeFn(buf []byte, ts interface{}) error {
- return sTestCodecDecode(buf, ts, testSimpleH, &testSimpleH.BasicHandle)
- }
- func fnCborEncodeFn(ts interface{}, bsIn []byte) (bs []byte, err error) {
- return sTestCodecEncode(ts, bsIn, fnBenchmarkByteBuf, testCborH, &testCborH.BasicHandle)
- }
- func fnCborDecodeFn(buf []byte, ts interface{}) error {
- return sTestCodecDecode(buf, ts, testCborH, &testCborH.BasicHandle)
- }
- func fnJsonEncodeFn(ts interface{}, bsIn []byte) (bs []byte, err error) {
- return sTestCodecEncode(ts, bsIn, fnBenchmarkByteBuf, testJsonH, &testJsonH.BasicHandle)
- }
- func fnJsonDecodeFn(buf []byte, ts interface{}) error {
- return sTestCodecDecode(buf, ts, testJsonH, &testJsonH.BasicHandle)
- }
- func fnGobEncodeFn(ts interface{}, bsIn []byte) ([]byte, error) {
- buf := fnBenchmarkByteBuf(bsIn)
- err := gob.NewEncoder(buf).Encode(ts)
- return buf.Bytes(), err
- }
- func fnGobDecodeFn(buf []byte, ts interface{}) error {
- return gob.NewDecoder(bytes.NewReader(buf)).Decode(ts)
- }
- func fnStdXmlEncodeFn(ts interface{}, bsIn []byte) ([]byte, error) {
- buf := fnBenchmarkByteBuf(bsIn)
- err := xml.NewEncoder(buf).Encode(ts)
- return buf.Bytes(), err
- }
- func fnStdXmlDecodeFn(buf []byte, ts interface{}) error {
- return xml.NewDecoder(bytes.NewReader(buf)).Decode(ts)
- }
- func fnStdJsonEncodeFn(ts interface{}, bsIn []byte) ([]byte, error) {
- if testUseIoEncDec >= 0 {
- buf := fnBenchmarkByteBuf(bsIn)
- err := json.NewEncoder(buf).Encode(ts)
- return buf.Bytes(), err
- }
- return json.Marshal(ts)
- }
- func fnStdJsonDecodeFn(buf []byte, ts interface{}) error {
- if testUseIoEncDec >= 0 {
- return json.NewDecoder(bytes.NewReader(buf)).Decode(ts)
- }
- return json.Unmarshal(buf, ts)
- }
- // ----------- DECODE ------------------
- func Benchmark__Msgpack____Encode(b *testing.B) {
- fnBenchmarkEncode(b, "msgpack", benchTs, fnMsgpackEncodeFn)
- }
- func Benchmark__Binc_______Encode(b *testing.B) {
- fnBenchmarkEncode(b, "binc", benchTs, fnBincEncodeFn)
- }
- func Benchmark__Simple_____Encode(b *testing.B) {
- fnBenchmarkEncode(b, "simple", benchTs, fnSimpleEncodeFn)
- }
- func Benchmark__Cbor_______Encode(b *testing.B) {
- fnBenchmarkEncode(b, "cbor", benchTs, fnCborEncodeFn)
- }
- func Benchmark__Json_______Encode(b *testing.B) {
- fnBenchmarkEncode(b, "json", benchTs, fnJsonEncodeFn)
- }
- func Benchmark__Std_Json___Encode(b *testing.B) {
- fnBenchmarkEncode(b, "std-json", benchTs, fnStdJsonEncodeFn)
- }
- func Benchmark__Gob________Encode(b *testing.B) {
- fnBenchmarkEncode(b, "gob", benchTs, fnGobEncodeFn)
- }
- func Benchmark__Std_Xml____Encode(b *testing.B) {
- fnBenchmarkEncode(b, "std-xml", benchTs, fnStdXmlEncodeFn)
- }
- // ----------- DECODE ------------------
- func Benchmark__Msgpack____Decode(b *testing.B) {
- fnBenchmarkDecode(b, "msgpack", benchTs, fnMsgpackEncodeFn, fnMsgpackDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Binc_______Decode(b *testing.B) {
- fnBenchmarkDecode(b, "binc", benchTs, fnBincEncodeFn, fnBincDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Simple_____Decode(b *testing.B) {
- fnBenchmarkDecode(b, "simple", benchTs, fnSimpleEncodeFn, fnSimpleDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Cbor_______Decode(b *testing.B) {
- fnBenchmarkDecode(b, "cbor", benchTs, fnCborEncodeFn, fnCborDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Json_______Decode(b *testing.B) {
- fnBenchmarkDecode(b, "json", benchTs, fnJsonEncodeFn, fnJsonDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Std_Json___Decode(b *testing.B) {
- fnBenchmarkDecode(b, "std-json", benchTs, fnStdJsonEncodeFn, fnStdJsonDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Gob________Decode(b *testing.B) {
- fnBenchmarkDecode(b, "gob", benchTs, fnGobEncodeFn, fnGobDecodeFn, fnBenchNewTs)
- }
- func Benchmark__Std_Xml____Decode(b *testing.B) {
- fnBenchmarkDecode(b, "std-xml", benchTs, fnStdXmlEncodeFn, fnStdXmlDecodeFn, fnBenchNewTs)
- }
|