123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- // 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
- // bench_test is the "helper" file for all benchmarking tests.
- //
- // There are also benchmarks which depend on just codec and the stdlib,
- // and benchmarks which depend on external libraries.
- // It is an explicit goal that you can run benchmarks without external
- // dependencies (which is why the 'x' build tag was explicitly introduced).
- //
- // There are 2 ways of running tests:
- // - generated
- // - not generated
- //
- // Consequently, we have 4 groups:
- // - codec_bench (gen, !gen)
- // - stdlib_bench (!gen only)
- // - x_bench (!gen only)
- // - x_bench_gen (gen only)
- //
- // We also have 4 matching suite files.
- // - z_all_bench (rename later to z_all_codec_bench???)
- // - z_all_stdlib_bench
- // - z_all_x_bench
- // - z_all_x_bench_gen
- //
- // Finally, we have a single test (TestBenchInit) that
- // will log information about whether each format can
- // encode or not, how long to encode (unscientifically),
- // and the encode size.
- //
- // This test MUST be run always, as it calls init() internally
- import (
- "reflect"
- "runtime"
- "testing"
- "time"
- )
- // Sample way to run:
- // go test -bi -bv -bd=1 -benchmem -bench=.
- const (
- benchUnscientificRes = true
- benchVerify = true
- benchRecover = true
- benchShowJsonOnError = true
- )
- 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 init() {
- testPreInitFns = append(testPreInitFns, benchPreInit)
- // testPostInitFns = append(testPostInitFns, codecbenchPostInit)
- }
- func benchPreInit() {
- benchTs = newTestStruc(testDepth, testNumRepeatString, true, !testSkipIntf, testMapStringKeyOnly)
- approxSize = approxDataSize(reflect.ValueOf(benchTs)) * 3 / 2 // multiply by 1.5 to appease msgp, and prevent alloc
- // bytesLen := 1024 * 4 * (testDepth + 1) * (testDepth + 1)
- // if bytesLen < approxSize {
- // bytesLen = approxSize
- // }
- }
- func benchReinit() {
- benchCheckers = nil
- }
- func benchmarkDivider() {
- // logTv(nil, "-------------------------------\n")
- println()
- }
- // func Test0(t *testing.T) {
- // testOnce.Do(testInitAll)
- // }
- func TestBenchInit(t *testing.T) {
- testOnce.Do(testInitAll)
- if !testing.Verbose() {
- return
- }
- // t.Logf("..............................................")
- t.Logf("BENCHMARK INIT: %v", time.Now())
- // t.Logf("To run full benchmark comparing encodings, use: \"go test -bench=.\"")
- t.Logf("Benchmark: ")
- t.Logf("\tStruct recursive Depth: %d", testDepth)
- if approxSize > 0 {
- t.Logf("\tApproxDeepSize Of benchmark Struct: %d bytes", approxSize)
- }
- if benchUnscientificRes {
- t.Logf("Benchmark One-Pass Run (with Unscientific Encode/Decode times): ")
- } else {
- t.Logf("Benchmark One-Pass Run:")
- }
- for _, bc := range benchCheckers {
- doBenchCheck(t, bc.name, bc.encodefn, bc.decodefn)
- }
- if testVerbose {
- t.Logf("..............................................")
- t.Logf("<<<<====>>>> depth: %v, ts: %#v\n", testDepth, 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 *testing.B) {
- if benchRecover {
- if r := recover(); r != nil {
- t.Logf("(recovered) panic: %v\n", r)
- }
- }
- }
- func benchRecoverPanicT(t *testing.T) {
- if benchRecover {
- if r := recover(); r != nil {
- t.Logf("(recovered) panic: %v\n", r)
- }
- }
- }
- func doBenchCheck(t *testing.T, name string, encfn benchEncFn, decfn benchDecFn) {
- // if benchUnscientificRes {
- // t.Logf("-------------- %s ----------------", name)
- // }
- defer benchRecoverPanicT(t)
- runtime.GC()
- tnow := time.Now()
- buf, err := encfn(benchTs, nil)
- if err != nil {
- t.Logf("\t%10s: **** Error encoding benchTs: %v", name, err)
- return
- }
- encDur := time.Since(tnow)
- encLen := len(buf)
- runtime.GC()
- if !benchUnscientificRes {
- t.Logf("\t%10s: len: %d bytes\n", name, encLen)
- return
- }
- tnow = time.Now()
- var ts2 TestStruc
- if err = decfn(buf, &ts2); err != nil {
- t.Logf("\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 {
- t.Logf("\t%10s: len: %d bytes,\t encode: %v,\t decode: %v,\tencoded == decoded", name, encLen, encDur, decDur)
- } else {
- t.Logf("\t%10s: len: %d bytes,\t encode: %v,\t decode: %v,\tencoded != decoded: %v", name, encLen, encDur, decDur, err)
- // if benchShowJsonOnError && strings.Contains(name, "json") {
- // fmt.Printf("\n\n%s\n\n", buf)
- // //fmt.Printf("\n\n%#v\n\n", benchTs)
- // //fmt.Printf("\n\n%#v\n\n", &ts2)
- // return
- // }
- // 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()
- // }
- // t.Logf("\t: err: %v,\n benchTs: %#v\n\n, ts2: %#v\n\n", err, benchTs, ts2) // TODO: remove
- // t.Logf("BenchVerify: Error comparing en|decoded TestStruc: %v", err)
- // return
- // t.Logf("BenchVerify: Error comparing benchTs: %v\n--------\n%v\n--------\n%v", err, benchTs, ts2)
- // if strings.Contains(name, "json") {
- // t.Logf("\n\tDECODED FROM\n--------\n%s", buf)
- // }
- }
- } else {
- t.Logf("\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 {
- b.Logf("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 {
- b.Logf("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 {
- // failT(b, "BenchVerify: Error decoding benchTs: %s: %v", encName, err)
- // }
- // if err = deepEqual(ts1, ts2); err != nil {
- // failT(b, "BenchVerify: Error comparing benchTs: %s: %v", encName, err)
- // }
- // }
- runtime.GC()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- ts = newfn()
- if err = decfn(buf, ts); err != nil {
- break
- }
- }
- if err != nil {
- b.Logf("Error decoding into new TestStruc: %s: %v", encName, err)
- b.FailNow()
- }
- }
|