// Copyright 2018 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 encoding_test import ( "flag" "fmt" "testing" jsonpbV1 "github.com/golang/protobuf/jsonpb" protoV1 "github.com/golang/protobuf/proto" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/prototext" pref "google.golang.org/protobuf/reflect/protoreflect" tpb "google.golang.org/protobuf/internal/testprotos/test" ) // 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") const maxRecurseLevel = 3 func makeProto() *tpb.TestAllTypes { m := &tpb.TestAllTypes{} fillMessage(m.ProtoReflect(), 0) return m } func fillMessage(m pref.Message, level int) { if level > maxRecurseLevel { return } fieldDescs := m.Descriptor().Fields() for i := 0; i < fieldDescs.Len(); i++ { fd := fieldDescs.Get(i) switch { case fd.IsList(): setList(m.Mutable(fd).List(), fd, level) case fd.IsMap(): setMap(m.Mutable(fd).Map(), fd, level) default: setScalarField(m, fd, level) } } } func setScalarField(m pref.Message, fd pref.FieldDescriptor, level int) { switch fd.Kind() { case pref.MessageKind, pref.GroupKind: val := m.NewField(fd) fillMessage(val.Message(), level+1) m.Set(fd, val) default: m.Set(fd, scalarField(fd.Kind())) } } func scalarField(kind pref.Kind) pref.Value { switch kind { case pref.BoolKind: return pref.ValueOfBool(true) case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind: return pref.ValueOfInt32(1 << 30) case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind: return pref.ValueOfInt64(1 << 30) case pref.Uint32Kind, pref.Fixed32Kind: return pref.ValueOfUint32(1 << 30) case pref.Uint64Kind, pref.Fixed64Kind: return pref.ValueOfUint64(1 << 30) case pref.FloatKind: return pref.ValueOfFloat32(3.14159265) case pref.DoubleKind: return pref.ValueOfFloat64(3.14159265) case pref.BytesKind: return pref.ValueOfBytes([]byte("hello world")) case pref.StringKind: return pref.ValueOfString("hello world") case pref.EnumKind: return pref.ValueOfEnum(42) } panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind)) } func setList(list pref.List, fd pref.FieldDescriptor, level int) { switch fd.Kind() { case pref.MessageKind, pref.GroupKind: for i := 0; i < 10; i++ { val := list.NewElement() fillMessage(val.Message(), level+1) list.Append(val) } default: for i := 0; i < 100; i++ { list.Append(scalarField(fd.Kind())) } } } func setMap(mmap pref.Map, fd pref.FieldDescriptor, level int) { fields := fd.Message().Fields() keyDesc := fields.ByNumber(1) valDesc := fields.ByNumber(2) pkey := scalarField(keyDesc.Kind()) switch kind := valDesc.Kind(); kind { case pref.MessageKind, pref.GroupKind: val := mmap.NewValue() fillMessage(val.Message(), level+1) mmap.Set(pkey.MapKey(), val) default: mmap.Set(pkey.MapKey(), scalarField(kind)) } } func BenchmarkTextEncode(b *testing.B) { m := makeProto() for i := 0; i < b.N; i++ { if *benchV1 { protoV1.MarshalTextString(m) } else { _, err := prototext.MarshalOptions{Indent: " "}.Marshal(m) if err != nil { b.Fatal(err) } } } } func BenchmarkTextDecode(b *testing.B) { m := makeProto() in, err := prototext.MarshalOptions{Indent: " "}.Marshal(m) if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { m := &tpb.TestAllTypes{} var err error if *benchV1 { err = protoV1.UnmarshalText(string(in), m) } else { err = prototext.Unmarshal(in, m) } if err != nil { b.Fatal(err) } } } func BenchmarkJSONEncode(b *testing.B) { m := makeProto() for i := 0; i < b.N; i++ { var err error if *benchV1 { jsm := &jsonpbV1.Marshaler{Indent: " "} _, err = jsm.MarshalToString(m) } else { _, err = protojson.MarshalOptions{Indent: " "}.Marshal(m) } if err != nil { b.Fatal(err) } } } func BenchmarkJSONDecode(b *testing.B) { m := makeProto() out, err := protojson.MarshalOptions{Indent: " "}.Marshal(m) if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { m := &tpb.TestAllTypes{} var err error if *benchV1 { err = jsonpbV1.UnmarshalString(string(out), m) } else { err = protojson.Unmarshal(out, m) } if err != nil { b.Fatal(err) } } }