|  | // Copyright 2020 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. | 
|  |  | 
|  | // This package contains microbenchmarks exercising specific areas of interest. | 
|  | // The benchmarks here are not comprehensive and are not necessarily indicative | 
|  | // real-world performance. | 
|  |  | 
|  | package micro_test | 
|  |  | 
|  | import ( | 
|  | "testing" | 
|  |  | 
|  | "google.golang.org/protobuf/internal/impl" | 
|  | "google.golang.org/protobuf/proto" | 
|  | "google.golang.org/protobuf/runtime/protoiface" | 
|  | "google.golang.org/protobuf/types/known/emptypb" | 
|  |  | 
|  | micropb "google.golang.org/protobuf/internal/testprotos/benchmarks/micro" | 
|  | testpb "google.golang.org/protobuf/internal/testprotos/test" | 
|  | ) | 
|  |  | 
|  | // BenchmarkEmptyMessage tests a google.protobuf.Empty. | 
|  | // | 
|  | // It measures per-operation overhead. | 
|  | func BenchmarkEmptyMessage(b *testing.B) { | 
|  | b.Run("Wire/Marshal", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | m := &emptypb.Empty{} | 
|  | for pb.Next() { | 
|  | if _, err := proto.Marshal(m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Unmarshal", func(b *testing.B) { | 
|  | opts := proto.UnmarshalOptions{ | 
|  | Merge: true, | 
|  | } | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | m := &emptypb.Empty{} | 
|  | for pb.Next() { | 
|  | if err := opts.Unmarshal([]byte{}, m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Validate", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | mt := (&emptypb.Empty{}).ProtoReflect().Type() | 
|  | for pb.Next() { | 
|  | _, got := impl.Validate(mt, protoiface.UnmarshalInput{}) | 
|  | want := impl.ValidationValid | 
|  | if got != want { | 
|  | b.Fatalf("Validate = %v, want %v", got, want) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Clone", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | m := &emptypb.Empty{} | 
|  | for pb.Next() { | 
|  | proto.Clone(m) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("New", func(b *testing.B) { | 
|  | mt := (&emptypb.Empty{}).ProtoReflect().Type() | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | for pb.Next() { | 
|  | mt.New() | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | // BenchmarkRepeatedInt32 tests a message containing 500 non-packed repeated int32s. | 
|  | // | 
|  | // For unmarshal operations, it measures the cost of the field decode loop, since each | 
|  | // item in the repeated field has an individual tag and value. | 
|  | func BenchmarkRepeatedInt32(b *testing.B) { | 
|  | m := &testpb.TestAllTypes{} | 
|  | for i := int32(0); i < 500; i++ { | 
|  | m.RepeatedInt32 = append(m.RepeatedInt32, i) | 
|  | } | 
|  | w, err := proto.Marshal(m) | 
|  | if err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | b.Run("Wire/Marshal", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | for pb.Next() { | 
|  | if _, err := proto.Marshal(m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Unmarshal", func(b *testing.B) { | 
|  | opts := proto.UnmarshalOptions{ | 
|  | Merge: true, | 
|  | } | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | m := &testpb.TestAllTypes{} | 
|  | for pb.Next() { | 
|  | m.RepeatedInt32 = m.RepeatedInt32[:0] | 
|  | if err := opts.Unmarshal(w, m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Validate", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | mt := (&testpb.TestAllTypes{}).ProtoReflect().Type() | 
|  | for pb.Next() { | 
|  | _, got := impl.Validate(mt, protoiface.UnmarshalInput{ | 
|  | Buf: w, | 
|  | }) | 
|  | want := impl.ValidationValid | 
|  | if got != want { | 
|  | b.Fatalf("Validate = %v, want %v", got, want) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Clone", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | for pb.Next() { | 
|  | proto.Clone(m) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | // BenchmarkRequired tests a message containing a required field. | 
|  | func BenchmarkRequired(b *testing.B) { | 
|  | m := µpb.SixteenRequired{ | 
|  | F1:  proto.Int32(1), | 
|  | F2:  proto.Int32(1), | 
|  | F3:  proto.Int32(1), | 
|  | F4:  proto.Int32(1), | 
|  | F5:  proto.Int32(1), | 
|  | F6:  proto.Int32(1), | 
|  | F7:  proto.Int32(1), | 
|  | F8:  proto.Int32(1), | 
|  | F9:  proto.Int32(1), | 
|  | F10: proto.Int32(1), | 
|  | F11: proto.Int32(1), | 
|  | F12: proto.Int32(1), | 
|  | F13: proto.Int32(1), | 
|  | F14: proto.Int32(1), | 
|  | F15: proto.Int32(1), | 
|  | F16: proto.Int32(1), | 
|  | } | 
|  | w, err := proto.Marshal(m) | 
|  | if err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | b.Run("Wire/Marshal", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | for pb.Next() { | 
|  | if _, err := proto.Marshal(m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Unmarshal", func(b *testing.B) { | 
|  | opts := proto.UnmarshalOptions{ | 
|  | Merge: true, | 
|  | } | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | m := µpb.SixteenRequired{} | 
|  | for pb.Next() { | 
|  | if err := opts.Unmarshal(w, m); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Wire/Validate", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | mt := (µpb.SixteenRequired{}).ProtoReflect().Type() | 
|  | for pb.Next() { | 
|  | _, got := impl.Validate(mt, protoiface.UnmarshalInput{ | 
|  | Buf: w, | 
|  | }) | 
|  | want := impl.ValidationValid | 
|  | if got != want { | 
|  | b.Fatalf("Validate = %v, want %v", got, want) | 
|  | } | 
|  | } | 
|  | }) | 
|  | }) | 
|  | b.Run("Clone", func(b *testing.B) { | 
|  | b.RunParallel(func(pb *testing.PB) { | 
|  | for pb.Next() { | 
|  | proto.Clone(m) | 
|  | } | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | func BenchmarkExtension(b *testing.B) { | 
|  | b.Run("Has/None", func(b *testing.B) { | 
|  | m := &testpb.TestAllExtensions{} | 
|  | for i := 0; i < b.N; i++ { | 
|  | proto.HasExtension(m, testpb.E_OptionalNestedMessage) | 
|  | } | 
|  | }) | 
|  | b.Run("Has/Set", func(b *testing.B) { | 
|  | m := &testpb.TestAllExtensions{} | 
|  | ext := &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(-32)} | 
|  | proto.SetExtension(m, testpb.E_OptionalNestedMessage, ext) | 
|  | for i := 0; i < b.N; i++ { | 
|  | proto.HasExtension(m, testpb.E_OptionalNestedMessage) | 
|  | } | 
|  | }) | 
|  | b.Run("Get/None", func(b *testing.B) { | 
|  | m := &testpb.TestAllExtensions{} | 
|  | for i := 0; i < b.N; i++ { | 
|  | proto.GetExtension(m, testpb.E_OptionalNestedMessage) | 
|  | } | 
|  | }) | 
|  | b.Run("Get/Set", func(b *testing.B) { | 
|  | m := &testpb.TestAllExtensions{} | 
|  | ext := &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(-32)} | 
|  | proto.SetExtension(m, testpb.E_OptionalNestedMessage, ext) | 
|  | for i := 0; i < b.N; i++ { | 
|  | proto.GetExtension(m, testpb.E_OptionalNestedMessage) | 
|  | } | 
|  | }) | 
|  | b.Run("Set", func(b *testing.B) { | 
|  | m := &testpb.TestAllExtensions{} | 
|  | ext := &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(-32)} | 
|  | for i := 0; i < b.N; i++ { | 
|  | proto.SetExtension(m, testpb.E_OptionalNestedMessage, ext) | 
|  | } | 
|  | }) | 
|  | } |