proto: add simple benchmark
Run the encode/decode tests as benchmarks. These are trivial microbenchmarks
and not representative of real-world usage, but serve as a useful overview
of the relative cost of various operations and are handy for profiling
specific narrow scenarios.
When run with the -v1 flag, benchmark the v1 implementation for comparison.
Change-Id: I469dd6759bef50e2bd039327095f82d29d70b8fc
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/171120
Reviewed-by: Joe Tsai <[email protected]>
diff --git a/proto/bench_test.go b/proto/bench_test.go
new file mode 100644
index 0000000..a38d11b
--- /dev/null
+++ b/proto/bench_test.go
@@ -0,0 +1,75 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto_test
+
+import (
+ "flag"
+ "fmt"
+ "reflect"
+ "testing"
+
+ protoV1 "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/v2/proto"
+)
+
+// The results of these microbenchmarks are unlikely to correspond well
+// to real world peformance. They are mainly useful as a quick check to
+// detect unexpected regressions and for profiling specific cases.
+
+var (
+ benchV1 = flag.Bool("v1", false, "benchmark the v1 implementation")
+ allowPartial = flag.Bool("allow_partial", false, "set AllowPartial")
+)
+
+// BenchmarkEncode benchmarks encoding all the test messages.
+func BenchmarkEncode(b *testing.B) {
+ for _, test := range testProtos {
+ for _, want := range test.decodeTo {
+ v1 := want.(protoV1.Message)
+ opts := proto.MarshalOptions{AllowPartial: *allowPartial}
+ b.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ var err error
+ if *benchV1 {
+ _, err = protoV1.Marshal(v1)
+ } else {
+ _, err = opts.Marshal(want)
+ }
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+ })
+ }
+ }
+}
+
+// BenchmarkDecode benchmarks decoding all the test messages.
+func BenchmarkDecode(b *testing.B) {
+ for _, test := range testProtos {
+ for _, want := range test.decodeTo {
+ opts := proto.UnmarshalOptions{AllowPartial: *allowPartial}
+ b.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ m := reflect.New(reflect.TypeOf(want).Elem()).Interface().(proto.Message)
+ v1 := m.(protoV1.Message)
+ for pb.Next() {
+ var err error
+ if *benchV1 {
+ err = protoV1.Unmarshal(test.wire, v1)
+ } else {
+ err = opts.Unmarshal(test.wire, m)
+ }
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+ })
+ }
+ }
+}