blob: 0341b19074f733cd37291fcbf62f96bc816eeb4d [file] [log] [blame]
Herbie Ong8eba9ee2019-04-15 15:29:50 -07001// 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 "flag"
9 "fmt"
10 "testing"
11
12 jsonpbV1 "github.com/golang/protobuf/jsonpb"
13 protoV1 "github.com/golang/protobuf/proto"
Damien Neile89e6242019-05-13 23:55:40 -070014 "google.golang.org/protobuf/encoding/jsonpb"
15 "google.golang.org/protobuf/encoding/textpb"
16 pref "google.golang.org/protobuf/reflect/protoreflect"
Herbie Ong8eba9ee2019-04-15 15:29:50 -070017
Damien Neile89e6242019-05-13 23:55:40 -070018 tpb "google.golang.org/protobuf/internal/testprotos/test"
Herbie Ong8eba9ee2019-04-15 15:29:50 -070019)
20
21// The results of these microbenchmarks are unlikely to correspond well
22// to real world peformance. They are mainly useful as a quick check to
23// detect unexpected regressions and for profiling specific cases.
24
25var benchV1 = flag.Bool("v1", false, "benchmark the v1 implementation")
26
27const (
28 boolValue = true
29 intValue = 1 << 30
30 floatValue = 3.14159265
31 strValue = "hello world"
32
33 maxRecurseLevel = 3
34)
35
36func makeProto() *tpb.TestAllTypes {
37 m := &tpb.TestAllTypes{}
38 fillMessage(m.ProtoReflect(), 0)
39 return m
40}
41
42func fillMessage(m pref.Message, level int) {
43 if level > maxRecurseLevel {
44 return
45 }
46
47 knownFields := m.KnownFields()
Joe Tsai0fc49f82019-05-01 12:29:25 -070048 fieldDescs := m.Descriptor().Fields()
Herbie Ong8eba9ee2019-04-15 15:29:50 -070049 for i := 0; i < fieldDescs.Len(); i++ {
50 fd := fieldDescs.Get(i)
51 num := fd.Number()
Joe Tsaiac31a352019-05-13 14:32:56 -070052 switch {
53 case fd.IsList():
54 setList(knownFields.Get(num).List(), fd, level)
55 case fd.IsMap():
56 setMap(knownFields.Get(num).Map(), fd, level)
57 default:
Herbie Ong8eba9ee2019-04-15 15:29:50 -070058 setScalarField(knownFields, fd, level)
59 }
60 }
61}
62
63func setScalarField(knownFields pref.KnownFields, fd pref.FieldDescriptor, level int) {
64 num := fd.Number()
65 switch fd.Kind() {
66 case pref.MessageKind, pref.GroupKind:
67 m := knownFields.NewMessage(num)
68 fillMessage(m, level+1)
69 knownFields.Set(num, pref.ValueOf(m))
70 default:
71 knownFields.Set(num, scalarField(fd.Kind()))
72 }
73}
74
75func scalarField(kind pref.Kind) pref.Value {
76 switch kind {
77 case pref.BoolKind:
78 return pref.ValueOf(boolValue)
79
80 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
81 return pref.ValueOf(int32(intValue))
82
83 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
84 return pref.ValueOf(int64(intValue))
85
86 case pref.Uint32Kind, pref.Fixed32Kind:
87 return pref.ValueOf(uint32(intValue))
88
89 case pref.Uint64Kind, pref.Fixed64Kind:
90 return pref.ValueOf(uint64(intValue))
91
92 case pref.FloatKind:
93 return pref.ValueOf(float32(floatValue))
94
95 case pref.DoubleKind:
96 return pref.ValueOf(float64(floatValue))
97
98 case pref.BytesKind:
99 return pref.ValueOf([]byte(strValue))
100
101 case pref.StringKind:
102 return pref.ValueOf(strValue)
103
104 case pref.EnumKind:
105 return pref.ValueOf(pref.EnumNumber(42))
106 }
107
108 panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind))
109}
110
111func setList(list pref.List, fd pref.FieldDescriptor, level int) {
112 switch fd.Kind() {
113 case pref.MessageKind, pref.GroupKind:
114 for i := 0; i < 10; i++ {
115 m := list.NewMessage()
116 fillMessage(m, level+1)
117 list.Append(pref.ValueOf(m))
118 }
119 default:
120 for i := 0; i < 100; i++ {
121 list.Append(scalarField(fd.Kind()))
122 }
123 }
124}
125
126func setMap(mmap pref.Map, fd pref.FieldDescriptor, level int) {
Joe Tsaid24bc722019-04-15 23:39:09 -0700127 fields := fd.Message().Fields()
Herbie Ong8eba9ee2019-04-15 15:29:50 -0700128 keyDesc := fields.ByNumber(1)
129 valDesc := fields.ByNumber(2)
130
131 pkey := scalarField(keyDesc.Kind())
132 switch kind := valDesc.Kind(); kind {
133 case pref.MessageKind, pref.GroupKind:
134 m := mmap.NewMessage()
135 fillMessage(m, level+1)
136 mmap.Set(pkey.MapKey(), pref.ValueOf(m))
137 default:
138 mmap.Set(pkey.MapKey(), scalarField(kind))
139 }
140}
141
142func BenchmarkTextEncode(b *testing.B) {
143 m := makeProto()
144 for i := 0; i < b.N; i++ {
145 if *benchV1 {
146 protoV1.MarshalTextString(m)
147 } else {
148 _, err := textpb.MarshalOptions{Indent: " "}.Marshal(m)
149 if err != nil {
150 b.Fatal(err)
151 }
152 }
153 }
154}
155
156func BenchmarkTextDecode(b *testing.B) {
157 m := makeProto()
158 in, err := textpb.MarshalOptions{Indent: " "}.Marshal(m)
159 if err != nil {
160 b.Fatal(err)
161 }
162
163 for i := 0; i < b.N; i++ {
164 m := &tpb.TestAllTypes{}
165 var err error
166 if *benchV1 {
167 err = protoV1.UnmarshalText(string(in), m)
168 } else {
169 err = textpb.Unmarshal(m, in)
170 }
171 if err != nil {
172 b.Fatal(err)
173 }
174 }
175}
176
177func BenchmarkJSONEncode(b *testing.B) {
178 m := makeProto()
179 for i := 0; i < b.N; i++ {
180 var err error
181 if *benchV1 {
182 jsm := &jsonpbV1.Marshaler{Indent: " "}
183 _, err = jsm.MarshalToString(m)
184 } else {
185 _, err = jsonpb.MarshalOptions{Indent: " "}.Marshal(m)
186 }
187 if err != nil {
188 b.Fatal(err)
189 }
190 }
191}
192
193func BenchmarkJSONDecode(b *testing.B) {
194 m := makeProto()
195 out, err := jsonpb.MarshalOptions{Indent: " "}.Marshal(m)
196 if err != nil {
197 b.Fatal(err)
198 }
199
200 for i := 0; i < b.N; i++ {
201 m := &tpb.TestAllTypes{}
202 var err error
203 if *benchV1 {
204 err = jsonpbV1.UnmarshalString(string(out), m)
205 } else {
206 err = jsonpb.Unmarshal(m, out)
207 }
208 if err != nil {
209 b.Fatal(err)
210 }
211 }
212}