1
2
3
4
5 package bench_test
6
7 import (
8 "flag"
9 "fmt"
10 "io/ioutil"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "strings"
15 "testing"
16 "time"
17
18 "google.golang.org/protobuf/encoding/protojson"
19 "google.golang.org/protobuf/encoding/prototext"
20 "google.golang.org/protobuf/proto"
21 "google.golang.org/protobuf/reflect/protoreflect"
22 "google.golang.org/protobuf/reflect/protoregistry"
23
24 benchpb "google.golang.org/protobuf/internal/testprotos/benchmarks"
25 _ "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message1/proto2"
26 _ "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message1/proto3"
27 _ "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message2"
28 _ "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3"
29 _ "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message4"
30 )
31
32 func BenchmarkWire(b *testing.B) {
33 bench(b, "Unmarshal", func(ds dataset, pb *testing.PB) {
34 for pb.Next() {
35 for _, p := range ds.wire {
36 m := ds.messageType.New().Interface()
37 if err := proto.Unmarshal(p, m); err != nil {
38 b.Fatal(err)
39 }
40 }
41 }
42 })
43 bench(b, "Marshal", func(ds dataset, pb *testing.PB) {
44 for pb.Next() {
45 for _, m := range ds.messages {
46 if _, err := proto.Marshal(m); err != nil {
47 b.Fatal(err)
48 }
49 }
50 }
51 })
52 bench(b, "Size", func(ds dataset, pb *testing.PB) {
53 for pb.Next() {
54 for _, m := range ds.messages {
55 proto.Size(m)
56 }
57 }
58 })
59 }
60
61 func BenchmarkText(b *testing.B) {
62 bench(b, "Unmarshal", func(ds dataset, pb *testing.PB) {
63 for pb.Next() {
64 for _, p := range ds.text {
65 m := ds.messageType.New().Interface()
66 if err := prototext.Unmarshal(p, m); err != nil {
67 b.Fatal(err)
68 }
69 }
70 }
71 })
72 bench(b, "Marshal", func(ds dataset, pb *testing.PB) {
73 for pb.Next() {
74 for _, m := range ds.messages {
75 if _, err := prototext.Marshal(m); err != nil {
76 b.Fatal(err)
77 }
78 }
79 }
80 })
81 }
82
83 func BenchmarkJSON(b *testing.B) {
84 bench(b, "Unmarshal", func(ds dataset, pb *testing.PB) {
85 for pb.Next() {
86 for _, p := range ds.json {
87 m := ds.messageType.New().Interface()
88 if err := protojson.Unmarshal(p, m); err != nil {
89 b.Fatal(err)
90 }
91 }
92 }
93 })
94 bench(b, "Marshal", func(ds dataset, pb *testing.PB) {
95 for pb.Next() {
96 for _, m := range ds.messages {
97 if _, err := protojson.Marshal(m); err != nil {
98 b.Fatal(err)
99 }
100 }
101 }
102 })
103 }
104
105 func Benchmark(b *testing.B) {
106 bench(b, "Clone", func(ds dataset, pb *testing.PB) {
107 for pb.Next() {
108 for _, src := range ds.messages {
109 proto.Clone(src)
110 }
111 }
112 })
113 }
114
115 func bench(b *testing.B, name string, f func(dataset, *testing.PB)) {
116 b.Helper()
117 b.Run(name, func(b *testing.B) {
118 for _, ds := range datasets {
119 b.Run(ds.name, func(b *testing.B) {
120 b.RunParallel(func(pb *testing.PB) {
121 f(ds, pb)
122 })
123 })
124 }
125 })
126 }
127
128 type dataset struct {
129 name string
130 messageType protoreflect.MessageType
131 messages []proto.Message
132 wire [][]byte
133 text [][]byte
134 json [][]byte
135 }
136
137 var datasets []dataset
138
139 func TestMain(m *testing.M) {
140
141
142
143
144
145
146
147
148
149 flag.Parse()
150 if v := flag.Lookup("test.bench").Value.(flag.Getter).Get(); v == "" {
151
152
153 return
154 }
155 if v := flag.Lookup("test.timeout").Value.(flag.Getter).Get().(time.Duration); v != 0 && v <= 10*time.Minute {
156
157
158
159
160
161
162
163
164
165 fmt.Fprintf(os.Stderr, "Test timeout of %v is probably too short; set -test.timeout=0.\n", v)
166 os.Exit(1)
167 }
168 out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
169 if err != nil {
170 panic(err)
171 }
172 repoRoot := strings.TrimSpace(string(out))
173 dataDir := filepath.Join(repoRoot, ".cache", "benchdata")
174 filepath.Walk(dataDir, func(path string, _ os.FileInfo, _ error) error {
175 if filepath.Ext(path) != ".pb" {
176 return nil
177 }
178 raw, err := ioutil.ReadFile(path)
179 if err != nil {
180 panic(err)
181 }
182 dspb := &benchpb.BenchmarkDataset{}
183 if err := proto.Unmarshal(raw, dspb); err != nil {
184 panic(err)
185 }
186 mt, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(dspb.MessageName))
187 if err != nil {
188 panic(err)
189 }
190 ds := dataset{
191 name: dspb.Name,
192 messageType: mt,
193 wire: dspb.Payload,
194 }
195 for _, payload := range dspb.Payload {
196 m := mt.New().Interface()
197 if err := proto.Unmarshal(payload, m); err != nil {
198 panic(err)
199 }
200 ds.messages = append(ds.messages, m)
201 b, err := prototext.Marshal(m)
202 if err != nil {
203 panic(err)
204 }
205 ds.text = append(ds.text, b)
206 b, err = protojson.Marshal(m)
207 if err != nil {
208 panic(err)
209 }
210 ds.json = append(ds.json, b)
211 }
212 datasets = append(datasets, ds)
213 return nil
214 })
215 os.Exit(m.Run())
216 }
217
View as plain text