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