3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 /* Microbenchmarks around CHTTP2 HPACK operations */
26 #include <benchmark/benchmark.h>
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
31 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
32 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
33 #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
34 #include "src/core/lib/slice/slice_internal.h"
35 #include "src/core/lib/slice/slice_string_helpers.h"
36 #include "src/core/lib/transport/static_metadata.h"
37 #include "src/core/lib/transport/timeout_encoding.h"
38 #include "test/core/util/test_config.h"
39 #include "test/cpp/microbenchmarks/helpers.h"
40 #include "test/cpp/util/test_config.h"
42 static grpc_slice MakeSlice(std::vector<uint8_t> bytes) {
43 grpc_slice s = grpc_slice_malloc(bytes.size());
44 uint8_t* p = GRPC_SLICE_START_PTR(s);
45 for (auto b : bytes) {
51 ////////////////////////////////////////////////////////////////////////////////
55 static void BM_HpackEncoderInitDestroy(benchmark::State& state) {
56 TrackCounters track_counters;
57 grpc_core::ExecCtx exec_ctx;
58 for (auto _ : state) {
59 grpc_core::HPackCompressor c;
60 grpc_core::ExecCtx::Get()->Flush();
63 track_counters.Finish(state);
65 BENCHMARK(BM_HpackEncoderInitDestroy);
67 static void BM_HpackEncoderEncodeDeadline(benchmark::State& state) {
68 TrackCounters track_counters;
69 grpc_core::ExecCtx exec_ctx;
70 grpc_millis saved_now = grpc_core::ExecCtx::Get()->Now();
72 grpc_metadata_batch b;
73 grpc_metadata_batch_init(&b);
74 b.deadline = saved_now + 30 * 1000;
76 grpc_core::HPackCompressor c;
77 grpc_transport_one_way_stats stats;
79 grpc_slice_buffer outbuf;
80 grpc_slice_buffer_init(&outbuf);
81 while (state.KeepRunning()) {
83 grpc_core::HPackCompressor::EncodeHeaderOptions{
84 static_cast<uint32_t>(state.iterations()),
87 static_cast<size_t>(1024),
91 grpc_slice_buffer_reset_and_unref_internal(&outbuf);
92 grpc_core::ExecCtx::Get()->Flush();
94 grpc_metadata_batch_destroy(&b);
95 grpc_slice_buffer_destroy_internal(&outbuf);
97 std::ostringstream label;
98 label << "framing_bytes/iter:"
99 << (static_cast<double>(stats.framing_bytes) /
100 static_cast<double>(state.iterations()))
101 << " header_bytes/iter:"
102 << (static_cast<double>(stats.header_bytes) /
103 static_cast<double>(state.iterations()));
104 track_counters.AddLabel(label.str());
105 track_counters.Finish(state);
107 BENCHMARK(BM_HpackEncoderEncodeDeadline);
109 template <class Fixture>
110 static void BM_HpackEncoderEncodeHeader(benchmark::State& state) {
111 TrackCounters track_counters;
112 grpc_core::ExecCtx exec_ctx;
113 static bool logged_representative_output = false;
115 grpc_metadata_batch b;
116 grpc_metadata_batch_init(&b);
117 std::vector<grpc_mdelem> elems = Fixture::GetElems();
118 std::vector<grpc_linked_mdelem> storage(elems.size());
119 for (size_t i = 0; i < elems.size(); i++) {
120 GPR_ASSERT(GRPC_LOG_IF_ERROR(
121 "addmd", grpc_metadata_batch_add_tail(&b, &storage[i], elems[i])));
124 grpc_core::HPackCompressor c;
125 grpc_transport_one_way_stats stats;
127 grpc_slice_buffer outbuf;
128 grpc_slice_buffer_init(&outbuf);
129 while (state.KeepRunning()) {
130 static constexpr int kEnsureMaxFrameAtLeast = 2;
132 grpc_core::HPackCompressor::EncodeHeaderOptions{
133 static_cast<uint32_t>(state.iterations()),
135 Fixture::kEnableTrueBinary,
136 static_cast<size_t>(state.range(1) + kEnsureMaxFrameAtLeast),
140 if (!logged_representative_output && state.iterations() > 3) {
141 logged_representative_output = true;
142 for (size_t i = 0; i < outbuf.count; i++) {
143 char* s = grpc_dump_slice(outbuf.slices[i], GPR_DUMP_HEX);
144 gpr_log(GPR_DEBUG, "%" PRIdPTR ": %s", i, s);
148 grpc_slice_buffer_reset_and_unref_internal(&outbuf);
149 grpc_core::ExecCtx::Get()->Flush();
151 grpc_metadata_batch_destroy(&b);
152 grpc_slice_buffer_destroy_internal(&outbuf);
154 std::ostringstream label;
155 label << "framing_bytes/iter:"
156 << (static_cast<double>(stats.framing_bytes) /
157 static_cast<double>(state.iterations()))
158 << " header_bytes/iter:"
159 << (static_cast<double>(stats.header_bytes) /
160 static_cast<double>(state.iterations()));
161 track_counters.AddLabel(label.str());
162 track_counters.Finish(state);
165 namespace hpack_encoder_fixtures {
169 static constexpr bool kEnableTrueBinary = false;
170 static std::vector<grpc_mdelem> GetElems() { return {}; }
173 class SingleStaticElem {
175 static constexpr bool kEnableTrueBinary = false;
176 static std::vector<grpc_mdelem> GetElems() {
177 return {GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE};
181 class SingleInternedElem {
183 static constexpr bool kEnableTrueBinary = false;
184 static std::vector<grpc_mdelem> GetElems() {
185 return {grpc_mdelem_from_slices(
186 grpc_slice_intern(grpc_slice_from_static_string("abc")),
187 grpc_slice_intern(grpc_slice_from_static_string("def")))};
191 template <int kLength, bool kTrueBinary>
192 class SingleInternedBinaryElem {
194 static constexpr bool kEnableTrueBinary = kTrueBinary;
195 static std::vector<grpc_mdelem> GetElems() {
196 grpc_slice bytes = MakeBytes();
197 std::vector<grpc_mdelem> out = {grpc_mdelem_from_slices(
198 grpc_slice_intern(grpc_slice_from_static_string("abc-bin")),
199 grpc_slice_intern(bytes))};
200 grpc_slice_unref(bytes);
205 static grpc_slice MakeBytes() {
208 for (int i = 0; i < kLength; i++) {
209 v.push_back(static_cast<char>(rand()));
211 return grpc_slice_from_copied_buffer(v.data(), v.size());
215 class SingleInternedKeyElem {
217 static constexpr bool kEnableTrueBinary = false;
218 static std::vector<grpc_mdelem> GetElems() {
219 return {grpc_mdelem_from_slices(
220 grpc_slice_intern(grpc_slice_from_static_string("abc")),
221 grpc_slice_from_static_string("def"))};
225 class SingleNonInternedElem {
227 static constexpr bool kEnableTrueBinary = false;
228 static std::vector<grpc_mdelem> GetElems() {
229 return {grpc_mdelem_from_slices(grpc_slice_from_static_string("abc"),
230 grpc_slice_from_static_string("def"))};
234 template <int kLength, bool kTrueBinary>
235 class SingleNonInternedBinaryElem {
237 static constexpr bool kEnableTrueBinary = kTrueBinary;
238 static std::vector<grpc_mdelem> GetElems() {
239 return {grpc_mdelem_from_slices(grpc_slice_from_static_string("abc-bin"),
244 static grpc_slice MakeBytes() {
247 for (int i = 0; i < kLength; i++) {
248 v.push_back(static_cast<char>(rand()));
250 return grpc_slice_from_copied_buffer(v.data(), v.size());
254 class RepresentativeClientInitialMetadata {
256 static constexpr bool kEnableTrueBinary = true;
257 static std::vector<grpc_mdelem> GetElems() {
259 GRPC_MDELEM_SCHEME_HTTP,
260 GRPC_MDELEM_METHOD_POST,
261 grpc_mdelem_from_slices(
263 grpc_slice_intern(grpc_slice_from_static_string("/foo/bar"))),
264 grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
265 grpc_slice_intern(grpc_slice_from_static_string(
266 "foo.test.google.fr:1234"))),
267 GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
268 GRPC_MDELEM_TE_TRAILERS,
269 GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
270 grpc_mdelem_from_slices(
271 GRPC_MDSTR_USER_AGENT,
272 grpc_slice_intern(grpc_slice_from_static_string(
273 "grpc-c/3.0.0-dev (linux; chttp2; green)")))};
277 // This fixture reflects how initial metadata are sent by a production client,
278 // with non-indexed :path and binary headers. The metadata here are the same as
279 // the corresponding parser benchmark below.
280 class MoreRepresentativeClientInitialMetadata {
282 static constexpr bool kEnableTrueBinary = true;
283 static std::vector<grpc_mdelem> GetElems() {
285 GRPC_MDELEM_SCHEME_HTTP,
286 GRPC_MDELEM_METHOD_POST,
287 grpc_mdelem_from_slices(GRPC_MDSTR_PATH,
288 grpc_slice_intern(grpc_slice_from_static_string(
289 "/grpc.test.FooService/BarMethod"))),
290 grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
291 grpc_slice_intern(grpc_slice_from_static_string(
292 "foo.test.google.fr:1234"))),
293 grpc_mdelem_from_slices(
294 GRPC_MDSTR_GRPC_TRACE_BIN,
295 grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
296 "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
297 "\x10\x11\x12\x13\x14\x15\x16\x17\x18"
298 "\x19\x1a\x1b\x1c\x1d\x1e\x1f"
299 "\x20\x21\x22\x23\x24\x25\x26\x27\x28"
300 "\x29\x2a\x2b\x2c\x2d\x2e\x2f"
302 grpc_mdelem_from_slices(
303 GRPC_MDSTR_GRPC_TAGS_BIN,
304 grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
305 "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
306 "\x10\x11\x12\x13")),
307 GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
308 GRPC_MDELEM_TE_TRAILERS,
309 GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
310 grpc_mdelem_from_slices(
311 GRPC_MDSTR_USER_AGENT,
312 grpc_slice_intern(grpc_slice_from_static_string(
313 "grpc-c/3.0.0-dev (linux; chttp2; green)")))};
317 class RepresentativeServerInitialMetadata {
319 static constexpr bool kEnableTrueBinary = true;
320 static std::vector<grpc_mdelem> GetElems() {
321 return {GRPC_MDELEM_STATUS_200,
322 GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
323 GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP};
327 class RepresentativeServerTrailingMetadata {
329 static constexpr bool kEnableTrueBinary = true;
330 static std::vector<grpc_mdelem> GetElems() {
331 return {GRPC_MDELEM_GRPC_STATUS_0};
335 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({0, 16384});
336 // test with eof (shouldn't affect anything)
337 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({1, 16384});
338 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleStaticElem)
340 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedKeyElem)
342 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedElem)
344 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
345 SingleInternedBinaryElem<1, false>)
347 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
348 SingleInternedBinaryElem<3, false>)
350 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
351 SingleInternedBinaryElem<10, false>)
353 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
354 SingleInternedBinaryElem<31, false>)
356 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
357 SingleInternedBinaryElem<100, false>)
359 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
360 SingleInternedBinaryElem<1, true>)
362 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
363 SingleInternedBinaryElem<3, true>)
365 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
366 SingleInternedBinaryElem<10, true>)
368 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
369 SingleInternedBinaryElem<31, true>)
371 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
372 SingleInternedBinaryElem<100, true>)
374 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
376 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
377 SingleNonInternedBinaryElem<1, false>)
379 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
380 SingleNonInternedBinaryElem<3, false>)
382 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
383 SingleNonInternedBinaryElem<10, false>)
385 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
386 SingleNonInternedBinaryElem<31, false>)
388 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
389 SingleNonInternedBinaryElem<100, false>)
391 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
392 SingleNonInternedBinaryElem<1, true>)
394 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
395 SingleNonInternedBinaryElem<3, true>)
397 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
398 SingleNonInternedBinaryElem<10, true>)
400 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
401 SingleNonInternedBinaryElem<31, true>)
403 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
404 SingleNonInternedBinaryElem<100, true>)
406 // test with a tiny frame size, to highlight continuation costs
407 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
410 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
411 RepresentativeClientInitialMetadata)
413 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
414 MoreRepresentativeClientInitialMetadata)
416 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
417 RepresentativeServerInitialMetadata)
419 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
420 RepresentativeServerTrailingMetadata)
423 } // namespace hpack_encoder_fixtures
425 ////////////////////////////////////////////////////////////////////////////////
429 static void BM_HpackParserInitDestroy(benchmark::State& state) {
430 TrackCounters track_counters;
431 grpc_core::ExecCtx exec_ctx;
432 for (auto _ : state) {
433 { grpc_core::HPackParser(); }
434 grpc_core::ExecCtx::Get()->Flush();
437 track_counters.Finish(state);
439 BENCHMARK(BM_HpackParserInitDestroy);
441 static grpc_error_handle UnrefHeader(void* /*user_data*/, grpc_mdelem md) {
442 GRPC_MDELEM_UNREF(md);
443 return GRPC_ERROR_NONE;
446 template <class Fixture, grpc_error_handle (*OnHeader)(void*, grpc_mdelem)>
447 static void BM_HpackParserParseHeader(benchmark::State& state) {
448 TrackCounters track_counters;
449 grpc_core::ExecCtx exec_ctx;
450 std::vector<grpc_slice> init_slices = Fixture::GetInitSlices();
451 std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
452 grpc_core::HPackParser p;
453 const int kArenaSize = 4096 * 4096;
454 auto* arena = grpc_core::Arena::Create(kArenaSize);
455 p.BeginFrame([arena](grpc_mdelem e) { return OnHeader(arena, e); },
456 grpc_core::HPackParser::Boundary::None,
457 grpc_core::HPackParser::Priority::None);
458 for (auto slice : init_slices) {
459 GPR_ASSERT(GRPC_ERROR_NONE == p.Parse(slice, false));
461 while (state.KeepRunning()) {
462 for (auto slice : benchmark_slices) {
463 GPR_ASSERT(GRPC_ERROR_NONE == p.Parse(slice, false));
465 grpc_core::ExecCtx::Get()->Flush();
466 // Recreate arena every 4k iterations to avoid oom
467 if (0 == (state.iterations() & 0xfff)) {
469 arena = grpc_core::Arena::Create(kArenaSize);
470 p.BeginFrame([arena](grpc_mdelem e) { return OnHeader(arena, e); },
471 grpc_core::HPackParser::Boundary::None,
472 grpc_core::HPackParser::Priority::None);
477 for (auto slice : init_slices) grpc_slice_unref(slice);
478 for (auto slice : benchmark_slices) grpc_slice_unref(slice);
480 track_counters.Finish(state);
483 namespace hpack_parser_fixtures {
487 static std::vector<grpc_slice> GetInitSlices() { return {}; }
488 static std::vector<grpc_slice> GetBenchmarkSlices() {
489 return {MakeSlice({})};
493 class IndexedSingleStaticElem {
495 static std::vector<grpc_slice> GetInitSlices() {
497 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
499 static std::vector<grpc_slice> GetBenchmarkSlices() {
500 return {MakeSlice({0xbe})};
504 class AddIndexedSingleStaticElem {
506 static std::vector<grpc_slice> GetInitSlices() { return {}; }
507 static std::vector<grpc_slice> GetBenchmarkSlices() {
509 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
513 class KeyIndexedSingleStaticElem {
515 static std::vector<grpc_slice> GetInitSlices() {
517 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
519 static std::vector<grpc_slice> GetBenchmarkSlices() {
520 return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})};
524 class IndexedSingleInternedElem {
526 static std::vector<grpc_slice> GetInitSlices() {
527 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
529 static std::vector<grpc_slice> GetBenchmarkSlices() {
530 return {MakeSlice({0xbe})};
534 class AddIndexedSingleInternedElem {
536 static std::vector<grpc_slice> GetInitSlices() { return {}; }
537 static std::vector<grpc_slice> GetBenchmarkSlices() {
538 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
542 class KeyIndexedSingleInternedElem {
544 static std::vector<grpc_slice> GetInitSlices() {
545 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
547 static std::vector<grpc_slice> GetBenchmarkSlices() {
548 return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
552 class NonIndexedElem {
554 static std::vector<grpc_slice> GetInitSlices() { return {}; }
555 static std::vector<grpc_slice> GetBenchmarkSlices() {
556 return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
560 template <int kLength, bool kTrueBinary>
561 class NonIndexedBinaryElem;
563 template <int kLength>
564 class NonIndexedBinaryElem<kLength, true> {
566 static std::vector<grpc_slice> GetInitSlices() { return {}; }
567 static std::vector<grpc_slice> GetBenchmarkSlices() {
568 std::vector<uint8_t> v = {
569 0x00, 0x07, 'a', 'b', 'c',
570 '-', 'b', 'i', 'n', static_cast<uint8_t>(kLength + 1),
572 for (int i = 0; i < kLength; i++) {
573 v.push_back(static_cast<uint8_t>(i));
575 return {MakeSlice(v)};
580 class NonIndexedBinaryElem<1, false> {
582 static std::vector<grpc_slice> GetInitSlices() { return {}; }
583 static std::vector<grpc_slice> GetBenchmarkSlices() {
585 {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x82, 0xf7, 0xb3})};
590 class NonIndexedBinaryElem<3, false> {
592 static std::vector<grpc_slice> GetInitSlices() { return {}; }
593 static std::vector<grpc_slice> GetBenchmarkSlices() {
594 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x84,
595 0x7f, 0x4e, 0x29, 0x3f})};
600 class NonIndexedBinaryElem<10, false> {
602 static std::vector<grpc_slice> GetInitSlices() { return {}; }
603 static std::vector<grpc_slice> GetBenchmarkSlices() {
604 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b',
605 'i', 'n', 0x8b, 0x71, 0x0c, 0xa5, 0x81,
606 0x73, 0x7b, 0x47, 0x13, 0xe9, 0xf7, 0xe3})};
611 class NonIndexedBinaryElem<31, false> {
613 static std::vector<grpc_slice> GetInitSlices() { return {}; }
614 static std::vector<grpc_slice> GetBenchmarkSlices() {
615 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n',
616 0xa3, 0x92, 0x43, 0x7f, 0xbe, 0x7c, 0xea, 0x6f, 0xf3,
617 0x3d, 0xa7, 0xa7, 0x67, 0xfb, 0xe2, 0x82, 0xf7, 0xf2,
618 0x8f, 0x1f, 0x9d, 0xdf, 0xf1, 0x7e, 0xb3, 0xef, 0xb2,
619 0x8f, 0x53, 0x77, 0xce, 0x0c, 0x13, 0xe3, 0xfd, 0x87})};
624 class NonIndexedBinaryElem<100, false> {
626 static std::vector<grpc_slice> GetInitSlices() { return {}; }
627 static std::vector<grpc_slice> GetBenchmarkSlices() {
629 {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0xeb, 0x1d, 0x4d,
630 0xe8, 0x96, 0x8c, 0x14, 0x20, 0x06, 0xc1, 0xc3, 0xdf, 0x6e, 0x1f, 0xef,
631 0xde, 0x2f, 0xde, 0xb7, 0xf2, 0xfe, 0x6d, 0xd4, 0xe4, 0x7d, 0xf5, 0x55,
632 0x46, 0x52, 0x3d, 0x91, 0xf2, 0xd4, 0x6f, 0xca, 0x34, 0xcd, 0xd9, 0x39,
633 0xbd, 0x03, 0x27, 0xe3, 0x9c, 0x74, 0xcc, 0x17, 0x34, 0xed, 0xa6, 0x6a,
634 0x77, 0x73, 0x10, 0xcd, 0x8e, 0x4e, 0x5c, 0x7c, 0x72, 0x39, 0xd8, 0xe6,
635 0x78, 0x6b, 0xdb, 0xa5, 0xb7, 0xab, 0xe7, 0x46, 0xae, 0x21, 0xab, 0x7f,
636 0x01, 0x89, 0x13, 0xd7, 0xca, 0x17, 0x6e, 0xcb, 0xd6, 0x79, 0x71, 0x68,
637 0xbf, 0x8a, 0x3f, 0x32, 0xe8, 0xba, 0xf5, 0xbe, 0xb3, 0xbc, 0xde, 0x28,
638 0xc7, 0xcf, 0x62, 0x7a, 0x58, 0x2c, 0xcf, 0x4d, 0xe3})};
642 class RepresentativeClientInitialMetadata {
644 static std::vector<grpc_slice> GetInitSlices() {
645 return {grpc_slice_from_static_string(
648 // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
649 // < test/core/bad_client/tests/simple_request.headers
651 "@\x05:path\x08/foo/bar"
652 "@\x07:scheme\x04http"
653 "@\x07:method\x04POST"
654 "@\x0a:authority\x09localhost"
658 "@\x14grpc-accept-encoding\x15identity,deflate,gzip"
659 "@\x02te\x08trailers"
660 "@\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)")};
662 static std::vector<grpc_slice> GetBenchmarkSlices() {
665 // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
666 // --hex < test/core/bad_client/tests/simple_request.headers
668 return {MakeSlice({0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe})};
672 // This fixture reflects how initial metadata are sent by a production client,
673 // with non-indexed :path and binary headers. The metadata here are the same as
674 // the corresponding encoder benchmark above.
675 class MoreRepresentativeClientInitialMetadata {
677 static std::vector<grpc_slice> GetInitSlices() {
679 {0x40, 0x07, ':', 's', 'c', 'h', 'e', 'm', 'e', 0x04, 'h', 't',
680 't', 'p', 0x40, 0x07, ':', 'm', 'e', 't', 'h', 'o', 'd', 0x04,
681 'P', 'O', 'S', 'T', 0x40, 0x05, ':', 'p', 'a', 't', 'h', 0x1f,
682 '/', 'g', 'r', 'p', 'c', '.', 't', 'e', 's', 't', '.', 'F',
683 'o', 'o', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'B', 'a',
684 'r', 'M', 'e', 't', 'h', 'o', 'd', 0x40, 0x0a, ':', 'a', 'u',
685 't', 'h', 'o', 'r', 'i', 't', 'y', 0x09, 'l', 'o', 'c', 'a',
686 'l', 'h', 'o', 's', 't', 0x40, 0x0e, 'g', 'r', 'p', 'c', '-',
687 't', 'r', 'a', 'c', 'e', '-', 'b', 'i', 'n', 0x31, 0x00, 0x01,
688 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
689 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
690 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
691 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x40,
692 0x0d, 'g', 'r', 'p', 'c', '-', 't', 'a', 'g', 's', '-', 'b',
693 'i', 'n', 0x14, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
694 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x40,
695 0x0c, 'c', 'o', 'n', 't', 'e', 'n', 't', '-', 't', 'y', 'p',
696 'e', 0x10, 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o',
697 'n', '/', 'g', 'r', 'p', 'c', 0x40, 0x14, 'g', 'r', 'p', 'c',
698 '-', 'a', 'c', 'c', 'e', 'p', 't', '-', 'e', 'n', 'c', 'o',
699 'd', 'i', 'n', 'g', 0x15, 'i', 'd', 'e', 'n', 't', 'i', 't',
700 'y', ',', 'd', 'e', 'f', 'l', 'a', 't', 'e', ',', 'g', 'z',
701 'i', 'p', 0x40, 0x02, 't', 'e', 0x08, 't', 'r', 'a', 'i', 'l',
702 'e', 'r', 's', 0x40, 0x0a, 'u', 's', 'e', 'r', '-', 'a', 'g',
703 'e', 'n', 't', 0x22, 'b', 'a', 'd', '-', 'c', 'l', 'i', 'e',
704 'n', 't', ' ', 'g', 'r', 'p', 'c', '-', 'c', '/', '0', '.',
705 '1', '2', '.', '0', '.', '0', ' ', '(', 'l', 'i', 'n', 'u',
708 static std::vector<grpc_slice> GetBenchmarkSlices() {
710 {0xc7, 0xc6, 0xc5, 0xc4, 0x7f, 0x04, 0x31, 0x00, 0x01, 0x02, 0x03, 0x04,
711 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
712 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
713 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
714 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x7f, 0x03, 0x14, 0x00,
715 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
716 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0xc1, 0xc0, 0xbf, 0xbe})};
720 class RepresentativeServerInitialMetadata {
722 static std::vector<grpc_slice> GetInitSlices() {
723 return {grpc_slice_from_static_string(
726 // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
728 // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
735 "@\x14grpc-accept-encoding\x15identity,deflate,gzip")};
737 static std::vector<grpc_slice> GetBenchmarkSlices() {
740 // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
742 // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
744 return {MakeSlice({0xc0, 0xbf, 0xbe})};
748 class RepresentativeServerTrailingMetadata {
750 static std::vector<grpc_slice> GetInitSlices() {
751 return {grpc_slice_from_static_string(
754 // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
756 // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
758 "@\x0bgrpc-status\x01"
760 "@\x0cgrpc-message\x00")};
762 static std::vector<grpc_slice> GetBenchmarkSlices() {
765 // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
767 // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
769 return {MakeSlice({0xbf, 0xbe})};
773 static void free_timeout(void* p) { gpr_free(p); }
775 // Benchmark the current on_initial_header implementation
776 static grpc_error_handle OnInitialHeader(void* user_data, grpc_mdelem md) {
777 // Setup for benchmark. This will bloat the absolute values of this benchmark
778 grpc_chttp2_incoming_metadata_buffer buffer(
779 static_cast<grpc_core::Arena*>(user_data));
780 bool seen_error = false;
782 // Below here is the code we actually care about benchmarking
783 if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
784 !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
787 if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
788 grpc_millis* cached_timeout =
789 static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
791 if (cached_timeout != nullptr) {
792 timeout = *cached_timeout;
795 !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
796 char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
797 gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
799 timeout = GRPC_MILLIS_INF_FUTURE;
801 if (GRPC_MDELEM_IS_INTERNED(md)) {
802 /* not already parsed: parse it now, and store the
805 static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
806 *cached_timeout = timeout;
807 grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
810 benchmark::DoNotOptimize(timeout);
811 GRPC_MDELEM_UNREF(md);
813 const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
815 buffer.size = new_size;
817 grpc_error_handle error =
818 grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
819 if (error != GRPC_ERROR_NONE) {
823 return GRPC_ERROR_NONE;
826 // Benchmark timeout handling
827 static grpc_error_handle OnHeaderTimeout(void* /*user_data*/, grpc_mdelem md) {
828 if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
829 grpc_millis* cached_timeout =
830 static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
832 if (cached_timeout != nullptr) {
833 timeout = *cached_timeout;
835 if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout)) {
836 char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
837 gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
839 timeout = GRPC_MILLIS_INF_FUTURE;
841 if (GRPC_MDELEM_IS_INTERNED(md)) {
842 /* not already parsed: parse it now, and store the
845 static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
846 *cached_timeout = timeout;
847 grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
850 benchmark::DoNotOptimize(timeout);
851 GRPC_MDELEM_UNREF(md);
855 return GRPC_ERROR_NONE;
858 // Send the same deadline repeatedly
861 static std::vector<grpc_slice> GetInitSlices() {
863 grpc_slice_from_static_string("@\x0cgrpc-timeout\x03"
866 static std::vector<grpc_slice> GetBenchmarkSlices() {
867 // Use saved key and literal value.
868 return {MakeSlice({0x0f, 0x2f, 0x03, '3', '0', 'S'})};
872 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch, UnrefHeader);
873 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem,
875 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem,
877 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem,
879 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem,
881 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem,
883 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem,
885 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem, UnrefHeader);
886 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, false>,
888 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, false>,
890 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, false>,
892 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, false>,
894 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, false>,
896 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, true>,
898 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, true>,
900 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, true>,
902 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>,
904 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>,
906 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
907 RepresentativeClientInitialMetadata, UnrefHeader);
908 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
909 MoreRepresentativeClientInitialMetadata, UnrefHeader);
910 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
911 RepresentativeServerInitialMetadata, UnrefHeader);
912 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
913 RepresentativeServerTrailingMetadata, UnrefHeader);
914 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
915 RepresentativeClientInitialMetadata, OnInitialHeader);
916 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
917 MoreRepresentativeClientInitialMetadata, OnInitialHeader);
918 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
919 RepresentativeServerInitialMetadata, OnInitialHeader);
920 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
922 } // namespace hpack_parser_fixtures
924 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
925 // and others do not. This allows us to support both modes.
926 namespace benchmark {
927 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
928 } // namespace benchmark
930 int main(int argc, char** argv) {
931 grpc::testing::TestEnvironment env(argc, argv);
932 LibraryInitializer libInit;
933 ::benchmark::Initialize(&argc, argv);
934 ::grpc::testing::InitTest(&argc, &argv, false);
935 benchmark::RunTheBenchmarksNamespaced();