Merge pull request #12525 from vjpai/fc_limits

Fix headers on flow control
diff --git a/.gitignore b/.gitignore
index 5e38f5f..5ccad2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,7 @@
 dist/
 *.egg
 py27/
-py34/
+py3[0-9]*/
 
 # Node installation output
 node_modules
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
index 0d71f35..2e2b411 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
@@ -174,7 +174,7 @@
           grpc_lb_addresses_set_address(
               *lb_addresses, i, &addr, addr_len,
               hr->is_balancer /* is_balancer */,
-              hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */,
+              hr->is_balancer ? hr->host : NULL /* balancer_name */,
               NULL /* user_data */);
           char output[INET6_ADDRSTRLEN];
           ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN);
@@ -195,7 +195,7 @@
           grpc_lb_addresses_set_address(
               *lb_addresses, i, &addr, addr_len,
               hr->is_balancer /* is_balancer */,
-              hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */,
+              hr->is_balancer ? hr->host : NULL /* balancer_name */,
               NULL /* user_data */);
           char output[INET_ADDRSTRLEN];
           ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN);
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index fa224a4..3fa38db 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -391,6 +391,8 @@
                                                     s->id, GRPC_HTTP2_NO_ERROR,
                                                     &s->stats.outgoing));
             }
+            grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1,
+                                           GRPC_ERROR_NONE);
           }
           result.early_results_scheduled |=
               update_list(exec_ctx, t, s,
@@ -449,6 +451,8 @@
               &t->outbuf, grpc_chttp2_rst_stream_create(
                               s->id, GRPC_HTTP2_NO_ERROR, &s->stats.outgoing));
         }
+        grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1,
+                                       GRPC_ERROR_NONE);
         now_writing = true;
         result.early_results_scheduled = true;
         grpc_chttp2_complete_closure_step(
@@ -519,10 +523,6 @@
                   GRPC_ERROR_REF(error));
       s->sending_bytes = 0;
     }
-    if (s->sent_trailing_metadata) {
-      grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1,
-                                     GRPC_ERROR_REF(error));
-    }
     GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end");
   }
   grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &t->outbuf);
diff --git a/src/core/lib/debug/stats_data_bq_schema.sql b/src/core/lib/debug/stats_data_bq_schema.sql
index b669555..7291bbf 100644
--- a/src/core/lib/debug/stats_data_bq_schema.sql
+++ b/src/core/lib/debug/stats_data_bq_schema.sql
@@ -30,4 +30,6 @@
 executor_scheduled_to_self_per_iteration:INTEGER,
 executor_wakeup_initiated_per_iteration:INTEGER,
 executor_queue_drained_per_iteration:INTEGER,
-executor_push_retries_per_iteration:INTEGER
+executor_push_retries_per_iteration:INTEGER,
+server_requested_calls_per_iteration:INTEGER,
+server_slowpath_requests_queued_per_iteration:INTEGER
diff --git a/tools/buildgen/generate_projects.py b/tools/buildgen/generate_projects.py
index 559ea16..d29cd02 100755
--- a/tools/buildgen/generate_projects.py
+++ b/tools/buildgen/generate_projects.py
@@ -85,7 +85,7 @@
       test[out] = tf[1]
       os.close(tf[0])
       cmd.append(test[out])
-    cmd.append(root + '/' + f)
+    cmd.append(args.base + '/' + root + '/' + f)
     jobs.append(jobset.JobSpec(cmd, shortname=out, timeout_seconds=None))
 
 jobset.run(pre_jobs, maxjobs=args.jobs)
diff --git a/tools/codegen/core/gen_stats_data.py b/tools/codegen/core/gen_stats_data.py
index cb01321..877a5d9 100755
--- a/tools/codegen/core/gen_stats_data.py
+++ b/tools/codegen/core/gen_stats_data.py
@@ -314,8 +314,97 @@
   print >>C, "void (*const grpc_stats_inc_histogram[%d])(grpc_exec_ctx *exec_ctx, int x) = {%s};" % (
       len(inst_map['Histogram']), ','.join('grpc_stats_inc_%s' % histogram.name.lower() for histogram in inst_map['Histogram']))
 
