// 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 ( "fmt" "testing" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/prototext" "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 performance. They are mainly useful as a quick check to // detect unexpected regressions and for profiling specific cases. const maxRecurseLevel = 3 func makeProto() *tpb.TestAllTypes { m := &tpb.TestAllTypes{} fillMessage(m.ProtoReflect(), 0) return m } func fillMessage(m protoreflect.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 protoreflect.Message, fd protoreflect.FieldDescriptor, level int) { switch fd.Kind() { case protoreflect.MessageKind, protoreflect.GroupKind: val := m.NewField(fd) fillMessage(val.Message(), level+1) m.Set(fd, val) default: m.Set(fd, scalarField(fd.Kind())) } } func scalarField(kind protoreflect.Kind) protoreflect.Value { switch kind { case protoreflect.BoolKind: return protoreflect.ValueOfBool(true) case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: return protoreflect.ValueOfInt32(1 << 30) case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: return protoreflect.ValueOfInt64(1 << 30) case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: return protoreflect.ValueOfUint32(1 << 30) case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: return protoreflect.ValueOfUint64(1 << 30) case protoreflect.FloatKind: return protoreflect.ValueOfFloat32(3.14159265) case protoreflect.DoubleKind: return protoreflect.ValueOfFloat64(3.14159265) case protoreflect.BytesKind: return protoreflect.ValueOfBytes([]byte("hello world")) case protoreflect.StringKind: return protoreflect.ValueOfString("hello world") case protoreflect.EnumKind: return protoreflect.ValueOfEnum(42) } panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind)) } func setList(list protoreflect.List, fd protoreflect.FieldDescriptor, level int) { switch fd.Kind() { case protoreflect.MessageKind, protoreflect.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 protoreflect.Map, fd protoreflect.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 protoreflect.MessageKind, protoreflect.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++ { _, 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{} if err := prototext.Unmarshal(in, m); err != nil { b.Fatal(err) } } } func BenchmarkJSONEncode(b *testing.B) { m := makeProto() for i := 0; i < b.N; i++ { _, 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{} if err := protojson.Unmarshal(out, m); err != nil { b.Fatal(err) } } }