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