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)