• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /* Microbenchmarks around CHTTP2 HPACK operations */
20 
21 #include <benchmark/benchmark.h>
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/log.h>
24 #include <string.h>
25 #include <memory>
26 #include <sstream>
27 
28 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
29 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
30 #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
31 #include "src/core/lib/slice/slice_internal.h"
32 #include "src/core/lib/slice/slice_string_helpers.h"
33 #include "src/core/lib/transport/static_metadata.h"
34 #include "src/core/lib/transport/timeout_encoding.h"
35 
36 #include "test/cpp/microbenchmarks/helpers.h"
37 #include "test/cpp/util/test_config.h"
38 
39 auto& force_library_initialization = Library::get();
40 
MakeSlice(std::vector<uint8_t> bytes)41 static grpc_slice MakeSlice(std::vector<uint8_t> bytes) {
42   grpc_slice s = grpc_slice_malloc(bytes.size());
43   uint8_t* p = GRPC_SLICE_START_PTR(s);
44   for (auto b : bytes) {
45     *p++ = b;
46   }
47   return s;
48 }
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 // HPACK encoder
52 //
53 
BM_HpackEncoderInitDestroy(benchmark::State & state)54 static void BM_HpackEncoderInitDestroy(benchmark::State& state) {
55   TrackCounters track_counters;
56   grpc_core::ExecCtx exec_ctx;
57   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
58       new grpc_chttp2_hpack_compressor);
59   while (state.KeepRunning()) {
60     grpc_chttp2_hpack_compressor_init(c.get());
61     grpc_chttp2_hpack_compressor_destroy(c.get());
62     grpc_core::ExecCtx::Get()->Flush();
63   }
64 
65   track_counters.Finish(state);
66 }
67 BENCHMARK(BM_HpackEncoderInitDestroy);
68 
BM_HpackEncoderEncodeDeadline(benchmark::State & state)69 static void BM_HpackEncoderEncodeDeadline(benchmark::State& state) {
70   TrackCounters track_counters;
71   grpc_core::ExecCtx exec_ctx;
72   grpc_millis saved_now = grpc_core::ExecCtx::Get()->Now();
73 
74   grpc_metadata_batch b;
75   grpc_metadata_batch_init(&b);
76   b.deadline = saved_now + 30 * 1000;
77 
78   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
79       new grpc_chttp2_hpack_compressor);
80   grpc_chttp2_hpack_compressor_init(c.get());
81   grpc_transport_one_way_stats stats;
82   memset(&stats, 0, sizeof(stats));
83   grpc_slice_buffer outbuf;
84   grpc_slice_buffer_init(&outbuf);
85   while (state.KeepRunning()) {
86     grpc_encode_header_options hopt = {
87         static_cast<uint32_t>(state.iterations()),
88         true,
89         false,
90         static_cast<size_t>(1024),
91         &stats,
92     };
93     grpc_chttp2_encode_header(c.get(), nullptr, 0, &b, &hopt, &outbuf);
94     grpc_slice_buffer_reset_and_unref_internal(&outbuf);
95     grpc_core::ExecCtx::Get()->Flush();
96   }
97   grpc_metadata_batch_destroy(&b);
98   grpc_chttp2_hpack_compressor_destroy(c.get());
99   grpc_slice_buffer_destroy_internal(&outbuf);
100 
101   std::ostringstream label;
102   label << "framing_bytes/iter:"
103         << (static_cast<double>(stats.framing_bytes) /
104             static_cast<double>(state.iterations()))
105         << " header_bytes/iter:"
106         << (static_cast<double>(stats.header_bytes) /
107             static_cast<double>(state.iterations()));
108   track_counters.AddLabel(label.str());
109   track_counters.Finish(state);
110 }
111 BENCHMARK(BM_HpackEncoderEncodeDeadline);
112 
113 template <class Fixture>
BM_HpackEncoderEncodeHeader(benchmark::State & state)114 static void BM_HpackEncoderEncodeHeader(benchmark::State& state) {
115   TrackCounters track_counters;
116   grpc_core::ExecCtx exec_ctx;
117   static bool logged_representative_output = false;
118 
119   grpc_metadata_batch b;
120   grpc_metadata_batch_init(&b);
121   std::vector<grpc_mdelem> elems = Fixture::GetElems();
122   std::vector<grpc_linked_mdelem> storage(elems.size());
123   for (size_t i = 0; i < elems.size(); i++) {
124     GPR_ASSERT(GRPC_LOG_IF_ERROR(
125         "addmd", grpc_metadata_batch_add_tail(&b, &storage[i], elems[i])));
126   }
127 
128   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
129       new grpc_chttp2_hpack_compressor);
130   grpc_chttp2_hpack_compressor_init(c.get());
131   grpc_transport_one_way_stats stats;
132   memset(&stats, 0, sizeof(stats));
133   grpc_slice_buffer outbuf;
134   grpc_slice_buffer_init(&outbuf);
135   while (state.KeepRunning()) {
136     grpc_encode_header_options hopt = {
137         static_cast<uint32_t>(state.iterations()),
138         state.range(0) != 0,
139         Fixture::kEnableTrueBinary,
140         static_cast<size_t>(state.range(1)),
141         &stats,
142     };
143     grpc_chttp2_encode_header(c.get(), nullptr, 0, &b, &hopt, &outbuf);
144     if (!logged_representative_output && state.iterations() > 3) {
145       logged_representative_output = true;
146       for (size_t i = 0; i < outbuf.count; i++) {
147         char* s = grpc_dump_slice(outbuf.slices[i], GPR_DUMP_HEX);
148         gpr_log(GPR_DEBUG, "%" PRIdPTR ": %s", i, s);
149         gpr_free(s);
150       }
151     }
152     grpc_slice_buffer_reset_and_unref_internal(&outbuf);
153     grpc_core::ExecCtx::Get()->Flush();
154   }
155   grpc_metadata_batch_destroy(&b);
156   grpc_chttp2_hpack_compressor_destroy(c.get());
157   grpc_slice_buffer_destroy_internal(&outbuf);
158 
159   std::ostringstream label;
160   label << "framing_bytes/iter:"
161         << (static_cast<double>(stats.framing_bytes) /
162             static_cast<double>(state.iterations()))
163         << " header_bytes/iter:"
164         << (static_cast<double>(stats.header_bytes) /
165             static_cast<double>(state.iterations()));
166   track_counters.AddLabel(label.str());
167   track_counters.Finish(state);
168 }
169 
170 namespace hpack_encoder_fixtures {
171 
172 class EmptyBatch {
173  public:
174   static constexpr bool kEnableTrueBinary = false;
GetElems()175   static std::vector<grpc_mdelem> GetElems() { return {}; }
176 };
177 
178 class SingleStaticElem {
179  public:
180   static constexpr bool kEnableTrueBinary = false;
GetElems()181   static std::vector<grpc_mdelem> GetElems() {
182     return {GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE};
183   }
184 };
185 
186 class SingleInternedElem {
187  public:
188   static constexpr bool kEnableTrueBinary = false;
GetElems()189   static std::vector<grpc_mdelem> GetElems() {
190     return {grpc_mdelem_from_slices(
191         grpc_slice_intern(grpc_slice_from_static_string("abc")),
192         grpc_slice_intern(grpc_slice_from_static_string("def")))};
193   }
194 };
195 
196 template <int kLength, bool kTrueBinary>
197 class SingleInternedBinaryElem {
198  public:
199   static constexpr bool kEnableTrueBinary = kTrueBinary;
GetElems()200   static std::vector<grpc_mdelem> GetElems() {
201     grpc_slice bytes = MakeBytes();
202     std::vector<grpc_mdelem> out = {grpc_mdelem_from_slices(
203         grpc_slice_intern(grpc_slice_from_static_string("abc-bin")),
204         grpc_slice_intern(bytes))};
205     grpc_slice_unref(bytes);
206     return out;
207   }
208 
209  private:
MakeBytes()210   static grpc_slice MakeBytes() {
211     std::vector<char> v;
212     v.reserve(kLength);
213     for (int i = 0; i < kLength; i++) {
214       v.push_back(static_cast<char>(rand()));
215     }
216     return grpc_slice_from_copied_buffer(v.data(), v.size());
217   }
218 };
219 
220 class SingleInternedKeyElem {
221  public:
222   static constexpr bool kEnableTrueBinary = false;
GetElems()223   static std::vector<grpc_mdelem> GetElems() {
224     return {grpc_mdelem_from_slices(
225         grpc_slice_intern(grpc_slice_from_static_string("abc")),
226         grpc_slice_from_static_string("def"))};
227   }
228 };
229 
230 class SingleNonInternedElem {
231  public:
232   static constexpr bool kEnableTrueBinary = false;
GetElems()233   static std::vector<grpc_mdelem> GetElems() {
234     return {grpc_mdelem_from_slices(grpc_slice_from_static_string("abc"),
235                                     grpc_slice_from_static_string("def"))};
236   }
237 };
238 
239 template <int kLength, bool kTrueBinary>
240 class SingleNonInternedBinaryElem {
241  public:
242   static constexpr bool kEnableTrueBinary = kTrueBinary;
GetElems()243   static std::vector<grpc_mdelem> GetElems() {
244     return {grpc_mdelem_from_slices(grpc_slice_from_static_string("abc-bin"),
245                                     MakeBytes())};
246   }
247 
248  private:
MakeBytes()249   static grpc_slice MakeBytes() {
250     std::vector<char> v;
251     v.reserve(kLength);
252     for (int i = 0; i < kLength; i++) {
253       v.push_back(static_cast<char>(rand()));
254     }
255     return grpc_slice_from_copied_buffer(v.data(), v.size());
256   }
257 };
258 
259 class RepresentativeClientInitialMetadata {
260  public:
261   static constexpr bool kEnableTrueBinary = true;
GetElems()262   static std::vector<grpc_mdelem> GetElems() {
263     return {
264         GRPC_MDELEM_SCHEME_HTTP,
265         GRPC_MDELEM_METHOD_POST,
266         grpc_mdelem_from_slices(
267             GRPC_MDSTR_PATH,
268             grpc_slice_intern(grpc_slice_from_static_string("/foo/bar"))),
269         grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
270                                 grpc_slice_intern(grpc_slice_from_static_string(
271                                     "foo.test.google.fr:1234"))),
272         GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
273         GRPC_MDELEM_TE_TRAILERS,
274         GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
275         grpc_mdelem_from_slices(
276             GRPC_MDSTR_USER_AGENT,
277             grpc_slice_intern(grpc_slice_from_static_string(
278                 "grpc-c/3.0.0-dev (linux; chttp2; green)")))};
279   }
280 };
281 
282 // This fixture reflects how initial metadata are sent by a production client,
283 // with non-indexed :path and binary headers. The metadata here are the same as
284 // the corresponding parser benchmark below.
285 class MoreRepresentativeClientInitialMetadata {
286  public:
287   static constexpr bool kEnableTrueBinary = true;
GetElems()288   static std::vector<grpc_mdelem> GetElems() {
289     return {
290         GRPC_MDELEM_SCHEME_HTTP,
291         GRPC_MDELEM_METHOD_POST,
292         grpc_mdelem_from_slices(GRPC_MDSTR_PATH,
293                                 grpc_slice_intern(grpc_slice_from_static_string(
294                                     "/grpc.test.FooService/BarMethod"))),
295         grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
296                                 grpc_slice_intern(grpc_slice_from_static_string(
297                                     "foo.test.google.fr:1234"))),
298         grpc_mdelem_from_slices(
299             GRPC_MDSTR_GRPC_TRACE_BIN,
300             grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
301                                           "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
302                                           "\x10\x11\x12\x13\x14\x15\x16\x17\x18"
303                                           "\x19\x1a\x1b\x1c\x1d\x1e\x1f"
304                                           "\x20\x21\x22\x23\x24\x25\x26\x27\x28"
305                                           "\x29\x2a\x2b\x2c\x2d\x2e\x2f"
306                                           "\x30")),
307         grpc_mdelem_from_slices(
308             GRPC_MDSTR_GRPC_TAGS_BIN,
309             grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
310                                           "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
311                                           "\x10\x11\x12\x13")),
312         GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
313         GRPC_MDELEM_TE_TRAILERS,
314         GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
315         grpc_mdelem_from_slices(
316             GRPC_MDSTR_USER_AGENT,
317             grpc_slice_intern(grpc_slice_from_static_string(
318                 "grpc-c/3.0.0-dev (linux; chttp2; green)")))};
319   }
320 };
321 
322 class RepresentativeServerInitialMetadata {
323  public:
324   static constexpr bool kEnableTrueBinary = true;
GetElems()325   static std::vector<grpc_mdelem> GetElems() {
326     return {GRPC_MDELEM_STATUS_200,
327             GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
328             GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP};
329   }
330 };
331 
332 class RepresentativeServerTrailingMetadata {
333  public:
334   static constexpr bool kEnableTrueBinary = true;
GetElems()335   static std::vector<grpc_mdelem> GetElems() {
336     return {GRPC_MDELEM_GRPC_STATUS_0};
337   }
338 };
339 
340 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({0, 16384});
341 // test with eof (shouldn't affect anything)
342 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({1, 16384});
343 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleStaticElem)
344     ->Args({0, 16384});
345 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedKeyElem)
346     ->Args({0, 16384});
347 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedElem)
348     ->Args({0, 16384});
349 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
350                    SingleInternedBinaryElem<1, false>)
351     ->Args({0, 16384});
352 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
353                    SingleInternedBinaryElem<3, false>)
354     ->Args({0, 16384});
355 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
356                    SingleInternedBinaryElem<10, false>)
357     ->Args({0, 16384});
358 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
359                    SingleInternedBinaryElem<31, false>)
360     ->Args({0, 16384});
361 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
362                    SingleInternedBinaryElem<100, false>)
363     ->Args({0, 16384});
364 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
365                    SingleInternedBinaryElem<1, true>)
366     ->Args({0, 16384});
367 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
368                    SingleInternedBinaryElem<3, true>)
369     ->Args({0, 16384});
370 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
371                    SingleInternedBinaryElem<10, true>)
372     ->Args({0, 16384});
373 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
374                    SingleInternedBinaryElem<31, true>)
375     ->Args({0, 16384});
376 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
377                    SingleInternedBinaryElem<100, true>)
378     ->Args({0, 16384});
379 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
380     ->Args({0, 16384});
381 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
382                    SingleNonInternedBinaryElem<1, false>)
383     ->Args({0, 16384});
384 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
385                    SingleNonInternedBinaryElem<3, false>)
386     ->Args({0, 16384});
387 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
388                    SingleNonInternedBinaryElem<10, false>)
389     ->Args({0, 16384});
390 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
391                    SingleNonInternedBinaryElem<31, false>)
392     ->Args({0, 16384});
393 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
394                    SingleNonInternedBinaryElem<100, false>)
395     ->Args({0, 16384});
396 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
397                    SingleNonInternedBinaryElem<1, true>)
398     ->Args({0, 16384});
399 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
400                    SingleNonInternedBinaryElem<3, true>)
401     ->Args({0, 16384});
402 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
403                    SingleNonInternedBinaryElem<10, true>)
404     ->Args({0, 16384});
405 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
406                    SingleNonInternedBinaryElem<31, true>)
407     ->Args({0, 16384});
408 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
409                    SingleNonInternedBinaryElem<100, true>)
410     ->Args({0, 16384});
411 // test with a tiny frame size, to highlight continuation costs
412 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
413     ->Args({0, 1});
414 
415 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
416                    RepresentativeClientInitialMetadata)
417     ->Args({0, 16384});
418 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
419                    MoreRepresentativeClientInitialMetadata)
420     ->Args({0, 16384});
421 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
422                    RepresentativeServerInitialMetadata)
423     ->Args({0, 16384});
424 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
425                    RepresentativeServerTrailingMetadata)
426     ->Args({1, 16384});
427 
428 }  // namespace hpack_encoder_fixtures
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 // HPACK parser
432 //
433 
BM_HpackParserInitDestroy(benchmark::State & state)434 static void BM_HpackParserInitDestroy(benchmark::State& state) {
435   TrackCounters track_counters;
436   grpc_core::ExecCtx exec_ctx;
437   grpc_chttp2_hpack_parser p;
438   while (state.KeepRunning()) {
439     grpc_chttp2_hpack_parser_init(&p);
440     grpc_chttp2_hpack_parser_destroy(&p);
441     grpc_core::ExecCtx::Get()->Flush();
442   }
443 
444   track_counters.Finish(state);
445 }
446 BENCHMARK(BM_HpackParserInitDestroy);
447 
UnrefHeader(void * user_data,grpc_mdelem md)448 static void UnrefHeader(void* user_data, grpc_mdelem md) {
449   GRPC_MDELEM_UNREF(md);
450 }
451 
452 template <class Fixture, void (*OnHeader)(void*, grpc_mdelem)>
BM_HpackParserParseHeader(benchmark::State & state)453 static void BM_HpackParserParseHeader(benchmark::State& state) {
454   TrackCounters track_counters;
455   grpc_core::ExecCtx exec_ctx;
456   std::vector<grpc_slice> init_slices = Fixture::GetInitSlices();
457   std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
458   grpc_chttp2_hpack_parser p;
459   grpc_chttp2_hpack_parser_init(&p);
460   const int kArenaSize = 4096 * 4096;
461   p.on_header_user_data = gpr_arena_create(kArenaSize);
462   p.on_header = OnHeader;
463   for (auto slice : init_slices) {
464     GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
465   }
466   while (state.KeepRunning()) {
467     for (auto slice : benchmark_slices) {
468       GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
469     }
470     grpc_core::ExecCtx::Get()->Flush();
471     // Recreate arena every 4k iterations to avoid oom
472     if (0 == (state.iterations() & 0xfff)) {
473       gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
474       p.on_header_user_data = gpr_arena_create(kArenaSize);
475     }
476   }
477   // Clean up
478   gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
479   for (auto slice : init_slices) grpc_slice_unref(slice);
480   for (auto slice : benchmark_slices) grpc_slice_unref(slice);
481   grpc_chttp2_hpack_parser_destroy(&p);
482 
483   track_counters.Finish(state);
484 }
485 
486 namespace hpack_parser_fixtures {
487 
488 class EmptyBatch {
489  public:
GetInitSlices()490   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()491   static std::vector<grpc_slice> GetBenchmarkSlices() {
492     return {MakeSlice({})};
493   }
494 };
495 
496 class IndexedSingleStaticElem {
497  public:
GetInitSlices()498   static std::vector<grpc_slice> GetInitSlices() {
499     return {MakeSlice(
500         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
501   }
GetBenchmarkSlices()502   static std::vector<grpc_slice> GetBenchmarkSlices() {
503     return {MakeSlice({0xbe})};
504   }
505 };
506 
507 class AddIndexedSingleStaticElem {
508  public:
GetInitSlices()509   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()510   static std::vector<grpc_slice> GetBenchmarkSlices() {
511     return {MakeSlice(
512         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
513   }
514 };
515 
516 class KeyIndexedSingleStaticElem {
517  public:
GetInitSlices()518   static std::vector<grpc_slice> GetInitSlices() {
519     return {MakeSlice(
520         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
521   }
GetBenchmarkSlices()522   static std::vector<grpc_slice> GetBenchmarkSlices() {
523     return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})};
524   }
525 };
526 
527 class IndexedSingleInternedElem {
528  public:
GetInitSlices()529   static std::vector<grpc_slice> GetInitSlices() {
530     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
531   }
GetBenchmarkSlices()532   static std::vector<grpc_slice> GetBenchmarkSlices() {
533     return {MakeSlice({0xbe})};
534   }
535 };
536 
537 class AddIndexedSingleInternedElem {
538  public:
GetInitSlices()539   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()540   static std::vector<grpc_slice> GetBenchmarkSlices() {
541     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
542   }
543 };
544 
545 class KeyIndexedSingleInternedElem {
546  public:
GetInitSlices()547   static std::vector<grpc_slice> GetInitSlices() {
548     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
549   }
GetBenchmarkSlices()550   static std::vector<grpc_slice> GetBenchmarkSlices() {
551     return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
552   }
553 };
554 
555 class NonIndexedElem {
556  public:
GetInitSlices()557   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()558   static std::vector<grpc_slice> GetBenchmarkSlices() {
559     return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
560   }
561 };
562 
563 template <int kLength, bool kTrueBinary>
564 class NonIndexedBinaryElem;
565 
566 template <int kLength>
567 class NonIndexedBinaryElem<kLength, true> {
568  public:
GetInitSlices()569   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()570   static std::vector<grpc_slice> GetBenchmarkSlices() {
571     std::vector<uint8_t> v = {
572         0x00, 0x07, 'a', 'b', 'c',
573         '-',  'b',  'i', 'n', static_cast<uint8_t>(kLength + 1),
574         0};
575     for (int i = 0; i < kLength; i++) {
576       v.push_back(static_cast<uint8_t>(i));
577     }
578     return {MakeSlice(v)};
579   }
580 };
581 
582 template <>
583 class NonIndexedBinaryElem<1, false> {
584  public:
GetInitSlices()585   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()586   static std::vector<grpc_slice> GetBenchmarkSlices() {
587     return {MakeSlice(
588         {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x82, 0xf7, 0xb3})};
589   }
590 };
591 
592 template <>
593 class NonIndexedBinaryElem<3, false> {
594  public:
GetInitSlices()595   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()596   static std::vector<grpc_slice> GetBenchmarkSlices() {
597     return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x84,
598                        0x7f, 0x4e, 0x29, 0x3f})};
599   }
600 };
601 
602 template <>
603 class NonIndexedBinaryElem<10, false> {
604  public:
GetInitSlices()605   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()606   static std::vector<grpc_slice> GetBenchmarkSlices() {
607     return {MakeSlice({0x00, 0x07, 'a',  'b',  'c',  '-',  'b',
608                        'i',  'n',  0x8b, 0x71, 0x0c, 0xa5, 0x81,
609                        0x73, 0x7b, 0x47, 0x13, 0xe9, 0xf7, 0xe3})};
610   }
611 };
612 
613 template <>
614 class NonIndexedBinaryElem<31, false> {
615  public:
GetInitSlices()616   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()617   static std::vector<grpc_slice> GetBenchmarkSlices() {
618     return {MakeSlice({0x00, 0x07, 'a',  'b',  'c',  '-',  'b',  'i',  'n',
619                        0xa3, 0x92, 0x43, 0x7f, 0xbe, 0x7c, 0xea, 0x6f, 0xf3,
620                        0x3d, 0xa7, 0xa7, 0x67, 0xfb, 0xe2, 0x82, 0xf7, 0xf2,
621                        0x8f, 0x1f, 0x9d, 0xdf, 0xf1, 0x7e, 0xb3, 0xef, 0xb2,
622                        0x8f, 0x53, 0x77, 0xce, 0x0c, 0x13, 0xe3, 0xfd, 0x87})};
623   }
624 };
625 
626 template <>
627 class NonIndexedBinaryElem<100, false> {
628  public:
GetInitSlices()629   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()630   static std::vector<grpc_slice> GetBenchmarkSlices() {
631     return {MakeSlice(
632         {0x00, 0x07, 'a',  'b',  'c',  '-',  'b',  'i',  'n',  0xeb, 0x1d, 0x4d,
633          0xe8, 0x96, 0x8c, 0x14, 0x20, 0x06, 0xc1, 0xc3, 0xdf, 0x6e, 0x1f, 0xef,
634          0xde, 0x2f, 0xde, 0xb7, 0xf2, 0xfe, 0x6d, 0xd4, 0xe4, 0x7d, 0xf5, 0x55,
635          0x46, 0x52, 0x3d, 0x91, 0xf2, 0xd4, 0x6f, 0xca, 0x34, 0xcd, 0xd9, 0x39,
636          0xbd, 0x03, 0x27, 0xe3, 0x9c, 0x74, 0xcc, 0x17, 0x34, 0xed, 0xa6, 0x6a,
637          0x77, 0x73, 0x10, 0xcd, 0x8e, 0x4e, 0x5c, 0x7c, 0x72, 0x39, 0xd8, 0xe6,
638          0x78, 0x6b, 0xdb, 0xa5, 0xb7, 0xab, 0xe7, 0x46, 0xae, 0x21, 0xab, 0x7f,
639          0x01, 0x89, 0x13, 0xd7, 0xca, 0x17, 0x6e, 0xcb, 0xd6, 0x79, 0x71, 0x68,
640          0xbf, 0x8a, 0x3f, 0x32, 0xe8, 0xba, 0xf5, 0xbe, 0xb3, 0xbc, 0xde, 0x28,
641          0xc7, 0xcf, 0x62, 0x7a, 0x58, 0x2c, 0xcf, 0x4d, 0xe3})};
642   }
643 };
644 
645 class RepresentativeClientInitialMetadata {
646  public:
GetInitSlices()647   static std::vector<grpc_slice> GetInitSlices() {
648     return {grpc_slice_from_static_string(
649         // generated with:
650         // ```
651         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
652         // < test/core/bad_client/tests/simple_request.headers
653         // ```
654         "@\x05:path\x08/foo/bar"
655         "@\x07:scheme\x04http"
656         "@\x07:method\x04POST"
657         "@\x0a:authority\x09localhost"
658         "@\x0c"
659         "content-type\x10"
660         "application/grpc"
661         "@\x14grpc-accept-encoding\x15identity,deflate,gzip"
662         "@\x02te\x08trailers"
663         "@\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)")};
664   }
GetBenchmarkSlices()665   static std::vector<grpc_slice> GetBenchmarkSlices() {
666     // generated with:
667     // ```
668     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
669     // --hex < test/core/bad_client/tests/simple_request.headers
670     // ```
671     return {MakeSlice({0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe})};
672   }
673 };
674 
675 // This fixture reflects how initial metadata are sent by a production client,
676 // with non-indexed :path and binary headers. The metadata here are the same as
677 // the corresponding encoder benchmark above.
678 class MoreRepresentativeClientInitialMetadata {
679  public:
GetInitSlices()680   static std::vector<grpc_slice> GetInitSlices() {
681     return {MakeSlice(
682         {0x40, 0x07, ':',  's',  'c',  'h',  'e',  'm',  'e',  0x04, 'h',  't',
683          't',  'p',  0x40, 0x07, ':',  'm',  'e',  't',  'h',  'o',  'd',  0x04,
684          'P',  'O',  'S',  'T',  0x40, 0x05, ':',  'p',  'a',  't',  'h',  0x1f,
685          '/',  'g',  'r',  'p',  'c',  '.',  't',  'e',  's',  't',  '.',  'F',
686          'o',  'o',  'S',  'e',  'r',  'v',  'i',  'c',  'e',  '/',  'B',  'a',
687          'r',  'M',  'e',  't',  'h',  'o',  'd',  0x40, 0x0a, ':',  'a',  'u',
688          't',  'h',  'o',  'r',  'i',  't',  'y',  0x09, 'l',  'o',  'c',  'a',
689          'l',  'h',  'o',  's',  't',  0x40, 0x0e, 'g',  'r',  'p',  'c',  '-',
690          't',  'r',  'a',  'c',  'e',  '-',  'b',  'i',  'n',  0x31, 0x00, 0x01,
691          0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
692          0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
693          0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
694          0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x40,
695          0x0d, 'g',  'r',  'p',  'c',  '-',  't',  'a',  'g',  's',  '-',  'b',
696          'i',  'n',  0x14, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
697          0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x40,
698          0x0c, 'c',  'o',  'n',  't',  'e',  'n',  't',  '-',  't',  'y',  'p',
699          'e',  0x10, 'a',  'p',  'p',  'l',  'i',  'c',  'a',  't',  'i',  'o',
700          'n',  '/',  'g',  'r',  'p',  'c',  0x40, 0x14, 'g',  'r',  'p',  'c',
701          '-',  'a',  'c',  'c',  'e',  'p',  't',  '-',  'e',  'n',  'c',  'o',
702          'd',  'i',  'n',  'g',  0x15, 'i',  'd',  'e',  'n',  't',  'i',  't',
703          'y',  ',',  'd',  'e',  'f',  'l',  'a',  't',  'e',  ',',  'g',  'z',
704          'i',  'p',  0x40, 0x02, 't',  'e',  0x08, 't',  'r',  'a',  'i',  'l',
705          'e',  'r',  's',  0x40, 0x0a, 'u',  's',  'e',  'r',  '-',  'a',  'g',
706          'e',  'n',  't',  0x22, 'b',  'a',  'd',  '-',  'c',  'l',  'i',  'e',
707          'n',  't',  ' ',  'g',  'r',  'p',  'c',  '-',  'c',  '/',  '0',  '.',
708          '1',  '2',  '.',  '0',  '.',  '0',  ' ',  '(',  'l',  'i',  'n',  'u',
709          'x',  ')'})};
710   }
GetBenchmarkSlices()711   static std::vector<grpc_slice> GetBenchmarkSlices() {
712     return {MakeSlice(
713         {0xc7, 0xc6, 0xc5, 0xc4, 0x7f, 0x04, 0x31, 0x00, 0x01, 0x02, 0x03, 0x04,
714          0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
715          0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
716          0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
717          0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x7f, 0x03, 0x14, 0x00,
718          0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
719          0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0xc1, 0xc0, 0xbf, 0xbe})};
720   }
721 };
722 
723 class RepresentativeServerInitialMetadata {
724  public:
GetInitSlices()725   static std::vector<grpc_slice> GetInitSlices() {
726     return {grpc_slice_from_static_string(
727         // generated with:
728         // ```
729         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
730         // <
731         // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
732         // ```
733         "@\x07:status\x03"
734         "200"
735         "@\x0c"
736         "content-type\x10"
737         "application/grpc"
738         "@\x14grpc-accept-encoding\x15identity,deflate,gzip")};
739   }
GetBenchmarkSlices()740   static std::vector<grpc_slice> GetBenchmarkSlices() {
741     // generated with:
742     // ```
743     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
744     // --hex <
745     // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
746     // ```
747     return {MakeSlice({0xc0, 0xbf, 0xbe})};
748   }
749 };
750 
751 class RepresentativeServerTrailingMetadata {
752  public:
GetInitSlices()753   static std::vector<grpc_slice> GetInitSlices() {
754     return {grpc_slice_from_static_string(
755         // generated with:
756         // ```
757         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
758         // <
759         // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
760         // ```
761         "@\x0bgrpc-status\x01"
762         "0"
763         "@\x0cgrpc-message\x00")};
764   }
GetBenchmarkSlices()765   static std::vector<grpc_slice> GetBenchmarkSlices() {
766     // generated with:
767     // ```
768     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
769     // --hex <
770     // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
771     // ```
772     return {MakeSlice({0xbf, 0xbe})};
773   }
774 };
775 
free_timeout(void * p)776 static void free_timeout(void* p) { gpr_free(p); }
777 
778 // Benchmark the current on_initial_header implementation
OnInitialHeader(void * user_data,grpc_mdelem md)779 static void OnInitialHeader(void* user_data, grpc_mdelem md) {
780   // Setup for benchmark. This will bloat the absolute values of this benchmark
781   grpc_chttp2_incoming_metadata_buffer buffer;
782   grpc_chttp2_incoming_metadata_buffer_init(&buffer, (gpr_arena*)user_data);
783   bool seen_error = false;
784 
785   // Below here is the code we actually care about benchmarking
786   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
787       !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
788     seen_error = true;
789   }
790   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
791     grpc_millis* cached_timeout =
792         static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
793     grpc_millis timeout;
794     if (cached_timeout != nullptr) {
795       timeout = *cached_timeout;
796     } else {
797       if (GPR_UNLIKELY(
798               !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
799         char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
800         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
801         gpr_free(val);
802         timeout = GRPC_MILLIS_INF_FUTURE;
803       }
804       if (GRPC_MDELEM_IS_INTERNED(md)) {
805         /* not already parsed: parse it now, and store the
806          * result away */
807         cached_timeout =
808             static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
809         *cached_timeout = timeout;
810         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
811       }
812     }
813     benchmark::DoNotOptimize(timeout);
814     GRPC_MDELEM_UNREF(md);
815   } else {
816     const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
817     if (!seen_error) {
818       buffer.size = new_size;
819     }
820     grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
821     if (error != GRPC_ERROR_NONE) {
822       GPR_ASSERT(0);
823     }
824   }
825   grpc_chttp2_incoming_metadata_buffer_destroy(&buffer);
826 }
827 
828 // Benchmark timeout handling
OnHeaderTimeout(void * user_data,grpc_mdelem md)829 static void OnHeaderTimeout(void* user_data, grpc_mdelem md) {
830   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
831     grpc_millis* cached_timeout =
832         static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
833     grpc_millis timeout;
834     if (cached_timeout != nullptr) {
835       timeout = *cached_timeout;
836     } else {
837       if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout)) {
838         char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
839         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
840         gpr_free(val);
841         timeout = GRPC_MILLIS_INF_FUTURE;
842       }
843       if (GRPC_MDELEM_IS_INTERNED(md)) {
844         /* not already parsed: parse it now, and store the
845          * result away */
846         cached_timeout =
847             static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
848         *cached_timeout = timeout;
849         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
850       }
851     }
852     benchmark::DoNotOptimize(timeout);
853     GRPC_MDELEM_UNREF(md);
854   } else {
855     GPR_ASSERT(0);
856   }
857 }
858 
859 // Send the same deadline repeatedly
860 class SameDeadline {
861  public:
GetInitSlices()862   static std::vector<grpc_slice> GetInitSlices() {
863     return {
864         grpc_slice_from_static_string("@\x0cgrpc-timeout\x03"
865                                       "30S")};
866   }
GetBenchmarkSlices()867   static std::vector<grpc_slice> GetBenchmarkSlices() {
868     // Use saved key and literal value.
869     return {MakeSlice({0x0f, 0x2f, 0x03, '3', '0', 'S'})};
870   }
871 };
872 
873 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch, UnrefHeader);
874 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem,
875                    UnrefHeader);
876 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem,
877                    UnrefHeader);
878 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem,
879                    UnrefHeader);
880 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem,
881                    UnrefHeader);
882 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem,
883                    UnrefHeader);
884 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem,
885                    UnrefHeader);
886 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem, UnrefHeader);
887 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, false>,
888                    UnrefHeader);
889 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, false>,
890                    UnrefHeader);
891 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, false>,
892                    UnrefHeader);
893 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, false>,
894                    UnrefHeader);
895 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, false>,
896                    UnrefHeader);
897 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, true>,
898                    UnrefHeader);
899 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, true>,
900                    UnrefHeader);
901 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, true>,
902                    UnrefHeader);
903 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>,
904                    UnrefHeader);
905 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>,
906                    UnrefHeader);
907 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
908                    RepresentativeClientInitialMetadata, UnrefHeader);
909 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
910                    MoreRepresentativeClientInitialMetadata, UnrefHeader);
911 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
912                    RepresentativeServerInitialMetadata, UnrefHeader);
913 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
914                    RepresentativeServerTrailingMetadata, UnrefHeader);
915 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
916                    RepresentativeClientInitialMetadata, OnInitialHeader);
917 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
918                    MoreRepresentativeClientInitialMetadata, OnInitialHeader);
919 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
920                    RepresentativeServerInitialMetadata, OnInitialHeader);
921 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
922 
923 }  // namespace hpack_parser_fixtures
924 
925 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
926 // and others do not. This allows us to support both modes.
927 namespace benchmark {
RunTheBenchmarksNamespaced()928 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
929 }  // namespace benchmark
930 
main(int argc,char ** argv)931 int main(int argc, char** argv) {
932   ::benchmark::Initialize(&argc, argv);
933   ::grpc::testing::InitTest(&argc, &argv, false);
934   benchmark::RunTheBenchmarksNamespaced();
935   return 0;
936 }
937