+# patch qps_test bigquery schema
+RECORD_EXPLICIT_PERCENTILES = [50, 95, 99]
+
+with open('tools/run_tests/performance/scenario_result_schema.json', 'r') as f:
+  qps_schema = json.loads(f.read())
+
+def FindNamed(js, name):
+  for el in js:
+    if el['name'] == name:
+      return el
+
+def RemoveCoreFields(js):
+  new_fields = []
+  for field in js['fields']:
+    if not field['name'].startswith('core_'):
+      new_fields.append(field)
+  js['fields'] = new_fields
+
+RemoveCoreFields(FindNamed(qps_schema, 'clientStats'))
+RemoveCoreFields(FindNamed(qps_schema, 'serverStats'))
+
+def AddCoreFields(js):
+  for counter in inst_map['Counter']:
+    js['fields'].append({
+      'name': 'core_%s' % counter.name,
+      'type': 'INTEGER',
+      'mode': 'NULLABLE'
+    })
+  for histogram in inst_map['Histogram']:
+    js['fields'].append({
+      'name': 'core_%s' % histogram.name,
+      'type': 'STRING',
+      'mode': 'NULLABLE'
+    })
+    js['fields'].append({
+      'name': 'core_%s_bkts' % histogram.name,
+      'type': 'STRING',
+      'mode': 'NULLABLE'
+    })
+    for pctl in RECORD_EXPLICIT_PERCENTILES:
+      js['fields'].append({
+        'name': 'core_%s_%dp' % (histogram.name, pctl),
+        'type': 'FLOAT',
+        'mode': 'NULLABLE'
+      })
+
+AddCoreFields(FindNamed(qps_schema, 'clientStats'))
+AddCoreFields(FindNamed(qps_schema, 'serverStats'))
+
+with open('tools/run_tests/performance/scenario_result_schema.json', 'w') as f:
+  f.write(json.dumps(qps_schema, indent=2, sort_keys=True))
+
+# and generate a helper script to massage scenario results into the format we'd
+# like to query
+with open('tools/run_tests/performance/massage_qps_stats.py', 'w') as P:
+  with open(sys.argv[0]) as my_source:
+    for line in my_source:
+      if line[0] != '#': break
+    for line in my_source:
+      if line[0] == '#':
+        print >>P, line.rstrip()
+        break
+    for line in my_source:
+      if line[0] != '#':
+        break
+      print >>P, line.rstrip()
+
+  print >>P
+  print >>P, '# Autogenerated by tools/codegen/core/gen_stats_data.py'
+  print >>P
+
+  print >>P, 'import massage_qps_stats_helpers'
+
+  print >>P, 'def massage_qps_stats(scenario_result):'
+  print >>P, '  for stats in scenario_result["serverStats"] + scenario_result["clientStats"]:'
+  print >>P, '    if "coreStats" not in stats: return'
+  print >>P, '    core_stats = stats["coreStats"]'
+  print >>P, '    del stats["coreStats"]'
+  for counter in inst_map['Counter']:
+    print >>P, '    stats["core_%s"] = massage_qps_stats_helpers.counter(core_stats, "%s")' % (counter.name, counter.name)
+  for i, histogram in enumerate(inst_map['Histogram']):
+    print >>P, '    h = massage_qps_stats_helpers.histogram(core_stats, "%s")' % histogram.name
+    print >>P, '    stats["core_%s"] = ",".join("%%f" %% x for x in h.buckets)' % histogram.name
+    print >>P, '    stats["core_%s_bkts"] = ",".join("%%f" %% x for x in h.boundaries)' % histogram.name
+    for pctl in RECORD_EXPLICIT_PERCENTILES:
+      print >>P, '    stats["core_%s_%dp"] = massage_qps_stats_helpers.percentile(h.buckets, %d, h.boundaries)' % (
+          histogram.name, pctl, pctl)
+
 with open('src/core/lib/debug/stats_data_bq_schema.sql', 'w') as S:
   columns = []
   for counter in inst_map['Counter']:
     columns.append(('%s_per_iteration' % counter.name, 'INTEGER'))
   print >>S, ',\n'.join('%s:%s' % x for x in columns)
+
diff --git a/tools/run_tests/performance/bq_upload_result.py b/tools/run_tests/performance/bq_upload_result.py
index 630ac23..31819d6 100755
--- a/tools/run_tests/performance/bq_upload_result.py
+++ b/tools/run_tests/performance/bq_upload_result.py
@@ -24,6 +24,7 @@
 import sys
 import time
 import uuid
