// Standard `go test -bench=.` benchmarks. Mirrors bench/bench.lua: per // fixture × per size, encode + decode, throughput + alloc. // // Two implementations per case: // * apiv2: google.golang.org/protobuf reflective Marshal/Unmarshal // — the default everyone gets out of the box. // * vtproto: planetscale/vtprotobuf generated MarshalVT/UnmarshalVT // — the fastest pure-Go path, conceptually equivalent to // our `mode=full` codegen. // // Runs are single-threaded by default (testing.B doesn't parallelize // unless RunParallel is called). package bench import ( "fmt" "testing" "google.golang.org/protobuf/proto" hellopb "github.com/tarantool-protobuf/bench/go/pb/hellopb" proto2pb "github.com/tarantool-protobuf/bench/go/pb/proto2pb" ) // --- hello.Person --------------------------------------------------------- func BenchmarkPersonEncode(b *testing.B) { for _, sz := range PersonSizes { msg := BuildPerson(sz.Target) wire, err := proto.Marshal(msg) if err != nil { b.Fatal(err) } b.Run(fmt.Sprintf("apiv2/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { if _, err := proto.Marshal(msg); err != nil { b.Fatal(err) } } }) b.Run(fmt.Sprintf("vtproto/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { if _, err := msg.MarshalVT(); err != nil { b.Fatal(err) } } }) } } func BenchmarkPersonDecode(b *testing.B) { for _, sz := range PersonSizes { msg := BuildPerson(sz.Target) wire, err := proto.Marshal(msg) if err != nil { b.Fatal(err) } b.Run(fmt.Sprintf("apiv2/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { var out hellopb.Person if err := proto.Unmarshal(wire, &out); err != nil { b.Fatal(err) } } }) b.Run(fmt.Sprintf("vtproto/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { var out hellopb.Person if err := out.UnmarshalVT(wire); err != nil { b.Fatal(err) } } }) } } // --- proto2_basic.BenchPayload -------------------------------------------- func BenchmarkProto2Encode(b *testing.B) { for _, sz := range Proto2Sizes { msg := BuildProto2(sz.Target) wire, err := proto.Marshal(msg) if err != nil { b.Fatal(err) } b.Run(fmt.Sprintf("apiv2/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { if _, err := proto.Marshal(msg); err != nil { b.Fatal(err) } } }) // vtproto's generated MarshalVT does not serialize extensions — // it skips XXX_unrecognized + protoimpl.ExtensionFields and so // drops the ext_count/ext_label payload. The benchmark would // produce shorter bytes than apiv2; skip the vtproto variant // when the fixture carries extensions so we don't publish // misleading throughput numbers. _ = msg.MarshalVT // keep symbol referenced; intentionally not benched } } func BenchmarkProto2Decode(b *testing.B) { for _, sz := range Proto2Sizes { msg := BuildProto2(sz.Target) wire, err := proto.Marshal(msg) if err != nil { b.Fatal(err) } b.Run(fmt.Sprintf("apiv2/%s", sz.Label), func(b *testing.B) { b.SetBytes(int64(len(wire))) b.ReportAllocs() for i := 0; i < b.N; i++ { var out proto2pb.BenchPayload if err := proto.Unmarshal(wire, &out); err != nil { b.Fatal(err) } } }) } }