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 <string.h>
22
23 #include <memory>
24 #include <sstream>
25
26 #include <benchmark/benchmark.h>
27
28 #include "absl/random/random.h"
29
30 #include <grpc/slice.h>
31 #include <grpc/support/alloc.h>
32 #include <grpc/support/log.h>
33
34 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
35 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
36 #include "src/core/lib/gprpp/crash.h"
37 #include "src/core/lib/gprpp/time.h"
38 #include "src/core/lib/resource_quota/resource_quota.h"
39 #include "src/core/lib/slice/slice_internal.h"
40 #include "src/core/lib/slice/slice_string_helpers.h"
41 #include "src/core/lib/transport/metadata_batch.h"
42 #include "src/core/lib/transport/timeout_encoding.h"
43 #include "test/core/util/test_config.h"
44 #include "test/cpp/microbenchmarks/helpers.h"
45 #include "test/cpp/util/test_config.h"
46
MakeSlice(const std::vector<uint8_t> & bytes)47 static grpc_slice MakeSlice(const std::vector<uint8_t>& bytes) {
48 grpc_slice s = grpc_slice_malloc(bytes.size());
49 uint8_t* p = GRPC_SLICE_START_PTR(s);
50 for (auto b : bytes) {
51 *p++ = b;
52 }
53 return s;
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////
57 // HPACK encoder
58 //
59
BM_HpackEncoderInitDestroy(benchmark::State & state)60 static void BM_HpackEncoderInitDestroy(benchmark::State& state) {
61 grpc_core::ExecCtx exec_ctx;
62 for (auto _ : state) {
63 grpc_core::HPackCompressor c;
64 grpc_core::ExecCtx::Get()->Flush();
65 }
66 }
67 BENCHMARK(BM_HpackEncoderInitDestroy);
68
BM_HpackEncoderEncodeDeadline(benchmark::State & state)69 static void BM_HpackEncoderEncodeDeadline(benchmark::State& state) {
70 grpc_core::ExecCtx exec_ctx;
71 grpc_core::Timestamp saved_now = grpc_core::Timestamp::Now();
72
73 grpc_core::MemoryAllocator memory_allocator =
74 grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
75 ->memory_quota()
76 ->CreateMemoryAllocator("test"));
77 auto arena = grpc_core::MakeScopedArena(1024, &memory_allocator);
78 grpc_metadata_batch b;
79 b.Set(grpc_core::GrpcTimeoutMetadata(),
80 saved_now + grpc_core::Duration::Seconds(30));
81
82 grpc_core::HPackCompressor c;
83 grpc_transport_one_way_stats stats;
84 stats = {};
85 grpc_slice_buffer outbuf;
86 grpc_slice_buffer_init(&outbuf);
87 while (state.KeepRunning()) {
88 c.EncodeHeaders(
89 grpc_core::HPackCompressor::EncodeHeaderOptions{
90 static_cast<uint32_t>(state.iterations()),
91 true,
92 false,
93 size_t{1024},
94 &stats,
95 },
96 b, &outbuf);
97 grpc_slice_buffer_reset_and_unref(&outbuf);
98 grpc_core::ExecCtx::Get()->Flush();
99 }
100 grpc_slice_buffer_destroy(&outbuf);
101 }
102 BENCHMARK(BM_HpackEncoderEncodeDeadline);
103
104 template <class Fixture>
BM_HpackEncoderEncodeHeader(benchmark::State & state)105 static void BM_HpackEncoderEncodeHeader(benchmark::State& state) {
106 grpc_core::ExecCtx exec_ctx;
107 static bool logged_representative_output = false;
108
109 grpc_core::MemoryAllocator memory_allocator =
110 grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
111 ->memory_quota()
112 ->CreateMemoryAllocator("test"));
113 auto arena = grpc_core::MakeScopedArena(1024, &memory_allocator);
114 grpc_metadata_batch b;
115 Fixture::Prepare(&b);
116
117 grpc_core::HPackCompressor c;
118 grpc_transport_one_way_stats stats;
119 stats = {};
120 grpc_slice_buffer outbuf;
121 grpc_slice_buffer_init(&outbuf);
122 while (state.KeepRunning()) {
123 static constexpr int kEnsureMaxFrameAtLeast = 2;
124 c.EncodeHeaders(
125 grpc_core::HPackCompressor::EncodeHeaderOptions{
126 static_cast<uint32_t>(state.iterations()),
127 state.range(0) != 0,
128 Fixture::kEnableTrueBinary,
129 static_cast<size_t>(state.range(1) + kEnsureMaxFrameAtLeast),
130 &stats,
131 },
132 b, &outbuf);
133 if (!logged_representative_output && state.iterations() > 3) {
134 logged_representative_output = true;
135 for (size_t i = 0; i < outbuf.count; i++) {
136 char* s = grpc_dump_slice(outbuf.slices[i], GPR_DUMP_HEX);
137 gpr_log(GPR_DEBUG, "%" PRIdPTR ": %s", i, s);
138 gpr_free(s);
139 }
140 }
141 grpc_slice_buffer_reset_and_unref(&outbuf);
142 grpc_core::ExecCtx::Get()->Flush();
143 }
144 grpc_slice_buffer_destroy(&outbuf);
145 }
146
147 namespace hpack_encoder_fixtures {
148
149 class EmptyBatch {
150 public:
151 static constexpr bool kEnableTrueBinary = false;
Prepare(grpc_metadata_batch *)152 static void Prepare(grpc_metadata_batch*) {}
153 };
154
155 class SingleStaticElem {
156 public:
157 static constexpr bool kEnableTrueBinary = false;
Prepare(grpc_metadata_batch * b)158 static void Prepare(grpc_metadata_batch* b) {
159 b->Set(grpc_core::GrpcAcceptEncodingMetadata(),
160 grpc_core::CompressionAlgorithmSet(
161 {GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE}));
162 }
163 };
164
CrashOnAppendError(absl::string_view,const grpc_core::Slice &)165 static void CrashOnAppendError(absl::string_view, const grpc_core::Slice&) {
166 abort();
167 }
168
169 class SingleNonBinaryElem {
170 public:
171 static constexpr bool kEnableTrueBinary = false;
Prepare(grpc_metadata_batch * b)172 static void Prepare(grpc_metadata_batch* b) {
173 b->Append("abc", grpc_core::Slice::FromStaticString("def"),
174 CrashOnAppendError);
175 }
176 };
177
178 template <int kLength, bool kTrueBinary>
179 class SingleBinaryElem {
180 public:
181 static constexpr bool kEnableTrueBinary = kTrueBinary;
Prepare(grpc_metadata_batch * b)182 static void Prepare(grpc_metadata_batch* b) {
183 b->Append("abc-bin", MakeBytes(), CrashOnAppendError);
184 }
185
186 private:
MakeBytes()187 static grpc_core::Slice MakeBytes() {
188 std::vector<char> v;
189 v.reserve(kLength);
190 for (int i = 0; i < kLength; i++) {
191 v.push_back(static_cast<char>(rand()));
192 }
193 return grpc_core::Slice::FromCopiedBuffer(v);
194 }
195 };
196
197 class RepresentativeClientInitialMetadata {
198 public:
199 static constexpr bool kEnableTrueBinary = true;
Prepare(grpc_metadata_batch * b)200 static void Prepare(grpc_metadata_batch* b) {
201 b->Set(grpc_core::HttpSchemeMetadata(),
202 grpc_core::HttpSchemeMetadata::kHttp);
203 b->Set(grpc_core::HttpMethodMetadata(),
204 grpc_core::HttpMethodMetadata::kPost);
205 b->Set(
206 grpc_core::HttpPathMetadata(),
207 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString("/foo/bar")));
208 b->Set(grpc_core::HttpAuthorityMetadata(),
209 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
210 "foo.test.google.fr:1234")));
211 b->Set(
212 grpc_core::GrpcAcceptEncodingMetadata(),
213 grpc_core::CompressionAlgorithmSet(
214 {GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_GZIP}));
215 b->Set(grpc_core::TeMetadata(), grpc_core::TeMetadata::kTrailers);
216 b->Set(grpc_core::ContentTypeMetadata(),
217 grpc_core::ContentTypeMetadata::kApplicationGrpc);
218 b->Set(grpc_core::UserAgentMetadata(),
219 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
220 "grpc-c/3.0.0-dev (linux; chttp2; green)")));
221 }
222 };
223
224 // This fixture reflects how initial metadata are sent by a production client,
225 // with non-indexed :path and binary headers. The metadata here are the same as
226 // the corresponding parser benchmark below.
227 class MoreRepresentativeClientInitialMetadata {
228 public:
229 static constexpr bool kEnableTrueBinary = true;
Prepare(grpc_metadata_batch * b)230 static void Prepare(grpc_metadata_batch* b) {
231 b->Set(grpc_core::HttpSchemeMetadata(),
232 grpc_core::HttpSchemeMetadata::kHttp);
233 b->Set(grpc_core::HttpMethodMetadata(),
234 grpc_core::HttpMethodMetadata::kPost);
235 b->Set(grpc_core::HttpPathMetadata(),
236 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
237 "/grpc.test.FooService/BarMethod")));
238 b->Set(grpc_core::HttpAuthorityMetadata(),
239 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
240 "foo.test.google.fr:1234")));
241 b->Set(grpc_core::GrpcTraceBinMetadata(),
242 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
243 "\x00\x01\x02\x03\x04\x05\x06\x07\x08"
244 "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
245 "\x10\x11\x12\x13\x14\x15\x16\x17\x18"
246 "\x19\x1a\x1b\x1c\x1d\x1e\x1f"
247 "\x20\x21\x22\x23\x24\x25\x26\x27\x28"
248 "\x29\x2a\x2b\x2c\x2d\x2e\x2f"
249 "\x30")));
250 b->Set(grpc_core::GrpcTagsBinMetadata(),
251 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
252 "\x00\x01\x02\x03\x04\x05\x06\x07\x08"
253 "\x09\x0a\x0b\x0c\x0d\x0e\x0f"
254 "\x10\x11\x12\x13")));
255 b->Set(
256 grpc_core::GrpcAcceptEncodingMetadata(),
257 grpc_core::CompressionAlgorithmSet(
258 {GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_GZIP}));
259 b->Set(grpc_core::TeMetadata(), grpc_core::TeMetadata::kTrailers);
260 b->Set(grpc_core::ContentTypeMetadata(),
261 grpc_core::ContentTypeMetadata::kApplicationGrpc);
262 b->Set(grpc_core::UserAgentMetadata(),
263 grpc_core::Slice(grpc_core::StaticSlice::FromStaticString(
264 "grpc-c/3.0.0-dev (linux; chttp2; green)")));
265 }
266 };
267
268 class RepresentativeServerInitialMetadata {
269 public:
270 static constexpr bool kEnableTrueBinary = true;
Prepare(grpc_metadata_batch * b)271 static void Prepare(grpc_metadata_batch* b) {
272 b->Set(grpc_core::HttpStatusMetadata(), 200);
273 b->Set(grpc_core::ContentTypeMetadata(),
274 grpc_core::ContentTypeMetadata::kApplicationGrpc);
275 b->Set(
276 grpc_core::GrpcAcceptEncodingMetadata(),
277 grpc_core::CompressionAlgorithmSet(
278 {GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_GZIP}));
279 }
280 };
281
282 class RepresentativeServerTrailingMetadata {
283 public:
284 static constexpr bool kEnableTrueBinary = true;
Prepare(grpc_metadata_batch * b)285 static void Prepare(grpc_metadata_batch* b) {
286 b->Set(grpc_core::GrpcStatusMetadata(), GRPC_STATUS_OK);
287 }
288 };
289
290 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({0, 16384});
291 // test with eof (shouldn't affect anything)
292 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({1, 16384});
293 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleStaticElem)
294 ->Args({0, 16384});
295 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonBinaryElem)
296 ->Args({0, 16384});
297 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleBinaryElem<1, false>)
298 ->Args({0, 16384});
299 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleBinaryElem<3, false>)
300 ->Args({0, 16384});
301 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleBinaryElem<10, false>)
302 ->Args({0, 16384});
303 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleBinaryElem<31, false>)
304 ->Args({0, 16384});
305 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleBinaryElem<100, false>)
306 ->Args({0, 16384});
307 // test with a tiny frame size, to highlight continuation costs
308 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonBinaryElem)
309 ->Args({0, 1});
310
311 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
312 RepresentativeClientInitialMetadata)
313 ->Args({0, 16384});
314 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
315 MoreRepresentativeClientInitialMetadata)
316 ->Args({0, 16384});
317 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
318 RepresentativeServerInitialMetadata)
319 ->Args({0, 16384});
320 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
321 RepresentativeServerTrailingMetadata)
322 ->Args({1, 16384});
323
324 } // namespace hpack_encoder_fixtures
325
326 ////////////////////////////////////////////////////////////////////////////////
327 // HPACK parser
328 //
329
BM_HpackParserInitDestroy(benchmark::State & state)330 static void BM_HpackParserInitDestroy(benchmark::State& state) {
331 grpc_core::ExecCtx exec_ctx;
332 for (auto _ : state) {
333 {
334 grpc_core::HPackParser();
335 }
336 grpc_core::ExecCtx::Get()->Flush();
337 }
338 }
339 BENCHMARK(BM_HpackParserInitDestroy);
340
341 template <class Fixture>
BM_HpackParserParseHeader(benchmark::State & state)342 static void BM_HpackParserParseHeader(benchmark::State& state) {
343 std::vector<grpc_slice> init_slices = Fixture::GetInitSlices();
344 std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
345 grpc_core::ExecCtx exec_ctx;
346 grpc_core::HPackParser p;
347 const int kArenaSize = 4096 * 4096;
348 grpc_core::MemoryAllocator memory_allocator =
349 grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
350 ->memory_quota()
351 ->CreateMemoryAllocator("test"));
352 auto* arena = grpc_core::Arena::Create(kArenaSize, &memory_allocator);
353 grpc_core::ManualConstructor<grpc_metadata_batch> b;
354 b.Init();
355 p.BeginFrame(&*b, std::numeric_limits<uint32_t>::max(),
356 std::numeric_limits<uint32_t>::max(),
357 grpc_core::HPackParser::Boundary::None,
358 grpc_core::HPackParser::Priority::None,
359 grpc_core::HPackParser::LogInfo{
360 1, grpc_core::HPackParser::LogInfo::kHeaders, false});
361 auto parse_vec = [&p, bitgen = absl::BitGen()](
362 const std::vector<grpc_slice>& slices) mutable {
363 for (size_t i = 0; i < slices.size(); ++i) {
364 auto error =
365 p.Parse(slices[i], i == slices.size() - 1, absl::BitGenRef(bitgen),
366 /*call_tracer=*/nullptr);
367 GPR_ASSERT(error.ok());
368 }
369 };
370 parse_vec(init_slices);
371 while (state.KeepRunning()) {
372 b->Clear();
373 parse_vec(benchmark_slices);
374 grpc_core::ExecCtx::Get()->Flush();
375 // Recreate arena every 4k iterations to avoid oom
376 if (0 == (state.iterations() & 0xfff)) {
377 b.Destroy();
378 arena->Destroy();
379 arena = grpc_core::Arena::Create(kArenaSize, &memory_allocator);
380 b.Init();
381 p.BeginFrame(&*b, std::numeric_limits<uint32_t>::max(),
382 std::numeric_limits<uint32_t>::max(),
383 grpc_core::HPackParser::Boundary::None,
384 grpc_core::HPackParser::Priority::None,
385 grpc_core::HPackParser::LogInfo{
386 1, grpc_core::HPackParser::LogInfo::kHeaders, false});
387 }
388 }
389 // Clean up
390 b.Destroy();
391 for (auto slice : init_slices) grpc_slice_unref(slice);
392 for (auto slice : benchmark_slices) grpc_slice_unref(slice);
393 arena->Destroy();
394 }
395
396 namespace hpack_parser_fixtures {
397
398 template <class EncoderFixture>
399 class FromEncoderFixture {
400 public:
GetInitSlices()401 static std::vector<grpc_slice> GetInitSlices() { return Generate(0); }
GetBenchmarkSlices()402 static std::vector<grpc_slice> GetBenchmarkSlices() { return Generate(1); }
403
404 private:
Generate(int iteration)405 static std::vector<grpc_slice> Generate(int iteration) {
406 grpc_core::ExecCtx exec_ctx;
407
408 grpc_core::MemoryAllocator memory_allocator =
409 grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
410 ->memory_quota()
411 ->CreateMemoryAllocator("test"));
412 auto arena = grpc_core::MakeScopedArena(1024, &memory_allocator);
413 grpc_metadata_batch b;
414 EncoderFixture::Prepare(&b);
415
416 grpc_core::HPackCompressor c;
417 grpc_transport_one_way_stats stats;
418 std::vector<grpc_slice> out;
419 stats = {};
420 bool done = false;
421 int i = 0;
422 while (!done) {
423 grpc_slice_buffer outbuf;
424 grpc_slice_buffer_init(&outbuf);
425 c.EncodeHeaders(
426 grpc_core::HPackCompressor::EncodeHeaderOptions{
427 static_cast<uint32_t>(i),
428 false,
429 EncoderFixture::kEnableTrueBinary,
430 1024 * 1024,
431 &stats,
432 },
433 b, &outbuf);
434 if (i == iteration) {
435 for (size_t s = 0; s < outbuf.count; s++) {
436 out.push_back(grpc_slice_ref(outbuf.slices[s]));
437 }
438 done = true;
439 }
440 grpc_slice_buffer_reset_and_unref(&outbuf);
441 grpc_core::ExecCtx::Get()->Flush();
442 grpc_slice_buffer_destroy(&outbuf);
443 i++;
444 }
445 // Remove the HTTP header.
446 GPR_ASSERT(!out.empty());
447 GPR_ASSERT(GRPC_SLICE_LENGTH(out[0]) > 9);
448 out[0] = grpc_slice_sub_no_ref(out[0], 9, GRPC_SLICE_LENGTH(out[0]));
449 return out;
450 }
451 };
452
453 class EmptyBatch {
454 public:
GetInitSlices()455 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()456 static std::vector<grpc_slice> GetBenchmarkSlices() {
457 return {MakeSlice({})};
458 }
459 };
460
461 class IndexedSingleStaticElem {
462 public:
GetInitSlices()463 static std::vector<grpc_slice> GetInitSlices() {
464 return {MakeSlice(
465 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
466 }
GetBenchmarkSlices()467 static std::vector<grpc_slice> GetBenchmarkSlices() {
468 return {MakeSlice({0xbe})};
469 }
470 };
471
472 class AddIndexedSingleStaticElem {
473 public:
GetInitSlices()474 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()475 static std::vector<grpc_slice> GetBenchmarkSlices() {
476 return {MakeSlice(
477 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
478 }
479 };
480
481 class KeyIndexedSingleStaticElem {
482 public:
GetInitSlices()483 static std::vector<grpc_slice> GetInitSlices() {
484 return {MakeSlice(
485 {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
486 }
GetBenchmarkSlices()487 static std::vector<grpc_slice> GetBenchmarkSlices() {
488 return {MakeSlice({0x7e, 0x03, '4', '0', '4'})};
489 }
490 };
491
492 class IndexedSingleInternedElem {
493 public:
GetInitSlices()494 static std::vector<grpc_slice> GetInitSlices() {
495 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
496 }
GetBenchmarkSlices()497 static std::vector<grpc_slice> GetBenchmarkSlices() {
498 return {MakeSlice({0xbe})};
499 }
500 };
501
502 class AddIndexedSingleInternedElem {
503 public:
GetInitSlices()504 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()505 static std::vector<grpc_slice> GetBenchmarkSlices() {
506 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
507 }
508 };
509
510 class KeyIndexedSingleInternedElem {
511 public:
GetInitSlices()512 static std::vector<grpc_slice> GetInitSlices() {
513 return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
514 }
GetBenchmarkSlices()515 static std::vector<grpc_slice> GetBenchmarkSlices() {
516 return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
517 }
518 };
519
520 class NonIndexedElem {
521 public:
GetInitSlices()522 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()523 static std::vector<grpc_slice> GetBenchmarkSlices() {
524 return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
525 }
526 };
527
528 template <int kLength, bool kTrueBinary>
529 class NonIndexedBinaryElem;
530
531 template <int kLength>
532 class NonIndexedBinaryElem<kLength, true> {
533 public:
GetInitSlices()534 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()535 static std::vector<grpc_slice> GetBenchmarkSlices() {
536 std::vector<uint8_t> v = {
537 0x00, 0x07, 'a', 'b', 'c',
538 '-', 'b', 'i', 'n', static_cast<uint8_t>(kLength + 1),
539 0};
540 for (int i = 0; i < kLength; i++) {
541 v.push_back(static_cast<uint8_t>(i));
542 }
543 return {MakeSlice(v)};
544 }
545 };
546
547 template <>
548 class NonIndexedBinaryElem<1, false> {
549 public:
GetInitSlices()550 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()551 static std::vector<grpc_slice> GetBenchmarkSlices() {
552 return {MakeSlice(
553 {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x82, 0xf7, 0xb3})};
554 }
555 };
556
557 template <>
558 class NonIndexedBinaryElem<3, false> {
559 public:
GetInitSlices()560 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()561 static std::vector<grpc_slice> GetBenchmarkSlices() {
562 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0x84,
563 0x7f, 0x4e, 0x29, 0x3f})};
564 }
565 };
566
567 template <>
568 class NonIndexedBinaryElem<10, false> {
569 public:
GetInitSlices()570 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()571 static std::vector<grpc_slice> GetBenchmarkSlices() {
572 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b',
573 'i', 'n', 0x8b, 0x71, 0x0c, 0xa5, 0x81,
574 0x73, 0x7b, 0x47, 0x13, 0xe9, 0xf7, 0xe3})};
575 }
576 };
577
578 template <>
579 class NonIndexedBinaryElem<31, false> {
580 public:
GetInitSlices()581 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()582 static std::vector<grpc_slice> GetBenchmarkSlices() {
583 return {MakeSlice({0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n',
584 0xa3, 0x92, 0x43, 0x7f, 0xbe, 0x7c, 0xea, 0x6f, 0xf3,
585 0x3d, 0xa7, 0xa7, 0x67, 0xfb, 0xe2, 0x82, 0xf7, 0xf2,
586 0x8f, 0x1f, 0x9d, 0xdf, 0xf1, 0x7e, 0xb3, 0xef, 0xb2,
587 0x8f, 0x53, 0x77, 0xce, 0x0c, 0x13, 0xe3, 0xfd, 0x87})};
588 }
589 };
590
591 template <>
592 class NonIndexedBinaryElem<100, false> {
593 public:
GetInitSlices()594 static std::vector<grpc_slice> GetInitSlices() { return {}; }
GetBenchmarkSlices()595 static std::vector<grpc_slice> GetBenchmarkSlices() {
596 return {MakeSlice(
597 {0x00, 0x07, 'a', 'b', 'c', '-', 'b', 'i', 'n', 0xeb, 0x1d, 0x4d,
598 0xe8, 0x96, 0x8c, 0x14, 0x20, 0x06, 0xc1, 0xc3, 0xdf, 0x6e, 0x1f, 0xef,
599 0xde, 0x2f, 0xde, 0xb7, 0xf2, 0xfe, 0x6d, 0xd4, 0xe4, 0x7d, 0xf5, 0x55,
600 0x46, 0x52, 0x3d, 0x91, 0xf2, 0xd4, 0x6f, 0xca, 0x34, 0xcd, 0xd9, 0x39,
601 0xbd, 0x03, 0x27, 0xe3, 0x9c, 0x74, 0xcc, 0x17, 0x34, 0xed, 0xa6, 0x6a,
602 0x77, 0x73, 0x10, 0xcd, 0x8e, 0x4e, 0x5c, 0x7c, 0x72, 0x39, 0xd8, 0xe6,
603 0x78, 0x6b, 0xdb, 0xa5, 0xb7, 0xab, 0xe7, 0x46, 0xae, 0x21, 0xab, 0x7f,
604 0x01, 0x89, 0x13, 0xd7, 0xca, 0x17, 0x6e, 0xcb, 0xd6, 0x79, 0x71, 0x68,
605 0xbf, 0x8a, 0x3f, 0x32, 0xe8, 0xba, 0xf5, 0xbe, 0xb3, 0xbc, 0xde, 0x28,
606 0xc7, 0xcf, 0x62, 0x7a, 0x58, 0x2c, 0xcf, 0x4d, 0xe3})};
607 }
608 };
609
610 using RepresentativeClientInitialMetadata = FromEncoderFixture<
611 hpack_encoder_fixtures::RepresentativeClientInitialMetadata>;
612 using RepresentativeServerInitialMetadata = FromEncoderFixture<
613 hpack_encoder_fixtures::RepresentativeServerInitialMetadata>;
614 using RepresentativeServerTrailingMetadata = FromEncoderFixture<
615 hpack_encoder_fixtures::RepresentativeServerTrailingMetadata>;
616 using MoreRepresentativeClientInitialMetadata = FromEncoderFixture<
617 hpack_encoder_fixtures::MoreRepresentativeClientInitialMetadata>;
618
619 // Send the same deadline repeatedly
620 class SameDeadline {
621 public:
GetInitSlices()622 static std::vector<grpc_slice> GetInitSlices() {
623 return {
624 grpc_slice_from_static_string("@\x0cgrpc-timeout\x03"
625 "30S")};
626 }
GetBenchmarkSlices()627 static std::vector<grpc_slice> GetBenchmarkSlices() {
628 // Use saved key and literal value.
629 return {MakeSlice({0x0f, 0x2f, 0x03, '3', '0', 'S'})};
630 }
631 };
632
633 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch);
634 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem);
635 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem);
636 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem);
637 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem);
638 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem);
639 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem);
640 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem);
641 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, false>);
642 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, false>);
643 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, false>);
644 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, false>);
645 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, false>);
646 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, true>);
647 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, true>);
648 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, true>);
649 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>);
650 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>);
651 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
652 RepresentativeClientInitialMetadata);
653 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
654 MoreRepresentativeClientInitialMetadata);
655 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
656 RepresentativeServerInitialMetadata);
657 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
658 RepresentativeServerTrailingMetadata);
659 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
660 RepresentativeClientInitialMetadata);
661 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
662 MoreRepresentativeClientInitialMetadata);
663 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
664 RepresentativeServerInitialMetadata);
665 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline);
666
667 } // namespace hpack_parser_fixtures
668
669 // Some distros have RunSpecifiedBenchmarks under the benchmark namespace,
670 // and others do not. This allows us to support both modes.
671 namespace benchmark {
RunTheBenchmarksNamespaced()672 void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); }
673 } // namespace benchmark
674
main(int argc,char ** argv)675 int main(int argc, char** argv) {
676 grpc::testing::TestEnvironment env(&argc, argv);
677 LibraryInitializer libInit;
678 ::benchmark::Initialize(&argc, argv);
679 grpc::testing::InitTest(&argc, &argv, false);
680 benchmark::RunTheBenchmarksNamespaced();
681 return 0;
682 }
683