• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 // Microbenchmarks around CHTTP2 HPACK operations
20 
21 #include <benchmark/benchmark.h>
22 #include <grpc/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