• 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/core/util/test_config.h"
37 #include "test/cpp/microbenchmarks/helpers.h"
38 #include "test/cpp/util/test_config.h"
39 
MakeSlice(std::vector<uint8_t> bytes)40 static grpc_slice MakeSlice(std::vector<uint8_t> bytes) {
41   grpc_slice s = grpc_slice_malloc(bytes.size());
42   uint8_t* p = GRPC_SLICE_START_PTR(s);
43   for (auto b : bytes) {
44     *p++ = b;
45   }
46   return s;
47 }
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 // HPACK encoder
51 //
52 
BM_HpackEncoderInitDestroy(benchmark::State & state)53 static void BM_HpackEncoderInitDestroy(benchmark::State& state) {
54   TrackCounters track_counters;
55   grpc_core::ExecCtx exec_ctx;
56   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
57       new grpc_chttp2_hpack_compressor);
58   for (auto _ : state) {
59     grpc_chttp2_hpack_compressor_init(c.get());
60     grpc_chttp2_hpack_compressor_destroy(c.get());
61     grpc_core::ExecCtx::Get()->Flush();
62   }
63 
64   track_counters.Finish(state);
65 }
66 BENCHMARK(BM_HpackEncoderInitDestroy);
67 
BM_HpackEncoderEncodeDeadline(benchmark::State & state)68 static void BM_HpackEncoderEncodeDeadline(benchmark::State& state) {
69   TrackCounters track_counters;
70   grpc_core::ExecCtx exec_ctx;
71   grpc_millis saved_now = grpc_core::ExecCtx::Get()->Now();
72 
73   grpc_metadata_batch b;
74   grpc_metadata_batch_init(&b);
75   b.deadline = saved_now + 30 * 1000;
76 
77   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
78       new grpc_chttp2_hpack_compressor);
79   grpc_chttp2_hpack_compressor_init(c.get());
80   grpc_transport_one_way_stats stats;
81   stats = {};
82   grpc_slice_buffer outbuf;
83   grpc_slice_buffer_init(&outbuf);
84   while (state.KeepRunning()) {
85     grpc_encode_header_options hopt = {
86         static_cast<uint32_t>(state.iterations()),
87         true,
88         false,
89         static_cast<size_t>(1024),
90         &stats,
91     };
92     grpc_chttp2_encode_header(c.get(), nullptr, 0, &b, &hopt, &outbuf);
93     grpc_slice_buffer_reset_and_unref_internal(&outbuf);
94     grpc_core::ExecCtx::Get()->Flush();
95   }
96   grpc_metadata_batch_destroy(&b);
97   grpc_chttp2_hpack_compressor_destroy(c.get());
98   grpc_slice_buffer_destroy_internal(&outbuf);
99 
100   std::ostringstream label;
101   label << "framing_bytes/iter:"
102         << (static_cast<double>(stats.framing_bytes) /
103             static_cast<double>(state.iterations()))
104         << " header_bytes/iter:"
105         << (static_cast<double>(stats.header_bytes) /
106             static_cast<double>(state.iterations()));
107   track_counters.AddLabel(label.str());
108   track_counters.Finish(state);
109 }
110 BENCHMARK(BM_HpackEncoderEncodeDeadline);
111 
112 template <class Fixture>
BM_HpackEncoderEncodeHeader(benchmark::State & state)113 static void BM_HpackEncoderEncodeHeader(benchmark::State& state) {
114   TrackCounters track_counters;
115   grpc_core::ExecCtx exec_ctx;
116   static bool logged_representative_output = false;
117 
118   grpc_metadata_batch b;
119   grpc_metadata_batch_init(&b);
120   std::vector<grpc_mdelem> elems = Fixture::GetElems();
121   std::vector<grpc_linked_mdelem> storage(elems.size());
122   for (size_t i = 0; i < elems.size(); i++) {
123     GPR_ASSERT(GRPC_LOG_IF_ERROR(
124         "addmd", grpc_metadata_batch_add_tail(&b, &storage[i], elems[i])));
125   }
126 
127   std::unique_ptr<grpc_chttp2_hpack_compressor> c(
128       new grpc_chttp2_hpack_compressor);
129   grpc_chttp2_hpack_compressor_init(c.get());
130   grpc_transport_one_way_stats stats;
131   stats = {};
132   grpc_slice_buffer outbuf;
133   grpc_slice_buffer_init(&outbuf);
134   while (state.KeepRunning()) {
135     static constexpr int kEnsureMaxFrameAtLeast = 2;
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) + kEnsureMaxFrameAtLeast),
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   // Initial destruction so we don't leak memory in the loop.
439   grpc_chttp2_hptbl_destroy(&p.table);
440   for (auto _ : state) {
441     grpc_chttp2_hpack_parser_init(&p);
442     // Note that grpc_chttp2_hpack_parser_destroy frees the table dynamic
443     // elements so we need to recreate it here. In actual operation,
444     // new grpc_chttp2_hpack_parser_destroy allocates the table once
445     // and for all.
446     new (&p.table) grpc_chttp2_hptbl();
447     grpc_chttp2_hpack_parser_destroy(&p);
448     grpc_core::ExecCtx::Get()->Flush();
449   }
450 
451   track_counters.Finish(state);
452 }
453 BENCHMARK(BM_HpackParserInitDestroy);
454 
UnrefHeader(void *,grpc_mdelem md)455 static grpc_error* UnrefHeader(void* /*user_data*/, grpc_mdelem md) {
456   GRPC_MDELEM_UNREF(md);
457   return GRPC_ERROR_NONE;
458 }
459 
460 template <class Fixture, grpc_error* (*OnHeader)(void*, grpc_mdelem)>
BM_HpackParserParseHeader(benchmark::State & state)461 static void BM_HpackParserParseHeader(benchmark::State& state) {
462   TrackCounters track_counters;
463   grpc_core::ExecCtx exec_ctx;
464   std::vector<grpc_slice> init_slices = Fixture::GetInitSlices();
465   std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
466   grpc_chttp2_hpack_parser p;
467   grpc_chttp2_hpack_parser_init(&p);
468   const int kArenaSize = 4096 * 4096;
469   p.on_header_user_data = grpc_core::Arena::Create(kArenaSize);
470   p.on_header = OnHeader;
471   for (auto slice : init_slices) {
472     GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
473   }
474   while (state.KeepRunning()) {
475     for (auto slice : benchmark_slices) {
476       GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
477     }
478     grpc_core::ExecCtx::Get()->Flush();
479     // Recreate arena every 4k iterations to avoid oom
480     if (0 == (state.iterations() & 0xfff)) {
481       static_cast<grpc_core::Arena*>(p.on_header_user_data)->Destroy();
482       p.on_header_user_data = grpc_core::Arena::Create(kArenaSize);
483     }
484   }
485   // Clean up
486   static_cast<grpc_core::Arena*>(p.on_header_user_data)->Destroy();
487   for (auto slice : init_slices) grpc_slice_unref(slice);
488   for (auto slice : benchmark_slices) grpc_slice_unref(slice);
489   grpc_chttp2_hpack_parser_destroy(&p);
490 
491   track_counters.Finish(state);
492 }
493 
494 namespace hpack_parser_fixtures {
495 
496 class EmptyBatch {
497  public:
GetInitSlices()498   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()499   static std::vector<grpc_slice> GetBenchmarkSlices() {
500     return {MakeSlice({})};
501   }
502 };
503 
504 class IndexedSingleStaticElem {
505  public:
GetInitSlices()506   static std::vector<grpc_slice> GetInitSlices() {
507     return {MakeSlice(
508         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
509   }
GetBenchmarkSlices()510   static std::vector<grpc_slice> GetBenchmarkSlices() {
511     return {MakeSlice({0xbe})};
512   }
513 };
514 
515 class AddIndexedSingleStaticElem {
516  public:
GetInitSlices()517   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()518   static std::vector<grpc_slice> GetBenchmarkSlices() {
519     return {MakeSlice(
520         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
521   }
522 };
523 
524 class KeyIndexedSingleStaticElem {
525  public:
GetInitSlices()526   static std::vector<grpc_slice> GetInitSlices() {
527     return {MakeSlice(
528         {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
529   }
GetBenchmarkSlices()530   static std::vector<grpc_slice> GetBenchmarkSlices() {
531     return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})};
532   }
533 };
534 
535 class IndexedSingleInternedElem {
536  public:
GetInitSlices()537   static std::vector<grpc_slice> GetInitSlices() {
538     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
539   }
GetBenchmarkSlices()540   static std::vector<grpc_slice> GetBenchmarkSlices() {
541     return {MakeSlice({0xbe})};
542   }
543 };
544 
545 class AddIndexedSingleInternedElem {
546  public:
GetInitSlices()547   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()548   static std::vector<grpc_slice> GetBenchmarkSlices() {
549     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
550   }
551 };
552 
553 class KeyIndexedSingleInternedElem {
554  public:
GetInitSlices()555   static std::vector<grpc_slice> GetInitSlices() {
556     return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
557   }
GetBenchmarkSlices()558   static std::vector<grpc_slice> GetBenchmarkSlices() {
559     return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
560   }
561 };
562 
563 class NonIndexedElem {
564  public:
GetInitSlices()565   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()566   static std::vector<grpc_slice> GetBenchmarkSlices() {
567     return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
568   }
569 };
570 
571 template <int kLength, bool kTrueBinary>
572 class NonIndexedBinaryElem;
573 
574 template <int kLength>
575 class NonIndexedBinaryElem<kLength, true> {
576  public:
GetInitSlices()577   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()578   static std::vector<grpc_slice> GetBenchmarkSlices() {
579     std::vector<uint8_t> v = {
580         0x00, 0x07, 'a', 'b', 'c',
581         '-',  'b',  'i', 'n', static_cast<uint8_t>(kLength + 1),
582         0};
583     for (int i = 0; i < kLength; i++) {
584       v.push_back(static_cast<uint8_t>(i));
585     }
586     return {MakeSlice(v)};
587   }
588 };
589 
590 template <>
591 class NonIndexedBinaryElem<1, false> {
592  public:
GetInitSlices()593   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()594   static std::vector<grpc_slice> GetBenchmarkSlices() {
595     return {MakeSlice(
596         {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x82, 0xf7, 0xb3})};
597   }
598 };
599 
600 template <>
601 class NonIndexedBinaryElem<3, false> {
602  public:
GetInitSlices()603   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()604   static std::vector<grpc_slice> GetBenchmarkSlices() {
605     return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x84,
606                        0x7f, 0x4e, 0x29, 0x3f})};
607   }
608 };
609 
610 template <>
611 class NonIndexedBinaryElem<10, false> {
612  public:
GetInitSlices()613   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()614   static std::vector<grpc_slice> GetBenchmarkSlices() {
615     return {MakeSlice({0x00, 0x07, 'a',  'b',  'c',  '-',  'b',
616                        'i',  'n',  0x8b, 0x71, 0x0c, 0xa5, 0x81,
617                        0x73, 0x7b, 0x47, 0x13, 0xe9, 0xf7, 0xe3})};
618   }
619 };
620 
621 template <>
622 class NonIndexedBinaryElem<31, false> {
623  public:
GetInitSlices()624   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()625   static std::vector<grpc_slice> GetBenchmarkSlices() {
626     return {MakeSlice({0x00, 0x07, 'a',  'b',  'c',  '-',  'b',  'i',  'n',
627                        0xa3, 0x92, 0x43, 0x7f, 0xbe, 0x7c, 0xea, 0x6f, 0xf3,
628                        0x3d, 0xa7, 0xa7, 0x67, 0xfb, 0xe2, 0x82, 0xf7, 0xf2,
629                        0x8f, 0x1f, 0x9d, 0xdf, 0xf1, 0x7e, 0xb3, 0xef, 0xb2,
630                        0x8f, 0x53, 0x77, 0xce, 0x0c, 0x13, 0xe3, 0xfd, 0x87})};
631   }
632 };
633 
634 template <>
635 class NonIndexedBinaryElem<100, false> {
636  public:
GetInitSlices()637   static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()638   static std::vector<grpc_slice> GetBenchmarkSlices() {
639     return {MakeSlice(
640         {0x00, 0x07, 'a',  'b',  'c',  '-',  'b',  'i',  'n',  0xeb, 0x1d, 0x4d,
641          0xe8, 0x96, 0x8c, 0x14, 0x20, 0x06, 0xc1, 0xc3, 0xdf, 0x6e, 0x1f, 0xef,
642          0xde, 0x2f, 0xde, 0xb7, 0xf2, 0xfe, 0x6d, 0xd4, 0xe4, 0x7d, 0xf5, 0x55,
643          0x46, 0x52, 0x3d, 0x91, 0xf2, 0xd4, 0x6f, 0xca, 0x34, 0xcd, 0xd9, 0x39,
644          0xbd, 0x03, 0x27, 0xe3, 0x9c, 0x74, 0xcc, 0x17, 0x34, 0xed, 0xa6, 0x6a,
645          0x77, 0x73, 0x10, 0xcd, 0x8e, 0x4e, 0x5c, 0x7c, 0x72, 0x39, 0xd8, 0xe6,
646          0x78, 0x6b, 0xdb, 0xa5, 0xb7, 0xab, 0xe7, 0x46, 0xae, 0x21, 0xab, 0x7f,
647          0x01, 0x89, 0x13, 0xd7, 0xca, 0x17, 0x6e, 0xcb, 0xd6, 0x79, 0x71, 0x68,
648          0xbf, 0x8a, 0x3f, 0x32, 0xe8, 0xba, 0xf5, 0xbe, 0xb3, 0xbc, 0xde, 0x28,
649          0xc7, 0xcf, 0x62, 0x7a, 0x58, 0x2c, 0xcf, 0x4d, 0xe3})};
650   }
651 };
652 
653 class RepresentativeClientInitialMetadata {
654  public:
GetInitSlices()655   static std::vector<grpc_slice> GetInitSlices() {
656     return {grpc_slice_from_static_string(
657         // generated with:
658         // ```
659         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
660         // < test/core/bad_client/tests/simple_request.headers
661         // ```
662         "@\x05:path\x08/foo/bar"
663         "@\x07:scheme\x04http"
664         "@\x07:method\x04POST"
665         "@\x0a:authority\x09localhost"
666         "@\x0c"
667         "content-type\x10"
668         "application/grpc"
669         "@\x14grpc-accept-encoding\x15identity,deflate,gzip"
670         "@\x02te\x08trailers"
671         "@\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)")};
672   }
GetBenchmarkSlices()673   static std::vector<grpc_slice> GetBenchmarkSlices() {
674     // generated with:
675     // ```
676     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
677     // --hex < test/core/bad_client/tests/simple_request.headers
678     // ```
679     return {MakeSlice({0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe})};
680   }
681 };
682 
683 // This fixture reflects how initial metadata are sent by a production client,
684 // with non-indexed :path and binary headers. The metadata here are the same as
685 // the corresponding encoder benchmark above.
686 class MoreRepresentativeClientInitialMetadata {
687  public:
GetInitSlices()688   static std::vector<grpc_slice> GetInitSlices() {
689     return {MakeSlice(
690         {0x40, 0x07, ':',  's',  'c',  'h',  'e',  'm',  'e',  0x04, 'h',  't',
691          't',  'p',  0x40, 0x07, ':',  'm',  'e',  't',  'h',  'o',  'd',  0x04,
692          'P',  'O',  'S',  'T',  0x40, 0x05, ':',  'p',  'a',  't',  'h',  0x1f,
693          '/',  'g',  'r',  'p',  'c',  '.',  't',  'e',  's',  't',  '.',  'F',
694          'o',  'o',  'S',  'e',  'r',  'v',  'i',  'c',  'e',  '/',  'B',  'a',
695          'r',  'M',  'e',  't',  'h',  'o',  'd',  0x40, 0x0a, ':',  'a',  'u',
696          't',  'h',  'o',  'r',  'i',  't',  'y',  0x09, 'l',  'o',  'c',  'a',
697          'l',  'h',  'o',  's',  't',  0x40, 0x0e, 'g',  'r',  'p',  'c',  '-',
698          't',  'r',  'a',  'c',  'e',  '-',  'b',  'i',  'n',  0x31, 0x00, 0x01,
699          0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
700          0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
701          0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
702          0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x40,
703          0x0d, 'g',  'r',  'p',  'c',  '-',  't',  'a',  'g',  's',  '-',  'b',
704          'i',  'n',  0x14, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
705          0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x40,
706          0x0c, 'c',  'o',  'n',  't',  'e',  'n',  't',  '-',  't',  'y',  'p',
707          'e',  0x10, 'a',  'p',  'p',  'l',  'i',  'c',  'a',  't',  'i',  'o',
708          'n',  '/',  'g',  'r',  'p',  'c',  0x40, 0x14, 'g',  'r',  'p',  'c',
709          '-',  'a',  'c',  'c',  'e',  'p',  't',  '-',  'e',  'n',  'c',  'o',
710          'd',  'i',  'n',  'g',  0x15, 'i',  'd',  'e',  'n',  't',  'i',  't',
711          'y',  ',',  'd',  'e',  'f',  'l',  'a',  't',  'e',  ',',  'g',  'z',
712          'i',  'p',  0x40, 0x02, 't',  'e',  0x08, 't',  'r',  'a',  'i',  'l',
713          'e',  'r',  's',  0x40, 0x0a, 'u',  's',  'e',  'r',  '-',  'a',  'g',
714          'e',  'n',  't',  0x22, 'b',  'a',  'd',  '-',  'c',  'l',  'i',  'e',
715          'n',  't',  ' ',  'g',  'r',  'p',  'c',  '-',  'c',  '/',  '0',  '.',
716          '1',  '2',  '.',  '0',  '.',  '0',  ' ',  '(',  'l',  'i',  'n',  'u',
717          'x',  ')'})};
718   }
GetBenchmarkSlices()719   static std::vector<grpc_slice> GetBenchmarkSlices() {
720     return {MakeSlice(
721         {0xc7, 0xc6, 0xc5, 0xc4, 0x7f, 0x04, 0x31, 0x00, 0x01, 0x02, 0x03, 0x04,
722          0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
723          0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
724          0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
725          0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x7f, 0x03, 0x14, 0x00,
726          0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
727          0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0xc1, 0xc0, 0xbf, 0xbe})};
728   }
729 };
730 
731 class RepresentativeServerInitialMetadata {
732  public:
GetInitSlices()733   static std::vector<grpc_slice> GetInitSlices() {
734     return {grpc_slice_from_static_string(
735         // generated with:
736         // ```
737         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
738         // <
739         // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
740         // ```
741         "@\x07:status\x03"
742         "200"
743         "@\x0c"
744         "content-type\x10"
745         "application/grpc"
746         "@\x14grpc-accept-encoding\x15identity,deflate,gzip")};
747   }
GetBenchmarkSlices()748   static std::vector<grpc_slice> GetBenchmarkSlices() {
749     // generated with:
750     // ```
751     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
752     // --hex <
753     // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
754     // ```
755     return {MakeSlice({0xc0, 0xbf, 0xbe})};
756   }
757 };
758 
759 class RepresentativeServerTrailingMetadata {
760  public:
GetInitSlices()761   static std::vector<grpc_slice> GetInitSlices() {
762     return {grpc_slice_from_static_string(
763         // generated with:
764         // ```
765         // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
766         // <
767         // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
768         // ```
769         "@\x0bgrpc-status\x01"
770         "0"
771         "@\x0cgrpc-message\x00")};
772   }
GetBenchmarkSlices()773   static std::vector<grpc_slice> GetBenchmarkSlices() {
774     // generated with:
775     // ```
776     // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
777     // --hex <
778     // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
779     // ```
780     return {MakeSlice({0xbf, 0xbe})};
781   }
782 };
783 
free_timeout(void * p)784 static void free_timeout(void* p) { gpr_free(p); }
785 
786 // Benchmark the current on_initial_header implementation
OnInitialHeader(void * user_data,grpc_mdelem md)787 static grpc_error* OnInitialHeader(void* user_data, grpc_mdelem md) {
788   // Setup for benchmark. This will bloat the absolute values of this benchmark
789   grpc_chttp2_incoming_metadata_buffer buffer(
790       static_cast<grpc_core::Arena*>(user_data));
791   bool seen_error = false;
792 
793   // Below here is the code we actually care about benchmarking
794   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
795       !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
796     seen_error = true;
797   }
798   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
799     grpc_millis* cached_timeout =
800         static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
801     grpc_millis timeout;
802     if (cached_timeout != nullptr) {
803       timeout = *cached_timeout;
804     } else {
805       if (GPR_UNLIKELY(
806               !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
807         char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
808         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
809         gpr_free(val);
810         timeout = GRPC_MILLIS_INF_FUTURE;
811       }
812       if (GRPC_MDELEM_IS_INTERNED(md)) {
813         /* not already parsed: parse it now, and store the
814          * result away */
815         cached_timeout =
816             static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
817         *cached_timeout = timeout;
818         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
819       }
820     }
821     benchmark::DoNotOptimize(timeout);
822     GRPC_MDELEM_UNREF(md);
823   } else {
824     const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
825     if (!seen_error) {
826       buffer.size = new_size;
827     }
828     grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
829     if (error != GRPC_ERROR_NONE) {
830       GPR_ASSERT(0);
831     }
832   }
833   return GRPC_ERROR_NONE;
834 }
835 
836 // Benchmark timeout handling
OnHeaderTimeout(void *,grpc_mdelem md)837 static grpc_error* OnHeaderTimeout(void* /*user_data*/, grpc_mdelem md) {
838   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
839     grpc_millis* cached_timeout =
840         static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
841     grpc_millis timeout;
842     if (cached_timeout != nullptr) {
843       timeout = *cached_timeout;
844     } else {
845       if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout)) {
846         char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
847         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
848         gpr_free(val);
849         timeout = GRPC_MILLIS_INF_FUTURE;
850       }
851       if (GRPC_MDELEM_IS_INTERNED(md)) {
852         /* not already parsed: parse it now, and store the
853          * result away */
854         cached_timeout =
855             static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
856         *cached_timeout = timeout;
857         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
858       }
859     }
860     benchmark::DoNotOptimize(timeout);
861     GRPC_MDELEM_UNREF(md);
862   } else {
863     GPR_ASSERT(0);
864   }
865   return GRPC_ERROR_NONE;
866 }
867 
868 // Send the same deadline repeatedly
869 class SameDeadline {
870  public:
GetInitSlices()871   static std::vector<grpc_slice> GetInitSlices() {
872     return {
873         grpc_slice_from_static_string("@\x0cgrpc-timeout\x03"
874                                       "30S")};
875   }
GetBenchmarkSlices()876   static std::vector<grpc_slice> GetBenchmarkSlices() {
877     // Use saved key and literal value.
878     return {MakeSlice({0x0f, 0x2f, 0x03, '3', '0', 'S'})};
879   }
880 };
881 
882 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch, UnrefHeader);
883 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem,
884                    UnrefHeader);
885 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem,
886                    UnrefHeader);
887 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem,
888                    UnrefHeader);
889 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem,
890                    UnrefHeader);
891 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem,
892                    UnrefHeader);
893 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem,
894                    UnrefHeader);
895 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem, UnrefHeader);
896 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, false>,
897                    UnrefHeader);
898 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, false>,
899                    UnrefHeader);
900 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, false>,
901                    UnrefHeader);
902 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, false>,
903                    UnrefHeader);
904 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, false>,
905                    UnrefHeader);
906 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, true>,
907                    UnrefHeader);
908 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, true>,
909                    UnrefHeader);
910 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, true>,
911                    UnrefHeader);
912 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>,
913                    UnrefHeader);
914 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>,
915                    UnrefHeader);
916 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
917                    RepresentativeClientInitialMetadata, UnrefHeader);
918 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
919                    MoreRepresentativeClientInitialMetadata, UnrefHeader);
920 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
921                    RepresentativeServerInitialMetadata, UnrefHeader);
922 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
923                    RepresentativeServerTrailingMetadata, UnrefHeader);
924 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
925                    RepresentativeClientInitialMetadata, OnInitialHeader);
926 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
927                    MoreRepresentativeClientInitialMetadata, OnInitialHeader);
928 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
929                    RepresentativeServerInitialMetadata, OnInitialHeader);
930 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
931 
932 }  // namespace hpack_parser_fixtures
933 
934 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
935 // and others do not. This allows us to support both modes.
936 namespace benchmark {
RunTheBenchmarksNamespaced()937 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
938 }  // namespace benchmark
939 
main(int argc,char ** argv)940 int main(int argc, char** argv) {
941   grpc::testing::TestEnvironment env(argc, argv);
942   LibraryInitializer libInit;
943   ::benchmark::Initialize(&argc, argv);
944   ::grpc::testing::InitTest(&argc, &argv, false);
945   benchmark::RunTheBenchmarksNamespaced();
946   return 0;
947 }
948