HPACK parsing benchmarks
diff --git a/test/cpp/microbenchmarks/bm_chttp2.cc b/test/cpp/microbenchmarks/bm_chttp2.cc
index fa3d84c..10bccdf 100644
--- a/test/cpp/microbenchmarks/bm_chttp2.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2.cc
@@ -283,20 +283,159 @@
}
};
-class IndexedSingleInternedElem {
+class AddIndexedSingleStaticElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice(
+ {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
+ }
+};
+
+class KeyIndexedSingleStaticElem {
public:
static std::vector<grpc_slice> GetInitSlices() {
return {MakeSlice(
- {0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class IndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
}
static std::vector<grpc_slice> GetBenchmarkSlices() {
return {MakeSlice({0xbe})};
}
};
+class AddIndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class KeyIndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
+ }
+};
+
+class NonIndexedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class RepresentativeClientInitialMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // < test/core/bad_client/tests/simple_request.headers
+ // ```
+ "@\x05:path\x08/foo/bar"
+ "@\x07:scheme\x04http"
+ "@\x07:method\x04POST"
+ "@\x0a:authority\x09localhost"
+ "@\x0c"
+ "content-type\x10"
+ "application/grpc"
+ "@\x14grpc-accept-encoding\x15identity,deflate,gzip"
+ "@\x02te\x08trailers"
+ "@\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex < test/core/bad_client/tests/simple_request.headers
+ // ```
+ return {MakeSlice({0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe})};
+ }
+};
+
+class RepresentativeServerInitialMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // <
+ // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
+ // ```
+ "@\x07:status\x03"
+ "200"
+ "@\x0c"
+ "content-type\x10"
+ "application/grpc"
+ "@\x14grpc-accept-encoding\x15identity,deflate,gzip")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex <
+ // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
+ // ```
+ return {MakeSlice({0xc0, 0xbf, 0xbe})};
+ }
+};
+
+class RepresentativeServerTrailingMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // <
+ // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
+ // ```
+ "@\x0bgrpc-status\x01"
+ "0"
+ "@\x0cgrpc-message\x00")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex <
+ // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
+ // ```
+ return {MakeSlice({0xbf, 0xbe})};
+ }
+};
+
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeClientInitialMetadata);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerInitialMetadata);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerTrailingMetadata);
} // namespace hpack_parser_fixtures
diff --git a/test/cpp/microbenchmarks/representative_server_initial_metadata.headers b/test/cpp/microbenchmarks/representative_server_initial_metadata.headers
new file mode 100644
index 0000000..d3e6933
--- /dev/null
+++ b/test/cpp/microbenchmarks/representative_server_initial_metadata.headers
@@ -0,0 +1,4 @@
+:status: 200
+content-type: application/grpc
+grpc-accept-encoding: identity,deflate,gzip
+
diff --git a/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers b/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
new file mode 100644
index 0000000..544d089
--- /dev/null
+++ b/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
@@ -0,0 +1,3 @@
+grpc-status: 0
+grpc-message:
+
diff --git a/tools/codegen/core/gen_header_frame.py b/tools/codegen/core/gen_header_frame.py
index ee47626..c92ff3c 100755
--- a/tools/codegen/core/gen_header_frame.py
+++ b/tools/codegen/core/gen_header_frame.py
@@ -37,8 +37,41 @@
import json
import sys
+import argparse
-set_end_stream = len(sys.argv) > 1 and sys.argv[1] == '--set_end_stream'
+def append_never_indexed(payload_line, n, count, key, value):
+ payload_line.append(0x10)
+ assert(len(key) <= 126)
+ payload_line.append(len(key))
+ payload_line.extend(ord(c) for c in key)
+ assert(len(value) <= 126)
+ payload_line.append(len(value))
+ payload_line.extend(ord(c) for c in value)
+
+def append_inc_indexed(payload_line, n, count, key, value):
+ payload_line.append(0x40)
+ assert(len(key) <= 126)
+ payload_line.append(len(key))
+ payload_line.extend(ord(c) for c in key)
+ assert(len(value) <= 126)
+ payload_line.append(len(value))
+ payload_line.extend(ord(c) for c in value)
+
+def append_pre_indexed(payload_line, n, count, key, value):
+ payload_line.append(0x80 + 61 + count - n)
+
+_COMPRESSORS = {
+ 'never': append_never_indexed,
+ 'inc': append_inc_indexed,
+ 'pre': append_pre_indexed,
+}
+
+argp = argparse.ArgumentParser('Generate header frames')
+argp.add_argument('--set_end_stream', default=False, action='store_const', const=True)
+argp.add_argument('--no_framing', default=False, action='store_const', const=True)
+argp.add_argument('--compression', choices=sorted(_COMPRESSORS.keys()), default='never')
+argp.add_argument('--hex', default=False, action='store_const', const=True)
+args = argp.parse_args()
# parse input, fill in vals
vals = []
@@ -52,38 +85,37 @@
vals.append((key, value))
# generate frame payload binary data
-payload_bytes = [[]] # reserve space for header
+payload_bytes = []
+if not args.no_framing:
+ payload_bytes.append([]) # reserve space for header
payload_len = 0
+n = 0
for key, value in vals:
payload_line = []
- payload_line.append(0x10)
- assert(len(key) <= 126)
- payload_line.append(len(key))
- payload_line.extend(ord(c) for c in key)
- assert(len(value) <= 126)
- payload_line.append(len(value))
- payload_line.extend(ord(c) for c in value)
+ _COMPRESSORS[args.compression](payload_line, n, len(vals), key, value)
+ n += 1
payload_len += len(payload_line)
payload_bytes.append(payload_line)
# fill in header
-flags = 0x04 # END_HEADERS
-if set_end_stream:
- flags |= 0x01 # END_STREAM
-payload_bytes[0].extend([
- (payload_len >> 16) & 0xff,
- (payload_len >> 8) & 0xff,
- (payload_len) & 0xff,
- # header frame
- 0x01,
- # flags
- flags,
- # stream id
- 0x00,
- 0x00,
- 0x00,
- 0x01
-])
+if not args.no_framing:
+ flags = 0x04 # END_HEADERS
+ if args.set_end_stream:
+ flags |= 0x01 # END_STREAM
+ payload_bytes[0].extend([
+ (payload_len >> 16) & 0xff,
+ (payload_len >> 8) & 0xff,
+ (payload_len) & 0xff,
+ # header frame
+ 0x01,
+ # flags
+ flags,
+ # stream id
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x01
+ ])
hex_bytes = [ord(c) for c in "abcdefABCDEF0123456789"]
@@ -105,6 +137,11 @@
return out + "\""
# dump bytes
-for line in payload_bytes:
- print esc_c(line)
-
+if args.hex:
+ all_bytes = []
+ for line in payload_bytes:
+ all_bytes.extend(line)
+ print '{%s}' % ', '.join('0x%02x' % c for c in all_bytes)
+else:
+ for line in payload_bytes:
+ print esc_c(line)