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