1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package encoding_test 6 7import ( 8 "fmt" 9 "testing" 10 11 "google.golang.org/protobuf/encoding/protojson" 12 "google.golang.org/protobuf/encoding/prototext" 13 "google.golang.org/protobuf/reflect/protoreflect" 14 15 tpb "google.golang.org/protobuf/internal/testprotos/test" 16) 17 18// The results of these microbenchmarks are unlikely to correspond well 19// to real world performance. They are mainly useful as a quick check to 20// detect unexpected regressions and for profiling specific cases. 21 22const maxRecurseLevel = 3 23 24func makeProto() *tpb.TestAllTypes { 25 m := &tpb.TestAllTypes{} 26 fillMessage(m.ProtoReflect(), 0) 27 return m 28} 29 30func fillMessage(m protoreflect.Message, level int) { 31 if level > maxRecurseLevel { 32 return 33 } 34 35 fieldDescs := m.Descriptor().Fields() 36 for i := 0; i < fieldDescs.Len(); i++ { 37 fd := fieldDescs.Get(i) 38 switch { 39 case fd.IsList(): 40 setList(m.Mutable(fd).List(), fd, level) 41 case fd.IsMap(): 42 setMap(m.Mutable(fd).Map(), fd, level) 43 default: 44 setScalarField(m, fd, level) 45 } 46 } 47} 48 49func setScalarField(m protoreflect.Message, fd protoreflect.FieldDescriptor, level int) { 50 switch fd.Kind() { 51 case protoreflect.MessageKind, protoreflect.GroupKind: 52 val := m.NewField(fd) 53 fillMessage(val.Message(), level+1) 54 m.Set(fd, val) 55 default: 56 m.Set(fd, scalarField(fd.Kind())) 57 } 58} 59 60func scalarField(kind protoreflect.Kind) protoreflect.Value { 61 switch kind { 62 case protoreflect.BoolKind: 63 return protoreflect.ValueOfBool(true) 64 65 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 66 return protoreflect.ValueOfInt32(1 << 30) 67 68 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 69 return protoreflect.ValueOfInt64(1 << 30) 70 71 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 72 return protoreflect.ValueOfUint32(1 << 30) 73 74 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 75 return protoreflect.ValueOfUint64(1 << 30) 76 77 case protoreflect.FloatKind: 78 return protoreflect.ValueOfFloat32(3.14159265) 79 80 case protoreflect.DoubleKind: 81 return protoreflect.ValueOfFloat64(3.14159265) 82 83 case protoreflect.BytesKind: 84 return protoreflect.ValueOfBytes([]byte("hello world")) 85 86 case protoreflect.StringKind: 87 return protoreflect.ValueOfString("hello world") 88 89 case protoreflect.EnumKind: 90 return protoreflect.ValueOfEnum(42) 91 } 92 93 panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind)) 94} 95 96func setList(list protoreflect.List, fd protoreflect.FieldDescriptor, level int) { 97 switch fd.Kind() { 98 case protoreflect.MessageKind, protoreflect.GroupKind: 99 for i := 0; i < 10; i++ { 100 val := list.NewElement() 101 fillMessage(val.Message(), level+1) 102 list.Append(val) 103 } 104 default: 105 for i := 0; i < 100; i++ { 106 list.Append(scalarField(fd.Kind())) 107 } 108 } 109} 110 111func setMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor, level int) { 112 fields := fd.Message().Fields() 113 keyDesc := fields.ByNumber(1) 114 valDesc := fields.ByNumber(2) 115 116 pkey := scalarField(keyDesc.Kind()) 117 switch kind := valDesc.Kind(); kind { 118 case protoreflect.MessageKind, protoreflect.GroupKind: 119 val := mmap.NewValue() 120 fillMessage(val.Message(), level+1) 121 mmap.Set(pkey.MapKey(), val) 122 default: 123 mmap.Set(pkey.MapKey(), scalarField(kind)) 124 } 125} 126 127func BenchmarkTextEncode(b *testing.B) { 128 m := makeProto() 129 for i := 0; i < b.N; i++ { 130 _, err := prototext.MarshalOptions{Indent: " "}.Marshal(m) 131 if err != nil { 132 b.Fatal(err) 133 } 134 } 135} 136 137func BenchmarkTextDecode(b *testing.B) { 138 m := makeProto() 139 in, err := prototext.MarshalOptions{Indent: " "}.Marshal(m) 140 if err != nil { 141 b.Fatal(err) 142 } 143 144 for i := 0; i < b.N; i++ { 145 m := &tpb.TestAllTypes{} 146 if err := prototext.Unmarshal(in, m); err != nil { 147 b.Fatal(err) 148 } 149 } 150} 151 152func BenchmarkJSONEncode(b *testing.B) { 153 m := makeProto() 154 for i := 0; i < b.N; i++ { 155 _, err := protojson.MarshalOptions{Indent: " "}.Marshal(m) 156 if err != nil { 157 b.Fatal(err) 158 } 159 } 160} 161 162func BenchmarkJSONDecode(b *testing.B) { 163 m := makeProto() 164 out, err := protojson.MarshalOptions{Indent: " "}.Marshal(m) 165 if err != nil { 166 b.Fatal(err) 167 } 168 169 for i := 0; i < b.N; i++ { 170 m := &tpb.TestAllTypes{} 171 if err := protojson.Unmarshal(out, m); err != nil { 172 b.Fatal(err) 173 } 174 } 175} 176