| // 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) |
| } |
| } |
| } |