+import massage_qps_stats
 
 
 gcp_utils_dir = os.path.abspath(os.path.join(
@@ -117,6 +118,7 @@
   scenario_result['serverCpuUsage'] = scenario_result['summary'].pop('serverCpuUsage', None)
   scenario_result['summary'].pop('successfulRequestsPerSecond', None)
   scenario_result['summary'].pop('failedRequestsPerSecond', None)
+  massage_qps_stats.massage_qps_stats(scenario_result)
 
 
 def _populate_metadata_inplace(scenario_result):
diff --git a/tools/run_tests/performance/massage_qps_stats.py b/tools/run_tests/performance/massage_qps_stats.py
new file mode 100644
index 0000000..30a94ca
--- /dev/null
+++ b/tools/run_tests/performance/massage_qps_stats.py
@@ -0,0 +1,123 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Autogenerated by tools/codegen/core/gen_stats_data.py
+
+import massage_qps_stats_helpers
+def massage_qps_stats(scenario_result):
+  for stats in scenario_result["serverStats"] + scenario_result["clientStats"]:
+    if "coreStats" not in stats: return
+    core_stats = stats["coreStats"]
+    del stats["coreStats"]
+    stats["core_client_calls_created"] = massage_qps_stats_helpers.counter(core_stats, "client_calls_created")
+    stats["core_server_calls_created"] = massage_qps_stats_helpers.counter(core_stats, "server_calls_created")
+    stats["core_syscall_poll"] = massage_qps_stats_helpers.counter(core_stats, "syscall_poll")
+    stats["core_syscall_wait"] = massage_qps_stats_helpers.counter(core_stats, "syscall_wait")
+    stats["core_histogram_slow_lookups"] = massage_qps_stats_helpers.counter(core_stats, "histogram_slow_lookups")
+    stats["core_syscall_write"] = massage_qps_stats_helpers.counter(core_stats, "syscall_write")
+    stats["core_syscall_read"] = massage_qps_stats_helpers.counter(core_stats, "syscall_read")
+    stats["core_tcp_backup_pollers_created"] = massage_qps_stats_helpers.counter(core_stats, "tcp_backup_pollers_created")
+    stats["core_tcp_backup_poller_polls"] = massage_qps_stats_helpers.counter(core_stats, "tcp_backup_poller_polls")
+    stats["core_http2_op_batches"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_batches")
+    stats["core_http2_op_cancel"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_cancel")
+    stats["core_http2_op_send_initial_metadata"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_send_initial_metadata")
+    stats["core_http2_op_send_message"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_send_message")
+    stats["core_http2_op_send_trailing_metadata"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_send_trailing_metadata")
+    stats["core_http2_op_recv_initial_metadata"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_recv_initial_metadata")
+    stats["core_http2_op_recv_message"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_recv_message")
+    stats["core_http2_op_recv_trailing_metadata"] = massage_qps_stats_helpers.counter(core_stats, "http2_op_recv_trailing_metadata")
+    stats["core_http2_settings_writes"] = massage_qps_stats_helpers.counter(core_stats, "http2_settings_writes")
+    stats["core_http2_pings_sent"] = massage_qps_stats_helpers.counter(core_stats, "http2_pings_sent")
+    stats["core_http2_writes_begun"] = massage_qps_stats_helpers.counter(core_stats, "http2_writes_begun")
+    stats["core_http2_writes_offloaded"] = massage_qps_stats_helpers.counter(core_stats, "http2_writes_offloaded")
+    stats["core_http2_writes_continued"] = massage_qps_stats_helpers.counter(core_stats, "http2_writes_continued")
+    stats["core_http2_partial_writes"] = massage_qps_stats_helpers.counter(core_stats, "http2_partial_writes")
+    stats["core_combiner_locks_initiated"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_initiated")
+    stats["core_combiner_locks_scheduled_items"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_scheduled_items")
+    stats["core_combiner_locks_scheduled_final_items"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_scheduled_final_items")
+    stats["core_combiner_locks_offloaded"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_offloaded")
+    stats["core_executor_scheduled_short_items"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_short_items")
+    stats["core_executor_scheduled_long_items"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_long_items")
+    stats["core_executor_scheduled_to_self"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_to_self")
+    stats["core_executor_wakeup_initiated"] = massage_qps_stats_helpers.counter(core_stats, "executor_wakeup_initiated")
+    stats["core_executor_queue_drained"] = massage_qps_stats_helpers.counter(core_stats, "executor_queue_drained")
+    stats["core_executor_push_retries"] = massage_qps_stats_helpers.counter(core_stats, "executor_push_retries")
+    stats["core_server_requested_calls"] = massage_qps_stats_helpers.counter(core_stats, "server_requested_calls")
+    stats["core_server_slowpath_requests_queued"] = massage_qps_stats_helpers.counter(core_stats, "server_slowpath_requests_queued")
+    h = massage_qps_stats_helpers.histogram(core_stats, "tcp_write_size")
+    stats["core_tcp_write_size"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_tcp_write_size_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_tcp_write_size_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_tcp_write_size_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_tcp_write_size_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "tcp_write_iov_size")
+    stats["core_tcp_write_iov_size"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_tcp_write_iov_size_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_tcp_write_iov_size_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_tcp_write_iov_size_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_tcp_write_iov_size_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "tcp_read_size")
+    stats["core_tcp_read_size"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_tcp_read_size_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_tcp_read_size_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_tcp_read_size_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_tcp_read_size_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "tcp_read_offer")
+    stats["core_tcp_read_offer"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_tcp_read_offer_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_tcp_read_offer_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_tcp_read_offer_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_tcp_read_offer_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "tcp_read_offer_iov_size")
+    stats["core_tcp_read_offer_iov_size"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_tcp_read_offer_iov_size_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_tcp_read_offer_iov_size_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_tcp_read_offer_iov_size_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_tcp_read_offer_iov_size_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "http2_send_message_size")
+    stats["core_http2_send_message_size"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_http2_send_message_size_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_http2_send_message_size_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_http2_send_message_size_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_http2_send_message_size_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "http2_send_initial_metadata_per_write")
+    stats["core_http2_send_initial_metadata_per_write"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_http2_send_initial_metadata_per_write_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_http2_send_initial_metadata_per_write_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_http2_send_initial_metadata_per_write_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_http2_send_initial_metadata_per_write_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "http2_send_message_per_write")
+    stats["core_http2_send_message_per_write"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_http2_send_message_per_write_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_http2_send_message_per_write_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_http2_send_message_per_write_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_http2_send_message_per_write_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "http2_send_trailing_metadata_per_write")
+    stats["core_http2_send_trailing_metadata_per_write"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_http2_send_trailing_metadata_per_write_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_http2_send_trailing_metadata_per_write_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_http2_send_trailing_metadata_per_write_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_http2_send_trailing_metadata_per_write_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "http2_send_flowctl_per_write")
+    stats["core_http2_send_flowctl_per_write"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_http2_send_flowctl_per_write_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_http2_send_flowctl_per_write_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_http2_send_flowctl_per_write_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_http2_send_flowctl_per_write_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
+    h = massage_qps_stats_helpers.histogram(core_stats, "server_cqs_checked")
+    stats["core_server_cqs_checked"] = ",".join("%f" % x for x in h.buckets)
+    stats["core_server_cqs_checked_bkts"] = ",".join("%f" % x for x in h.boundaries)
+    stats["core_server_cqs_checked_50p"] = massage_qps_stats_helpers.percentile(h.buckets, 50, h.boundaries)
+    stats["core_server_cqs_checked_95p"] = massage_qps_stats_helpers.percentile(h.buckets, 95, h.boundaries)
+    stats["core_server_cqs_checked_99p"] = massage_qps_stats_helpers.percentile(h.buckets, 99, h.boundaries)
diff --git a/tools/run_tests/performance/massage_qps_stats_helpers.py b/tools/run_tests/performance/massage_qps_stats_helpers.py
new file mode 100644
index 0000000..400a0c8
--- /dev/null
+++ b/tools/run_tests/performance/massage_qps_stats_helpers.py
@@ -0,0 +1,57 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+
+def _threshold_for_count_below(buckets, boundaries, count_below):
+  count_so_far = 0
+  for lower_idx in range(0, len(buckets)):
+    count_so_far += buckets[lower_idx]
+    if count_so_far >= count_below:
+      break
+  if count_so_far == count_below:
+    # this bucket hits the threshold exactly... we should be midway through
+    # any run of zero values following the bucket
+    for upper_idx in range(lower_idx + 1, num_buckets):
+      if buckets[upper_idx] != 0:
+        break
+    return (boundaries[lower_idx] + boundaries[upper_idx]) / 2.0
+  else:
+    # treat values as uniform throughout the bucket, and find where this value
+    # should lie
+    lower_bound = boundaries[lower_idx]
+    upper_bound = boundaries[lower_idx + 1]
+    return (upper_bound -
+           (upper_bound - lower_bound) * (count_so_far - count_below) /
+               float(buckets[lower_idx]))
+
+def percentile(buckets, pctl, boundaries):
+  return _threshold_for_count_below(
+      buckets, boundaries, sum(buckets) * pctl / 100.0)
+
+def counter(core_stats, name):
+  for stat in core_stats['metrics']:
+    if stat['name'] == name:
+      return int(stat.get('count', 0))
+
+Histogram = collections.namedtuple('Histogram', 'buckets boundaries')
+def histogram(core_stats, name):
+  for stat in core_stats['metrics']:
+    if stat['name'] == name:
+      buckets = []
+      boundaries = []
+      for b in stat['histogram']['buckets']:
+        buckets.append(int(b.get('count', 0)))
+        boundaries.append(int(b.get('start', 0)))
+  return Histogram(buckets=buckets, boundaries=boundaries)
diff --git a/tools/run_tests/performance/scenario_result_schema.json b/tools/run_tests/performance/scenario_result_schema.json
index d7e2e29..84b3cb7 100644
--- a/tools/run_tests/performance/scenario_result_schema.json
+++ b/tools/run_tests/performance/scenario_result_schema.json
@@ -1,269 +1,1169 @@
 [
   {
-    "name": "metadata",
-    "type": "RECORD",
-    "mode": "NULLABLE",
     "fields": [
       {
-        "name": "buildNumber",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "buildNumber", 
+        "type": "INTEGER"
+      }, 
       {
-        "name": "buildUrl",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "buildUrl", 
+        "type": "STRING"
+      }, 
       {
-        "name": "jobName",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "jobName", 
+        "type": "STRING"
+      }, 
       {
-        "name": "gitCommit",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "gitCommit", 
+        "type": "STRING"
+      }, 
       {
-        "name": "gitActualCommit",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "gitActualCommit", 
+        "type": "STRING"
+      }, 
       {
-        "name": "created",
-        "type": "TIMESTAMP",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "created", 
+        "type": "TIMESTAMP"
       }
-    ]
-  },
+    ], 
+    "mode": "NULLABLE", 
+    "name": "metadata", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "scenario",
-    "type": "RECORD",
-    "mode": "NULLABLE",
     "fields": [
       {
-        "name": "name",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "name", 
+        "type": "STRING"
+      }, 
       {
-        "name": "clientConfig",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "clientConfig", 
+        "type": "STRING"
+      }, 
       {
-        "name": "numClients",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "numClients", 
+        "type": "INTEGER"
+      }, 
       {
-        "name": "serverConfig",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "serverConfig", 
+        "type": "STRING"
+      }, 
       {
-        "name": "numServers",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "numServers", 
+        "type": "INTEGER"
+      }, 
       {
-        "name": "warmupSeconds",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "warmupSeconds", 
+        "type": "INTEGER"
+      }, 
       {
-        "name": "benchmarkSeconds",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "benchmarkSeconds", 
+        "type": "INTEGER"
       }
-    ]
-  },
+    ], 
+    "mode": "NULLABLE", 
+    "name": "scenario", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "latencies",
-    "type": "STRING",
-    "mode": "NULLABLE"
-  },
+    "mode": "NULLABLE", 
+    "name": "latencies", 
+    "type": "STRING"
+  }, 
   {
-    "name": "clientStats",
-    "type": "RECORD",
-    "mode": "REPEATED",
     "fields": [
       {
-        "name": "latencies",
-        "type": "STRING",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latencies", 
+        "type": "STRING"
+      }, 
       {
-        "name": "timeElapsed",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeElapsed", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "timeUser",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeUser", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "timeSystem",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeSystem", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "cqPollCount",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "cqPollCount", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_client_calls_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_calls_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_poll", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_wait", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_histogram_slow_lookups", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_write", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_read", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_backup_pollers_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_backup_poller_polls", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_batches", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_cancel", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_initial_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_message", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_trailing_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_initial_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_message", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_trailing_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_settings_writes", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_pings_sent", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_begun", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_offloaded", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_continued", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_partial_writes", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_scheduled_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_scheduled_final_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_offloaded", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_short_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_long_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_to_self", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_wakeup_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_queue_drained", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_push_retries", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_requested_calls", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_slowpath_requests_queued", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_99p", 
+        "type": "FLOAT"
       }
-    ]
-  },
+    ], 
+    "mode": "REPEATED", 
+    "name": "clientStats", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "serverStats",
-    "type": "RECORD",
-    "mode": "REPEATED",
     "fields": [
       {
-        "name": "timeElapsed",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeElapsed", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "timeUser",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeUser", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "timeSystem",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "timeSystem", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "cqPollCount",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "cqPollCount", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_client_calls_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_calls_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_poll", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_wait", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_histogram_slow_lookups", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_write", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_syscall_read", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_backup_pollers_created", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_backup_poller_polls", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_batches", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_cancel", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_initial_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_message", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_send_trailing_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_initial_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_message", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_op_recv_trailing_metadata", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_settings_writes", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_pings_sent", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_begun", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_offloaded", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_writes_continued", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_partial_writes", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_scheduled_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_scheduled_final_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_combiner_locks_offloaded", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_short_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_long_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_scheduled_to_self", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_wakeup_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_queue_drained", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_executor_push_retries", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_requested_calls", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_slowpath_requests_queued", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_write_iov_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_tcp_read_offer_iov_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_size_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_initial_metadata_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_message_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_trailing_metadata_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_http2_send_flowctl_per_write_99p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_bkts", 
+        "type": "STRING"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_50p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_95p", 
+        "type": "FLOAT"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_server_cqs_checked_99p", 
+        "type": "FLOAT"
       }
-    ]
-  },
+    ], 
+    "mode": "REPEATED", 
+    "name": "serverStats", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "serverCores",
-    "type": "STRING",
-    "mode": "NULLABLE"
-  },
+    "mode": "NULLABLE", 
+    "name": "serverCores", 
+    "type": "STRING"
+  }, 
   {
-    "name": "summary",
-    "type": "RECORD",
-    "mode": "NULLABLE",
     "fields": [
       {
-        "name": "qps",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "qps", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "qpsPerServerCore",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "qpsPerServerCore", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "serverSystemTime",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "serverSystemTime", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "serverUserTime",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "serverUserTime", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "clientSystemTime",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "clientSystemTime", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "clientUserTime",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "clientUserTime", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "latency50",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latency50", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "latency90",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latency90", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "latency95",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latency95", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "latency99",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latency99", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "latency999",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "latency999", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "clientPollsPerRequest",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "clientPollsPerRequest", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "serverPollsPerRequest",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "serverPollsPerRequest", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "serverQueriesPerCpuSec",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "serverQueriesPerCpuSec", 
+        "type": "FLOAT"
+      }, 
       {
-        "name": "clientQueriesPerCpuSec",
-        "type": "FLOAT",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "clientQueriesPerCpuSec", 
+        "type": "FLOAT"
       }
-    ]
-  },
+    ], 
+    "mode": "NULLABLE", 
+    "name": "summary", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "clientSuccess",
-    "type": "STRING",
-    "mode": "NULLABLE"
-  },
+    "mode": "NULLABLE", 
+    "name": "clientSuccess", 
+    "type": "STRING"
+  }, 
   {
-    "name": "serverSuccess",
-    "type": "STRING",
-    "mode": "NULLABLE"
-  },
+    "mode": "NULLABLE", 
+    "name": "serverSuccess", 
+    "type": "STRING"
+  }, 
   {
-    "name": "requestResults",
-    "type": "STRING",
-    "mode": "NULLABLE"
-  },
+    "mode": "NULLABLE", 
+    "name": "requestResults", 
+    "type": "STRING"
+  }, 
   {
-    "name": "serverCpuStats",
-    "type": "RECORD",
-    "mode": "REPEATED",
     "fields": [
       {
-        "name": "totalCpuTime",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
-      },
+        "mode": "NULLABLE", 
+        "name": "totalCpuTime", 
+        "type": "INTEGER"
+      }, 
       {
-        "name": "idleCpuTime",
-        "type": "INTEGER",
-        "mode": "NULLABLE"
+        "mode": "NULLABLE", 
+        "name": "idleCpuTime", 
+        "type": "INTEGER"
       }
-    ]
-  },
+    ], 
+    "mode": "REPEATED", 
+    "name": "serverCpuStats", 
+    "type": "RECORD"
+  }, 
   {
-    "name": "serverCpuUsage",
-    "type": "FLOAT",
-    "mode": "NULLABLE"
+    "mode": "NULLABLE", 
+    "name": "serverCpuUsage", 
+    "type": "FLOAT"
   }
-]
+]
\ No newline at end of file
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 08d652a..80e7944 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -224,7 +224,7 @@
     self.retries = 0
     self.message = ''
     self.cpu_estimated = 1
-    self.cpu_measured = 0
+    self.cpu_measured = 1
 
 
 def read_from_start(f):