blob: ca866c012fd009e3e76b063d73022a7f63286764 [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"
14 "github.com/golang/protobuf/v2/encoding/jsonpb"
15 "github.com/golang/protobuf/v2/encoding/textpb"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
17
18 tpb "github.com/golang/protobuf/v2/internal/testprotos/test"
19)
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()
48 fieldDescs := m.Type().Fields()
49 for i := 0; i < fieldDescs.Len(); i++ {
50 fd := fieldDescs.Get(i)
51 num := fd.Number()
52 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
53 if !fd.IsMap() {
54 setList(knownFields.Get(num).List(), fd, level)
55 } else {
56 setMap(knownFields.Get(num).Map(), fd, level)
57 }
58 } else {
59 setScalarField(knownFields, fd, level)
60 }
61 }
62}
63
64func setScalarField(knownFields pref.KnownFields, fd pref.FieldDescriptor, level int) {
65 num := fd.Number()
66 switch fd.Kind() {
67 case pref.MessageKind, pref.GroupKind:
68 m := knownFields.NewMessage(num)
69 fillMessage(m, level+1)
70 knownFields.Set(num, pref.ValueOf(m))
71 default:
72 knownFields.Set(num, scalarField(fd.Kind()))
73 }
74}
75
76func scalarField(kind pref.Kind) pref.Value {
77 switch kind {
78 case pref.BoolKind:
79 return pref.ValueOf(boolValue)
80
81 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
82 return pref.ValueOf(int32(intValue))
83
84 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
85 return pref.ValueOf(int64(intValue))
86
87 case pref.Uint32Kind, pref.Fixed32Kind:
88 return pref.ValueOf(uint32(intValue))
89
90 case pref.Uint64Kind, pref.Fixed64Kind:
91 return pref.ValueOf(uint64(intValue))
92
93 case pref.FloatKind:
94 return pref.ValueOf(float32(floatValue))
95
96 case pref.DoubleKind:
97 return pref.ValueOf(float64(floatValue))
98
99 case pref.BytesKind:
100 return pref.ValueOf([]byte(strValue))
101
102 case pref.StringKind:
103 return pref.ValueOf(strValue)
104
105 case pref.EnumKind:
106 return pref.ValueOf(pref.EnumNumber(42))
107 }
108
109 panic(fmt.Sprintf("FieldDescriptor.Kind %v is not valid", kind))
110}
111
112func setList(list pref.List, fd pref.FieldDescriptor, level int) {
113 switch fd.Kind() {
114 case pref.MessageKind, pref.GroupKind:
115 for i := 0; i < 10; i++ {
116 m := list.NewMessage()
117 fillMessage(m, level+1)
118 list.Append(pref.ValueOf(m))
119 }
120 default:
121 for i := 0; i < 100; i++ {
122 list.Append(scalarField(fd.Kind()))
123 }
124 }
125}
126
127func setMap(mmap pref.Map, fd pref.FieldDescriptor, level int) {
128 fields := fd.MessageType().Fields()
129 keyDesc := fields.ByNumber(1)
130 valDesc := fields.ByNumber(2)
131
132 pkey := scalarField(keyDesc.Kind())
133 switch kind := valDesc.Kind(); kind {
134 case pref.MessageKind, pref.GroupKind:
135 m := mmap.NewMessage()
136 fillMessage(m, level+1)
137 mmap.Set(pkey.MapKey(), pref.ValueOf(m))
138 default:
139 mmap.Set(pkey.MapKey(), scalarField(kind))
140 }
141}
142
143func BenchmarkTextEncode(b *testing.B) {
144 m := makeProto()
145 for i := 0; i < b.N; i++ {
146 if *benchV1 {
147 protoV1.MarshalTextString(m)
148 } else {
149 _, err := textpb.MarshalOptions{Indent: " "}.Marshal(m)
150 if err != nil {
151 b.Fatal(err)
152 }
153 }
154 }
155}
156
157func BenchmarkTextDecode(b *testing.B) {
158 m := makeProto()
159 in, err := textpb.MarshalOptions{Indent: " "}.Marshal(m)
160 if err != nil {
161 b.Fatal(err)
162 }
163
164 for i := 0; i < b.N; i++ {
165 m := &tpb.TestAllTypes{}
166 var err error
167 if *benchV1 {
168 err = protoV1.UnmarshalText(string(in), m)
169 } else {
170 err = textpb.Unmarshal(m, in)
171 }
172 if err != nil {
173 b.Fatal(err)
174 }
175 }
176}
177
178func BenchmarkJSONEncode(b *testing.B) {
179 m := makeProto()
180 for i := 0; i < b.N; i++ {
181 var err error
182 if *benchV1 {
183 jsm := &jsonpbV1.Marshaler{Indent: " "}
184 _, err = jsm.MarshalToString(m)
185 } else {
186 _, err = jsonpb.MarshalOptions{Indent: " "}.Marshal(m)
187 }
188 if err != nil {
189 b.Fatal(err)
190 }
191 }
192}
193
194func BenchmarkJSONDecode(b *testing.B) {
195 m := makeProto()
196 out, err := jsonpb.MarshalOptions{Indent: " "}.Marshal(m)
197 if err != nil {
198 b.Fatal(err)
199 }
200
201 for i := 0; i < b.N; i++ {
202 m := &tpb.TestAllTypes{}
203 var err error
204 if *benchV1 {
205 err = jsonpbV1.UnmarshalString(string(out), m)
206 } else {
207 err = jsonpb.Unmarshal(m, out)
208 }
209 if err != nil {
210 b.Fatal(err)
211 }
212 }
213}