From 0db30f3dd0f14d02fa1ace4208e8c977807a3898 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Feb 2017 08:48:34 -0800 Subject: [PATCH] HPACK parsing benchmarks --- test/cpp/microbenchmarks/bm_chttp2.cc | 143 +++++++++++++++++- ...esentative_server_initial_metadata.headers | 4 + ...sentative_server_trailing_metadata.headers | 3 + tools/codegen/core/gen_header_frame.py | 95 ++++++++---- 4 files changed, 214 insertions(+), 31 deletions(-) create mode 100644 test/cpp/microbenchmarks/representative_server_initial_metadata.headers create mode 100644 test/cpp/microbenchmarks/representative_server_trailing_metadata.headers diff --git a/test/cpp/microbenchmarks/bm_chttp2.cc b/test/cpp/microbenchmarks/bm_chttp2.cc index fa3d84cf800..10bccdfcee5 100644 --- a/test/cpp/microbenchmarks/bm_chttp2.cc +++ b/test/cpp/microbenchmarks/bm_chttp2.cc @@ -283,20 +283,159 @@ class IndexedSingleStaticElem { } }; -class IndexedSingleInternedElem { +class AddIndexedSingleStaticElem { + public: + static std::vector GetInitSlices() { return {}; } + static std::vector GetBenchmarkSlices() { + return {MakeSlice( + {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})}; + } +}; + +class KeyIndexedSingleStaticElem { public: static std::vector 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 GetBenchmarkSlices() { + return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})}; + } +}; + +class IndexedSingleInternedElem { + public: + static std::vector GetInitSlices() { + return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})}; } static std::vector GetBenchmarkSlices() { return {MakeSlice({0xbe})}; } }; +class AddIndexedSingleInternedElem { + public: + static std::vector GetInitSlices() { return {}; } + static std::vector GetBenchmarkSlices() { + return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})}; + } +}; + +class KeyIndexedSingleInternedElem { + public: + static std::vector GetInitSlices() { + return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})}; + } + static std::vector GetBenchmarkSlices() { + return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})}; + } +}; + +class NonIndexedElem { + public: + static std::vector GetInitSlices() { return {}; } + static std::vector GetBenchmarkSlices() { + return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})}; + } +}; + +class RepresentativeClientInitialMetadata { + public: + static std::vector 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 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 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 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 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 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 00000000000..d3e69333668 --- /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 00000000000..544d0898539 --- /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 ee476267f23..c92ff3c579d 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 @@ for line in sys.stdin: 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 @@ def esc_c(line): 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)