1
2 #include <benchmark/benchmark.h>
3 #include <string.h>
4
5 #include "absl/container/flat_hash_set.h"
6 #include "benchmarks/descriptor.pb.h"
7 #include "benchmarks/descriptor.upb.h"
8 #include "benchmarks/descriptor.upbdefs.h"
9 #include "benchmarks/descriptor_sv.pb.h"
10 #include "google/ads/googleads/v5/services/google_ads_service.upbdefs.h"
11 #include "google/protobuf/descriptor.pb.h"
12 #include "upb/def.hpp"
13
14 upb_strview descriptor = benchmarks_descriptor_proto_upbdefinit.descriptor;
15 namespace protobuf = ::google::protobuf;
16
17 /* A buffer big enough to parse descriptor.proto without going to heap. */
18 char buf[65535];
19
CollectFileDescriptors(const upb_def_init * file,std::vector<upb_strview> & serialized_files,absl::flat_hash_set<const upb_def_init * > & seen)20 void CollectFileDescriptors(const upb_def_init* file,
21 std::vector<upb_strview>& serialized_files,
22 absl::flat_hash_set<const upb_def_init*>& seen) {
23 if (!seen.insert(file).second) return;
24 for (upb_def_init **deps = file->deps; *deps; deps++) {
25 CollectFileDescriptors(*deps, serialized_files, seen);
26 }
27 serialized_files.push_back(file->descriptor);
28 }
29
BM_ArenaOneAlloc(benchmark::State & state)30 static void BM_ArenaOneAlloc(benchmark::State& state) {
31 for (auto _ : state) {
32 upb_arena* arena = upb_arena_new();
33 upb_arena_malloc(arena, 1);
34 upb_arena_free(arena);
35 }
36 }
37 BENCHMARK(BM_ArenaOneAlloc);
38
BM_ArenaInitialBlockOneAlloc(benchmark::State & state)39 static void BM_ArenaInitialBlockOneAlloc(benchmark::State& state) {
40 for (auto _ : state) {
41 upb_arena* arena = upb_arena_init(buf, sizeof(buf), NULL);
42 upb_arena_malloc(arena, 1);
43 upb_arena_free(arena);
44 }
45 }
46 BENCHMARK(BM_ArenaInitialBlockOneAlloc);
47
BM_LoadDescriptor_Upb(benchmark::State & state)48 static void BM_LoadDescriptor_Upb(benchmark::State& state) {
49 size_t bytes_per_iter = 0;
50 for (auto _ : state) {
51 upb::SymbolTable symtab;
52 upb_benchmark_DescriptorProto_getmsgdef(symtab.ptr());
53 bytes_per_iter = _upb_symtab_bytesloaded(symtab.ptr());
54 }
55 state.SetBytesProcessed(state.iterations() * bytes_per_iter);
56 }
57 BENCHMARK(BM_LoadDescriptor_Upb);
58
BM_LoadAdsDescriptor_Upb(benchmark::State & state)59 static void BM_LoadAdsDescriptor_Upb(benchmark::State& state) {
60 size_t bytes_per_iter = 0;
61 for (auto _ : state) {
62 upb::SymbolTable symtab;
63 google_ads_googleads_v5_services_SearchGoogleAdsRequest_getmsgdef(
64 symtab.ptr());
65 bytes_per_iter = _upb_symtab_bytesloaded(symtab.ptr());
66 }
67 state.SetBytesProcessed(state.iterations() * bytes_per_iter);
68 }
69 BENCHMARK(BM_LoadAdsDescriptor_Upb);
70
BM_LoadDescriptor_Proto2(benchmark::State & state)71 static void BM_LoadDescriptor_Proto2(benchmark::State& state) {
72 for (auto _ : state) {
73 protobuf::Arena arena;
74 protobuf::StringPiece input(descriptor.data,descriptor.size);
75 auto proto = protobuf::Arena::CreateMessage<protobuf::FileDescriptorProto>(
76 &arena);
77 protobuf::DescriptorPool pool;
78 bool ok = proto->ParseFrom<protobuf::MessageLite::kMergePartial>(input) &&
79 pool.BuildFile(*proto) != nullptr;
80 if (!ok) {
81 printf("Failed to add file.\n");
82 exit(1);
83 }
84 }
85 state.SetBytesProcessed(state.iterations() * descriptor.size);
86 }
87 BENCHMARK(BM_LoadDescriptor_Proto2);
88
BM_LoadAdsDescriptor_Proto2(benchmark::State & state)89 static void BM_LoadAdsDescriptor_Proto2(benchmark::State& state) {
90 extern upb_def_init google_ads_googleads_v5_services_google_ads_service_proto_upbdefinit;
91 std::vector<upb_strview> serialized_files;
92 absl::flat_hash_set<const upb_def_init*> seen_files;
93 CollectFileDescriptors(
94 &google_ads_googleads_v5_services_google_ads_service_proto_upbdefinit,
95 serialized_files, seen_files);
96 size_t bytes_per_iter = 0;
97 for (auto _ : state) {
98 bytes_per_iter = 0;
99 protobuf::Arena arena;
100 protobuf::DescriptorPool pool;
101 for (auto file : serialized_files) {
102 protobuf::StringPiece input(file.data, file.size);
103 auto proto = protobuf::Arena::CreateMessage<protobuf::FileDescriptorProto>(
104 &arena);
105 bool ok = proto->ParseFrom<protobuf::MessageLite::kMergePartial>(input) &&
106 pool.BuildFile(*proto) != nullptr;
107 if (!ok) {
108 printf("Failed to add file.\n");
109 exit(1);
110 }
111 bytes_per_iter += input.size();
112 }
113 }
114 state.SetBytesProcessed(state.iterations() * bytes_per_iter);
115 }
116 BENCHMARK(BM_LoadAdsDescriptor_Proto2);
117
118 enum CopyStrings {
119 Copy,
120 Alias,
121 };
122
123 enum ArenaMode {
124 NoArena,
125 UseArena,
126 InitBlock,
127 };
128
129 template <ArenaMode AMode, CopyStrings Copy>
BM_Parse_Upb_FileDesc(benchmark::State & state)130 static void BM_Parse_Upb_FileDesc(benchmark::State& state) {
131 size_t bytes = 0;
132 for (auto _ : state) {
133 upb_arena *arena;
134 if (AMode == InitBlock) {
135 arena = upb_arena_init(buf, sizeof(buf), NULL);
136 } else {
137 arena = upb_arena_new();
138 }
139 upb_benchmark_FileDescriptorProto* set =
140 upb_benchmark_FileDescriptorProto_parse_ex(
141 descriptor.data, descriptor.size, arena,
142 Copy == Alias ? UPB_DECODE_ALIAS : 0);
143 if (!set) {
144 printf("Failed to parse.\n");
145 exit(1);
146 }
147 bytes += descriptor.size;
148 upb_arena_free(arena);
149 }
150 state.SetBytesProcessed(state.iterations() * descriptor.size);
151 }
152 BENCHMARK_TEMPLATE(BM_Parse_Upb_FileDesc, UseArena, Copy);
153 BENCHMARK_TEMPLATE(BM_Parse_Upb_FileDesc, UseArena, Alias);
154 BENCHMARK_TEMPLATE(BM_Parse_Upb_FileDesc, InitBlock, Copy);
155 BENCHMARK_TEMPLATE(BM_Parse_Upb_FileDesc, InitBlock, Alias);
156
157 template <ArenaMode AMode, class P>
158 struct Proto2Factory;
159
160 template<class P>
161 struct Proto2Factory<NoArena, P> {
162 public:
GetProtoProto2Factory163 P* GetProto() { return &proto_; }
164
165 private:
166 P proto_;
167 };
168
169 template <class P>
170 struct Proto2Factory<UseArena, P> {
171 public:
GetProtoProto2Factory172 P* GetProto() { return protobuf::Arena::CreateMessage<P>(&arena_); }
173
174 private:
175 protobuf::Arena arena_;
176 };
177
178 template <class P>
179 struct Proto2Factory<InitBlock, P> {
180 public:
Proto2FactoryProto2Factory181 Proto2Factory() : arena_(GetOptions()) {}
GetProtoProto2Factory182 P* GetProto() { return protobuf::Arena::CreateMessage<P>(&arena_); }
183
184 private:
GetOptionsProto2Factory185 protobuf::ArenaOptions GetOptions() {
186 protobuf::ArenaOptions opts;
187 opts.initial_block = buf;
188 opts.initial_block_size = sizeof(buf);
189 return opts;
190 }
191
192 protobuf::Arena arena_;
193 };
194
195 using FileDesc = ::upb_benchmark::FileDescriptorProto;
196 using FileDescSV = ::upb_benchmark::sv::FileDescriptorProto;
197
198 template <class P, ArenaMode AMode, CopyStrings kCopy>
BM_Parse_Proto2(benchmark::State & state)199 void BM_Parse_Proto2(benchmark::State& state) {
200 size_t bytes = 0;
201 constexpr protobuf::MessageLite::ParseFlags kParseFlags =
202 kCopy == Copy
203 ? protobuf::MessageLite::ParseFlags::kMergePartial
204 : protobuf::MessageLite::ParseFlags::kMergePartialWithAliasing;
205 for (auto _ : state) {
206 Proto2Factory<AMode, P> proto_factory;
207 auto proto = proto_factory.GetProto();
208 protobuf::StringPiece input(descriptor.data,descriptor.size);
209 bool ok = proto->template ParseFrom<kParseFlags>(input);
210 if (!ok) {
211 printf("Failed to parse.\n");
212 exit(1);
213 }
214 bytes += descriptor.size;
215 }
216 state.SetBytesProcessed(state.iterations() * descriptor.size);
217 }
218 BENCHMARK_TEMPLATE(BM_Parse_Proto2, FileDesc, NoArena, Copy);
219 BENCHMARK_TEMPLATE(BM_Parse_Proto2, FileDesc, UseArena, Copy);
220 BENCHMARK_TEMPLATE(BM_Parse_Proto2, FileDesc, InitBlock, Copy);
221 BENCHMARK_TEMPLATE(BM_Parse_Proto2, FileDescSV, InitBlock, Alias);
222
BM_SerializeDescriptor_Proto2(benchmark::State & state)223 static void BM_SerializeDescriptor_Proto2(benchmark::State& state) {
224 size_t bytes = 0;
225 upb_benchmark::FileDescriptorProto proto;
226 proto.ParseFromArray(descriptor.data, descriptor.size);
227 for (auto _ : state) {
228 proto.SerializePartialToArray(buf, sizeof(buf));
229 bytes += descriptor.size;
230 }
231 state.SetBytesProcessed(state.iterations() * descriptor.size);
232 }
233 BENCHMARK(BM_SerializeDescriptor_Proto2);
234
BM_SerializeDescriptor_Upb(benchmark::State & state)235 static void BM_SerializeDescriptor_Upb(benchmark::State& state) {
236 int64_t total = 0;
237 upb_arena* arena = upb_arena_new();
238 upb_benchmark_FileDescriptorProto* set =
239 upb_benchmark_FileDescriptorProto_parse(descriptor.data, descriptor.size,
240 arena);
241 if (!set) {
242 printf("Failed to parse.\n");
243 exit(1);
244 }
245 for (auto _ : state) {
246 upb_arena* enc_arena = upb_arena_init(buf, sizeof(buf), NULL);
247 size_t size;
248 char* data =
249 upb_benchmark_FileDescriptorProto_serialize(set, enc_arena, &size);
250 if (!data) {
251 printf("Failed to serialize.\n");
252 exit(1);
253 }
254 total += size;
255 }
256 state.SetBytesProcessed(total);
257 }
258 BENCHMARK(BM_SerializeDescriptor_Upb);
259