Merge pull request #1293 from tbetbetbe/grpc_ruby_add_interop_cancellation_tests

Grpc ruby add interop cancellation tests
diff --git a/.travis.yml b/.travis.yml
index 165f892..7d86345 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,12 +4,13 @@
   - sudo add-apt-repository ppa:h-rayflood/llvm -y
   - sudo apt-get update -qq
   - sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv clang-3.5
-  - sudo pip install cpp-coveralls
+  - sudo pip install cpp-coveralls mako simplejson
 env:
   global:
     - RUBY_VERSION=2.1
     - COVERALLS_PARALLEL=true
   matrix:
+    - CONFIG=opt TEST=sanity
     - CONFIG=dbg TEST=c
     - CONFIG=dbg TEST=c++
     - CONFIG=opt TEST=c
diff --git a/BUILD b/BUILD
index 916f24e..e25359d 100644
--- a/BUILD
+++ b/BUILD
@@ -766,6 +766,29 @@
 
 
 cc_library(
+  name = "pubsub_client_lib",
+  srcs = [
+    "examples/pubsub/label.proto",
+    "examples/pubsub/empty.proto",
+    "examples/pubsub/pubsub.proto",
+    "examples/pubsub/publisher.cc",
+    "examples/pubsub/subscriber.cc",
+  ],
+  hdrs = [
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":grpc++",
+    ":grpc",
+    ":gpr",
+  ],
+)
+
+
+cc_library(
   name = "grpc_csharp_ext",
   srcs = [
     "src/csharp/ext/grpc_csharp_ext.c",
diff --git a/Makefile b/Makefile
index f42213d..0511c77 100644
--- a/Makefile
+++ b/Makefile
@@ -1087,13 +1087,13 @@
 
 privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a
 
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libqps.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a
 
 buildtests: buildtests_c buildtests_cxx
 
 buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_smoke_test $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_smoke_test $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
 
 test: test_c test_cxx
 
@@ -1941,10 +1941,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing interop_test"
 	$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
-	$(E) "[RUN]     Testing pubsub_publisher_test"
-	$(Q) $(BINDIR)/$(CONFIG)/pubsub_publisher_test || ( echo test pubsub_publisher_test failed ; exit 1 )
-	$(E) "[RUN]     Testing pubsub_subscriber_test"
-	$(Q) $(BINDIR)/$(CONFIG)/pubsub_subscriber_test || ( echo test pubsub_subscriber_test failed ; exit 1 )
 	$(E) "[RUN]     Testing status_test"
 	$(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 )
 	$(E) "[RUN]     Testing thread_pool_test"
@@ -9008,7 +9004,7 @@
 $(BINDIR)/$(CONFIG)/pubsub_client: $(PROTOBUF_DEP) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_client
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_client
 
 endif
 
@@ -9050,7 +9046,7 @@
 $(BINDIR)/$(CONFIG)/pubsub_publisher_test: $(PROTOBUF_DEP) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
 
 endif
 
@@ -9092,7 +9088,7 @@
 $(BINDIR)/$(CONFIG)/pubsub_subscriber_test: $(PROTOBUF_DEP) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 
 endif
 
diff --git a/build.json b/build.json
index 0dfe7a1..ce0726b 100644
--- a/build.json
+++ b/build.json
@@ -620,7 +620,7 @@
     },
     {
       "name": "pubsub_client_lib",
-      "build": "private",
+      "build": "do_not_build",
       "language": "c++",
       "src": [
         "examples/pubsub/label.proto",
@@ -2030,7 +2030,7 @@
     },
     {
       "name": "pubsub_client",
-      "build": "test",
+      "build": "do_not_build",
       "run": false,
       "language": "c++",
       "src": [
@@ -2047,7 +2047,7 @@
     },
     {
       "name": "pubsub_publisher_test",
-      "build": "test",
+      "build": "do_not_build",
       "language": "c++",
       "src": [
         "examples/pubsub/publisher_test.cc"
@@ -2064,7 +2064,7 @@
     },
     {
       "name": "pubsub_subscriber_test",
-      "build": "test",
+      "build": "do_not_build",
       "language": "c++",
       "src": [
         "examples/pubsub/subscriber_test.cc"
diff --git a/examples/pubsub/README b/examples/pubsub/README
index faeb622..36fcb08 100644
--- a/examples/pubsub/README
+++ b/examples/pubsub/README
@@ -1,3 +1,4 @@
+NOTE: This example does not build and is being updated.
 Experimental example code, likely to change.
 Users should not attempt to run this code till this warning is removed.
 
diff --git a/examples/pubsub/empty.proto b/examples/pubsub/empty.proto
deleted file mode 100644
index 5d6eb10..0000000
--- a/examples/pubsub/empty.proto
+++ /dev/null
@@ -1,44 +0,0 @@
-// This file will be moved to a new location.
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-syntax = "proto2";
-
-package proto2;
-
-// An empty message that you can re-use to avoid defining duplicated empty
-// messages in your project. A typical example is to use it as argument or the
-// return value of a service API. For instance:
-//
-//   service Foo {
-//     rpc Bar (proto2.Empty) returns (proto2.Empty) { };
-//   };
-//
-message Empty {}
diff --git a/examples/pubsub/label.proto b/examples/pubsub/label.proto
deleted file mode 100644
index 0af15a2..0000000
--- a/examples/pubsub/label.proto
+++ /dev/null
@@ -1,79 +0,0 @@
-// This file will be moved to a new location.
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Labels provide a way to associate user-defined metadata with various
-// objects.  Labels may be used to organize objects into non-hierarchical
-// groups; think metadata tags attached to mp3s.
-
-syntax = "proto2";
-
-package tech.label;
-
-// A key-value pair applied to a given object.
-message Label {
-  // The key of a label is a syntactically valid URL (as per RFC 1738) with
-  // the "scheme" and initial slashes omitted and with the additional
-  // restrictions noted below.  Each key should be globally unique.  The
-  // "host" portion is called the "namespace" and is not necessarily
-  // resolvable to a network endpoint.  Instead, the namespace indicates what
-  // system or entity defines the semantics of the label.  Namespaces do not
-  // restrict the set of objects to which a label may be associated.
-  //
-  // Keys are defined by the following grammar:
-  //
-  //   key          = hostname "/" kpath
-  //   kpath        = ksegment *[ "/" ksegment ]
-  //   ksegment     = alphadigit | *[ alphadigit | "-" | "_" | "." ]
-  //
-  // where "hostname" and "alphadigit" are defined as in RFC 1738.
-  //
-  // Example key:
-  //   spanner.google.com/universe
-  required string key = 1;
-
-  // The value of the label.
-  oneof value {
-    // A string value.
-    string str_value = 2;
-    // An integer value.
-    int64 num_value = 3;
-  }
-}
-
-// A collection of labels, such as the set of all labels attached to an
-// object.  Each label in the set must have a different key.
-//
-// Users should prefer to embed "repeated Label" directly when possible.
-// This message should only be used in cases where that isn't possible (e.g.
-// with oneof).
-message Labels {
-  repeated Label label = 1;
-}
diff --git a/examples/pubsub/pubsub.proto b/examples/pubsub/pubsub.proto
deleted file mode 100644
index 9443ae3..0000000
--- a/examples/pubsub/pubsub.proto
+++ /dev/null
@@ -1,729 +0,0 @@
-// This file will be moved to a new location.
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-// Specification of the Pubsub API.
-
-syntax = "proto2";
-
-import "examples/pubsub/empty.proto";
-import "examples/pubsub/label.proto";
-
-package tech.pubsub;
-
-// -----------------------------------------------------------------------------
-// Overview of the Pubsub API
-// -----------------------------------------------------------------------------
-
-// This file describes an API for a Pubsub system.  This system provides a
-// reliable many-to-many communication mechanism between independently written
-// publishers and subscribers where the publisher publishes messages to "topics"
-// and each subscriber creates a "subscription" and consumes messages from it.
-//
-// (a) The pubsub system maintains bindings between topics and subscriptions.
-// (b) A publisher publishes messages into a topic.
-// (c) The pubsub system delivers messages from topics into relevant
-//     subscriptions.
-// (d) A subscriber receives pending messages from its subscription and
-//     acknowledges or nacks each one to the pubsub system.
-// (e) The pubsub system removes acknowledged messages from that subscription.
-
-// -----------------------------------------------------------------------------
-// Data Model
-// -----------------------------------------------------------------------------
-
-// The data model consists of the following:
-//
-// * Topic: A topic is a resource to which messages are published by publishers.
-//     Topics are named, and the name of the topic is unique within the pubsub
-//     system.
-//
-// * Subscription: A subscription records the subscriber's interest in a topic.
-//     It can optionally include a query to select a subset of interesting
-//     messages.  The pubsub system maintains a logical cursor tracking the
-//     matching messages which still need to be delivered and acked so that
-//     they can retried as needed.  The set of messages that have not been
-//     acknowledged is called the subscription backlog.
-//
-// * Message: A message is a unit of data that flows in the system.  It contains
-//     opaque data from the publisher along with its labels.
-//
-// * Message Labels (optional): A set of opaque key, value pairs assigned
-//     by the publisher which the subscriber can use for filtering out messages
-//     in the topic.  For example, a label with key "foo.com/device_type" and
-//     value "mobile" may be added for messages that are only relevant for a
-//     mobile subscriber; a subscriber on a phone may decide to create a
-//     subscription only for messages that have this label.
-
-// -----------------------------------------------------------------------------
-// Publisher Flow
-// -----------------------------------------------------------------------------
-
-// A publisher publishes messages to the topic using the Publish request:
-//
-//   PubsubMessage message;
-//   message.set_data("....");
-//   Label label;
-//   label.set_key("foo.com/key1");
-//   label.set_str_value("value1");
-//   message.add_label(label);
-//   PublishRequest request;
-//   request.set_topic("topicName");
-//   request.set_message(message);
-//   PublisherService.Publish(request);
-
-// -----------------------------------------------------------------------------
-// Subscriber Flow
-// -----------------------------------------------------------------------------
-
-// The subscriber part of the API is richer than the publisher part and has a
-// number of concepts w.r.t. subscription creation and monitoring:
-//
-// (1) A subscriber creates a subscription using the CreateSubscription call.
-//     It may specify an optional "query" to indicate that it wants to receive
-//     only messages with a certain set of labels using the label query syntax.
-//     It may also specify an optional truncation policy to indicate when old
-//     messages from the subcription can be removed.
-//
-// (2) A subscriber receives messages in one of two ways: via push or pull.
-//
-// (a) To receive messages via push, the PushConfig field must be specified in
-//     the Subscription parameter when creating a subscription.  The PushConfig
-//     specifies an endpoint at which the subscriber must expose the
-//     PushEndpointService.  Messages are received via the HandlePubsubEvent
-//     method.  The push subscriber responds to the HandlePubsubEvent method
-//     with a result code that indicates one of three things: Ack (the message
-//     has been successfully processed and the Pubsub system may delete it),
-//     Nack (the message has been rejected, the Pubsub system should resend it
-//     at a later time), or Push-Back (this is a Nack with the additional
-//     semantics that the subscriber is overloaded and the pubsub system should
-//     back off on the rate at which it is invoking HandlePubsubEvent).  The
-//     endpoint may be a load balancer for better scalability.
-//
-// (b) To receive messages via pull a subscriber calls the Pull method on the
-//     SubscriberService to get messages from the subscription.  For each
-//     individual message, the subscriber may use the ack_id received in the
-//     PullResponse to Ack the message, Nack the message, or modify the ack
-//     deadline with ModifyAckDeadline.  See the
-//     Subscription.ack_deadline_seconds field documentation for details on the
-//     ack deadline behavior.
-//
-//     Note: Messages may be consumed in parallel by multiple subscribers making
-//       Pull calls to the same subscription; this will result in the set of
-//       messages from the subscription being shared and each subscriber
-//       receiving a subset of the messages.
-//
-// (4) The subscriber can explicitly truncate the current subscription.
-//
-// (5) "Truncated" events are delivered when a subscription is
-//     truncated, whether due to the subscription's truncation policy
-//     or an explicit request from the subscriber.
-//
-// Subscription creation:
-//
-//   Subscription subscription;
-//   subscription.set_topic("topicName");
-//   subscription.set_name("subscriptionName");
-//   subscription.push_config().set_push_endpoint("machinename:8888");
-//   SubscriberService.CreateSubscription(subscription);
-//
-// Consuming messages via push:
-//
-//  The port 'machinename:8888' must be bound to a server that implements
-//  the PushEndpointService with the following method:
-//
-//   int HandlePubsubEvent(PubsubEvent event) {
-//     if (event.subscription().equals("subscriptionName")) {
-//       if (event.has_message()) {
-//         Process(event.message().data());
-//       } else if (event.truncated()) {
-//         ProcessTruncatedEvent();
-//       }
-//     }
-//     return OK;  // This return code implies an acknowledgment
-//   }
-//
-// Consuming messages via pull:
-//
-//  The subscription must be created without setting the push_config field.
-//
-//   PullRequest pull_request;
-//   pull_request.set_subscription("subscriptionName");
-//   pull_request.set_return_immediately(false);
-//   while (true) {
-//     PullResponse pull_response;
-//     if (SubscriberService.Pull(pull_request, pull_response) == OK) {
-//       PubsubEvent event = pull_response.pubsub_event();
-//       if (event.has_message()) {
-//         Process(event.message().data());
-//       } else if (event.truncated()) {
-//         ProcessTruncatedEvent();
-//       }
-//       AcknowledgeRequest ack_request;
-//       ackRequest.set_subscription("subscriptionName");
-//       ackRequest.set_ack_id(pull_response.ack_id());
-//       SubscriberService.Acknowledge(ack_request);
-//     }
-//   }
-
-// -----------------------------------------------------------------------------
-// Reliability Semantics
-// -----------------------------------------------------------------------------
-
-// When a subscriber successfully creates a subscription using
-// Subscriber.CreateSubscription, it establishes a "subscription point" with
-// respect to that subscription - the subscriber is guaranteed to receive any
-// message published after this subscription point that matches the
-// subscription's query.  Note that messages published before the Subscription
-// point may or may not be delivered.
-//
-// If the system truncates the subscription according to the specified
-// truncation policy, the system delivers a subscription status event with the
-// "truncated" field set to true.  We refer to such events as "truncation
-// events".  A truncation event:
-//
-// * Informs the subscriber that part of the subscription messages have been
-//   discarded.  The subscriber may want to recover from the message loss, e.g.,
-//   by resyncing its state with its backend.
-// * Establishes a new subscription point, i.e., the subscriber is guaranteed to
-//   receive all changes published after the trunction event is received (or
-//   until another truncation event is received).
-//
-// Note that messages are not delivered in any particular order by the pubsub
-// system.  Furthermore, the system guarantees at-least-once delivery
-// of each message or truncation events until acked.
-
-// -----------------------------------------------------------------------------
-// Deletion
-// -----------------------------------------------------------------------------
-
-// Both topics and subscriptions may be deleted.  Deletion of a topic implies
-// deletion of all attached subscriptions.
-//
-// When a subscription is deleted directly by calling DeleteSubscription, all
-// messages are immediately dropped.  If it is a pull subscriber, future pull
-// requests will return NOT_FOUND.
-//
-// When a topic is deleted all corresponding subscriptions are immediately
-// deleted, and subscribers experience the same behavior as directly deleting
-// the subscription.
-
-// -----------------------------------------------------------------------------
-// The Publisher service and its protos.
-// -----------------------------------------------------------------------------
-
-// The service that an application uses to manipulate topics, and to send
-// messages to a topic.
-service PublisherService {
-
-  // Creates the given topic with the given name.
-  rpc CreateTopic(Topic) returns (Topic) {
-  }
-
-  // Adds a message to the topic.  Returns NOT_FOUND if the topic does not
-  // exist.
-  rpc Publish(PublishRequest) returns (proto2.Empty) {
-  }
-
-  // Adds one or more messages to the topic. Returns NOT_FOUND if the topic does
-  // not exist.
-  rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse) {
-  }
-
-  // Gets the configuration of a topic. Since the topic only has the name
-  // attribute, this method is only useful to check the existence of a topic.
-  // If other attributes are added in the future, they will be returned here.
-  rpc GetTopic(GetTopicRequest) returns (Topic) {
-  }
-
-  // Lists matching topics.
-  rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) {
-  }
-
-  // Deletes the topic with the given name.  All subscriptions to this topic
-  // are also deleted. Returns NOT_FOUND if the topic does not exist.
-  // After a topic is deleted, a new topic may be created with the same name.
-  rpc DeleteTopic(DeleteTopicRequest) returns (proto2.Empty)  {
-  }
-}
-
-// A topic resource.
-message Topic {
-  // Name of the topic.
-  optional string name = 1;
-}
-
-// A message data and its labels.
-message PubsubMessage {
-  // The message payload.
-  optional bytes data = 1;
-
-  // Optional list of labels for this message. Keys in this collection must
-  // be unique.
-  repeated tech.label.Label label = 2;
-
-  // ID of this message assigned by the server at publication time. Guaranteed
-  // to be unique within the topic. This value may be read by a subscriber
-  // that receives a PubsubMessage via a Pull call or a push delivery. It must
-  // not be populated by a publisher in a Publish call.
-  optional string message_id = 3;
-}
-
-// Request for the GetTopic method.
-message GetTopicRequest {
-  // The name of the topic to get.
-  optional string topic = 1;
-}
-
-// Request for the Publish method.
-message PublishRequest {
-  // The message in the request will be published on this topic.
-  optional string topic = 1;
-
-  // The message to publish.
-  optional PubsubMessage message = 2;
-}
-
-// Request for the PublishBatch method.
-message PublishBatchRequest {
-  // The messages in the request will be published on this topic.
-  optional string topic = 1;
-
-  // The messages to publish.
-  repeated PubsubMessage messages = 2;
-}
-
-// Response for the PublishBatch method.
-message PublishBatchResponse {
-  // The server-assigned ID of each published message, in the same order as
-  // the messages in the request. IDs are guaranteed to be unique within
-  // the topic.
-  repeated string message_ids = 1;
-}
-
-// Request for the ListTopics method.
-message ListTopicsRequest {
-  // A valid label query expression.
-  // (-- Which labels are required or supported is implementation-specific. --)
-  optional string query = 1;
-
-  // Maximum number of topics to return.
-  // (-- If not specified or <= 0, the implementation will select a reasonable
-  // value. --)
-  optional int32 max_results = 2;
-
-  // The value obtained in the last <code>ListTopicsResponse</code>
-  // for continuation.
-  optional string page_token = 3;
-
-}
-
-// Response for the ListTopics method.
-message ListTopicsResponse {
-  // The resulting topics.
-  repeated Topic topic = 1;
-
-  // If not empty, indicates that there are more topics that match the request,
-  // and this value should be passed to the next <code>ListTopicsRequest</code>
-  // to continue.
-  optional string next_page_token = 2;
-}
-
-// Request for the Delete method.
-message DeleteTopicRequest {
-  // Name of the topic to delete.
-  optional string topic = 1;
-}
-
-// -----------------------------------------------------------------------------
-// The Subscriber service and its protos.
-// -----------------------------------------------------------------------------
-
-// The service that an application uses to manipulate subscriptions and to
-// consume messages from a subscription via the pull method.
-service SubscriberService {
-
-  // Creates a subscription on a given topic for a given subscriber.
-  // If the subscription already exists, returns ALREADY_EXISTS.
-  // If the corresponding topic doesn't exist, returns NOT_FOUND.
-  //
-  // If the name is not provided in the request, the server will assign a random
-  // name for this subscription on the same project as the topic.
-  rpc CreateSubscription(Subscription) returns (Subscription) {
-  }
-
-  // Gets the configuration details of a subscription.
-  rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) {
-  }
-
-  // Lists matching subscriptions.
-  rpc ListSubscriptions(ListSubscriptionsRequest)
-      returns (ListSubscriptionsResponse) {
-  }
-
-  // Deletes an existing subscription. All pending messages in the subscription
-  // are immediately dropped. Calls to Pull after deletion will return
-  // NOT_FOUND.
-  rpc DeleteSubscription(DeleteSubscriptionRequest) returns (proto2.Empty) {
-  }
-
-  // Removes all the pending messages in the subscription and releases the
-  // storage associated with them. Results in a truncation event to be sent to
-  // the subscriber. Messages added after this call returns are stored in the
-  // subscription as before.
-  rpc TruncateSubscription(TruncateSubscriptionRequest) returns (proto2.Empty) {
-  }
-
-  //
-  // Push subscriber calls.
-  //
-
-  // Modifies the <code>PushConfig</code> for a specified subscription.
-  // This method can be used to suspend the flow of messages to an endpoint
-  // by clearing the <code>PushConfig</code> field in the request. Messages
-  // will be accumulated for delivery even if no push configuration is
-  // defined or while the configuration is modified.
-  rpc ModifyPushConfig(ModifyPushConfigRequest) returns (proto2.Empty) {
-  }
-
-  //
-  // Pull Subscriber calls
-  //
-
-  // Pulls a single message from the server.
-  // If return_immediately is true, and no messages are available in the
-  // subscription, this method returns FAILED_PRECONDITION. The system is free
-  // to return an UNAVAILABLE error if no messages are available in a
-  // reasonable amount of time (to reduce system load).
-  rpc Pull(PullRequest) returns (PullResponse) {
-  }
-
-  // Pulls messages from the server. Returns an empty list if there are no
-  // messages available in the backlog. The system is free to return UNAVAILABLE
-  // if there are too many pull requests outstanding for the given subscription.
-  rpc PullBatch(PullBatchRequest) returns (PullBatchResponse) {
-  }
-
-  // Modifies the Ack deadline for a message received from a pull request.
-  rpc ModifyAckDeadline(ModifyAckDeadlineRequest) returns (proto2.Empty) {
-  }
-
-  // Acknowledges a particular received message: the Pub/Sub system can remove
-  // the given message from the subscription. Acknowledging a message whose
-  // Ack deadline has expired may succeed, but the message could have been
-  // already redelivered. Acknowledging a message more than once will not
-  // result in an error. This is only used for messages received via pull.
-  rpc Acknowledge(AcknowledgeRequest) returns (proto2.Empty) {
-  }
-
-  // Refuses processing a particular received message. The system will
-  // redeliver this message to some consumer of the subscription at some
-  // future time. This is only used for messages received via pull.
-  rpc Nack(NackRequest) returns (proto2.Empty) {
-  }
-}
-
-// A subscription resource.
-message Subscription {
-  // Name of the subscription.
-  optional string name = 1;
-
-  // The name of the topic from which this subscription is receiving messages.
-  optional string topic = 2;
-
-  // If <code>query</code> is non-empty, only messages on the subscriber's
-  // topic whose labels match the query will be returned. Otherwise all
-  // messages on the topic will be returned.
-  // (-- The query syntax is described in label_query.proto --)
-  optional string query = 3;
-
-  // The subscriber may specify requirements for truncating unacknowledged
-  // subscription entries. The system will honor the
-  // <code>CreateSubscription</code> request only if it can meet these
-  // requirements. If this field is not specified, messages are never truncated
-  // by the system.
-  optional TruncationPolicy truncation_policy = 4;
-
-  // Specifies which messages can be truncated by the system.
-  message TruncationPolicy {
-    oneof policy {
-      // If <code>max_bytes</code> is specified, the system is allowed to drop
-      // old messages to keep the combined size of stored messages under
-      // <code>max_bytes</code>. This is a hint; the system may keep more than
-      // this many bytes, but will make a best effort to keep the size from
-      // growing much beyond this parameter.
-      int64 max_bytes = 1;
-
-      // If <code>max_age_seconds</code> is specified, the system is allowed to
-      // drop messages that have been stored for at least this many seconds.
-      // This is a hint; the system may keep these messages, but will make a
-      // best effort to remove them when their maximum age is reached.
-      int64 max_age_seconds = 2;
-    }
-  }
-
-  // If push delivery is used with this subscription, this field is
-  // used to configure it.
-  optional PushConfig push_config = 5;
-
-  // For either push or pull delivery, the value is the maximum time after a
-  // subscriber receives a message before the subscriber should acknowledge or
-  // Nack the message. If the Ack deadline for a message passes without an
-  // Ack or a Nack, the Pub/Sub system will eventually redeliver the message.
-  // If a subscriber acknowledges after the deadline, the Pub/Sub system may
-  // accept the Ack, but it is possible that the message has been already
-  // delivered again. Multiple Acks to the message are allowed and will
-  // succeed.
-  //
-  // For push delivery, this value is used to set the request timeout for
-  // the call to the push endpoint.
-  //
-  // For pull delivery, this value is used as the initial value for the Ack
-  // deadline. It may be overridden for a specific pull request (message) with
-  // <code>ModifyAckDeadline</code>.
-  // While a message is outstanding (i.e. it has been delivered to a pull
-  // subscriber and the subscriber has not yet Acked or Nacked), the Pub/Sub
-  // system will not deliver that message to another pull subscriber
-  // (on a best-effort basis).
-  optional int32 ack_deadline_seconds = 6;
-
-  // If this parameter is set to n, the system is allowed to (but not required
-  // to) delete the subscription when at least n seconds have elapsed since the
-  // client presence was detected. (Presence is detected through any
-  // interaction using the subscription ID, including Pull(), Get(), or
-  // acknowledging a message.)
-  //
-  // If this parameter is not set, the subscription will stay live until
-  // explicitly deleted.
-  //
-  // Clients can detect such garbage collection when a Get call or a Pull call
-  // (for pull subscribers only) returns NOT_FOUND.
-  optional int64 garbage_collect_seconds = 7;
-}
-
-// Configuration for a push delivery endpoint.
-message PushConfig {
-  // A URL locating the endpoint to which messages should be pushed.
-  // For example, a Webhook endpoint might use "https://example.com/push".
-  // (-- An Android application might use "gcm:<REGID>", where <REGID> is a
-  // GCM registration id allocated for pushing messages to the application. --)
-  optional string push_endpoint = 1;
-}
-
-// An event indicating a received message or truncation event.
-message PubsubEvent {
-  // The subscription that received the event.
-  optional string subscription = 1;
-
-  oneof type {
-    // A received message.
-    PubsubMessage message = 2;
-
-    // Indicates that this subscription has been truncated.
-    bool truncated = 3;
-
-    // Indicates that this subscription has been deleted. (Note that pull
-    // subscribers will always receive NOT_FOUND in response in their pull
-    // request on the subscription, rather than seeing this boolean.)
-    bool deleted = 4;
-  }
-}
-
-// Request for the GetSubscription method.
-message GetSubscriptionRequest {
-  // The name of the subscription to get.
-  optional string subscription = 1;
-}
-
-// Request for the ListSubscriptions method.
-message ListSubscriptionsRequest {
-  // A valid label query expression.
-  // (-- Which labels are required or supported is implementation-specific.
-  // TODO(eschapira): This method must support to query by topic. We must
-  // define the key URI for the "topic" label. --)
-  optional string query = 1;
-
-  // Maximum number of subscriptions to return.
-  // (-- If not specified or <= 0, the implementation will select a reasonable
-  // value. --)
-  optional int32 max_results = 3;
-
-  // The value obtained in the last <code>ListSubscriptionsResponse</code>
-  // for continuation.
-  optional string page_token = 4;
-}
-
-// Response for the ListSubscriptions method.
-message ListSubscriptionsResponse {
-  // The subscriptions that match the request.
-  repeated Subscription subscription = 1;
-
-  // If not empty, indicates that there are more subscriptions that match the
-  // request and this value should be passed to the next
-  // <code>ListSubscriptionsRequest</code> to continue.
-  optional string next_page_token = 2;
-}
-
-// Request for the TruncateSubscription method.
-message TruncateSubscriptionRequest {
-  // The subscription that is being truncated.
-  optional string subscription = 1;
-}
-
-// Request for the DeleteSubscription method.
-message DeleteSubscriptionRequest {
-  // The subscription to delete.
-  optional string subscription = 1;
-}
-
-// Request for the ModifyPushConfig method.
-message ModifyPushConfigRequest {
-  // The name of the subscription.
-  optional string subscription = 1;
-
-  // An empty <code>push_config</code> indicates that the Pub/Sub system should
-  // pause pushing messages from the given subscription.
-  optional PushConfig push_config = 2;
-}
-
-// -----------------------------------------------------------------------------
-// The protos used by a pull subscriber.
-// -----------------------------------------------------------------------------
-
-// Request for the Pull method.
-message PullRequest {
-  // The subscription from which a message should be pulled.
-  optional string subscription = 1;
-
-  // If this is specified as true the system will respond immediately even if
-  // it is not able to return a message in the Pull response. Otherwise the
-  // system is allowed to wait until at least one message is available rather
-  // than returning FAILED_PRECONDITION. The client may cancel the request if
-  // it does not wish to wait any longer for the response.
-  optional bool return_immediately = 2;
-}
-
-// Either a <code>PubsubMessage</code> or a truncation event. One of these two
-// must be populated.
-message PullResponse {
-  // This ID must be used to acknowledge the received event or message.
-  optional string ack_id = 1;
-
-  // A pubsub message or truncation event.
-  optional PubsubEvent pubsub_event = 2;
-}
-
-// Request for the PullBatch method.
-message PullBatchRequest {
-  // The subscription from which messages should be pulled.
-  optional string subscription = 1;
-
-  // If this is specified as true the system will respond immediately even if
-  // it is not able to return a message in the Pull response. Otherwise the
-  // system is allowed to wait until at least one message is available rather
-  // than returning no messages. The client may cancel the request if it does
-  // not wish to wait any longer for the response.
-  optional bool return_immediately = 2;
-
-  // The maximum number of PubsubEvents returned for this request. The Pub/Sub
-  // system may return fewer than the number of events specified.
-  optional int32 max_events = 3;
-}
-
-// Response for the PullBatch method.
-message PullBatchResponse {
-
-  // Received Pub/Sub messages or status events. The Pub/Sub system will return
-  // zero messages if there are no more messages available in the backlog. The
-  // Pub/Sub system may return fewer than the max_events requested even if
-  // there are more messages available in the backlog.
-  repeated PullResponse pull_responses = 2;
-}
-
-// Request for the ModifyAckDeadline method.
-message ModifyAckDeadlineRequest {
-  // The name of the subscription from which messages are being pulled.
-  optional string subscription = 1;
-
-  // The acknowledgment ID.
-  optional string ack_id = 2;
-
-  // The new Ack deadline. Must be >= 0.
-  optional int32 ack_deadline_seconds = 3;
-}
-
-// Request for the Acknowledge method.
-message AcknowledgeRequest {
-  // The subscription whose message is being acknowledged.
-  optional string subscription = 1;
-
-  // The acknowledgment ID for the message being acknowledged. This was
-  // returned by the Pub/Sub system in the Pull response.
-  repeated string ack_id = 2;
-}
-
-// Request for the Nack method.
-message NackRequest {
-  // The subscription whose message is being Nacked.
-  optional string subscription = 1;
-
-  // The acknowledgment ID for the message being refused. This was returned by
-  // the Pub/Sub system in the Pull response.
-  repeated string ack_id = 2;
-}
-
-// -----------------------------------------------------------------------------
-// The service and protos used by a push subscriber.
-// -----------------------------------------------------------------------------
-
-// The service that a subscriber uses to handle messages sent via push
-// delivery.
-// This service is not currently exported for HTTP clients.
-// TODO(eschapira): Explain HTTP subscribers.
-service PushEndpointService {
-  // Sends a <code>PubsubMessage</code> or a subscription status event to a
-  // push endpoint.
-  // The push endpoint responds with an empty message and a code from
-  // util/task/codes.proto. The following codes have a particular meaning to the
-  // Pub/Sub system:
-  // OK          - This is interpreted by Pub/Sub as Ack.
-  // ABORTED     - This is intepreted by Pub/Sub as a Nack, without implying
-  //               pushback for congestion control.  The Pub/Sub system will
-  //               retry this message at a later time.
-  // UNAVAILABLE - This is intepreted by Pub/Sub as a Nack, with the additional
-  //               semantics of push-back.  The Pub/Sub system will use an AIMD
-  //               congestion control algorithm to backoff the rate of sending
-  //               messages from this subscription.
-  // Any other code, or a failure to respond, will be interpreted in the same
-  // way as ABORTED; i.e. the system will retry the message at a later time to
-  // ensure reliable delivery.
-  rpc HandlePubsubEvent(PubsubEvent) returns (proto2.Empty);
-}
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 597a2a6..86721e9 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -46,6 +46,7 @@
 
 #include "src/core/support/string.h"
 #include "src/core/debug/trace.h"
+#include "src/core/profiling/timers.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
@@ -326,6 +327,7 @@
   gpr_slice *final_slices;
   size_t final_nslices;
 
+  GRPC_TIMER_MARK(HANDLE_READ_BEGIN, 0);
   slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
                    0);
 
@@ -348,9 +350,11 @@
     msg.msg_controllen = 0;
     msg.msg_flags = 0;
 
+    GRPC_TIMER_MARK(RECVMSG_BEGIN, 0);
     do {
       read_bytes = recvmsg(tcp->fd, &msg, 0);
     } while (read_bytes < 0 && errno == EINTR);
+    GRPC_TIMER_MARK(RECVMSG_END, 0);
 
     if (read_bytes < allocated_bytes) {
       /* TODO(klempner): Consider a second read first, in hopes of getting a
@@ -402,6 +406,7 @@
       ++iov_size;
     }
   }
+  GRPC_TIMER_MARK(HANDLE_READ_END, 0);
 }
 
 static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
@@ -433,10 +438,12 @@
     msg.msg_controllen = 0;
     msg.msg_flags = 0;
 
+    GRPC_TIMER_MARK(SENDMSG_BEGIN, 0);
     do {
       /* TODO(klempner): Cork if this is a partial write */
       sent_length = sendmsg(tcp->fd, &msg, 0);
     } while (sent_length < 0 && errno == EINTR);
+    GRPC_TIMER_MARK(SENDMSG_END, 0);
 
     if (sent_length < 0) {
       if (errno == EAGAIN) {
@@ -472,6 +479,7 @@
     return;
   }
 
+  GRPC_TIMER_MARK(CB_WRITE_BEGIN, 0);
   write_status = grpc_tcp_flush(tcp);
   if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
     grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
@@ -487,6 +495,7 @@
     cb(tcp->write_user_data, cb_status);
     grpc_tcp_unref(tcp);
   }
+  GRPC_TIMER_MARK(CB_WRITE_END, 0);
 }
 
 static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
@@ -509,6 +518,7 @@
     }
   }
 
+  GRPC_TIMER_MARK(WRITE_BEGIN, 0);
   GPR_ASSERT(tcp->write_cb == NULL);
   slice_state_init(&tcp->write_state, slices, nslices, nslices);
 
@@ -522,6 +532,7 @@
     grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
   }
 
+  GRPC_TIMER_MARK(WRITE_END, 0);
   return status;
 }
 
diff --git a/src/core/profiling/timers.c b/src/core/profiling/timers.c
index 478397d..7cc79bd 100644
--- a/src/core/profiling/timers.c
+++ b/src/core/profiling/timers.c
@@ -45,7 +45,7 @@
 typedef struct grpc_timer_entry {
   grpc_precise_clock tm;
   const char* tag;
-  int seq;
+  void* id;
   const char* file;
   int line;
 } grpc_timer_entry;
@@ -85,7 +85,7 @@
     grpc_timer_entry* entry = &(log->log[i]);
     fprintf(fp, "GRPC_LAT_PROF ");
     grpc_precise_clock_print(&entry->tm, fp);
-    fprintf(fp, " %s#%d,%s:%d\n", entry->tag, entry->seq, entry->file,
+    fprintf(fp, " %s %p %s %d\n", entry->tag, entry->id, entry->file,
             entry->line);
   }
 
@@ -104,7 +104,7 @@
   gpr_free(log);
 }
 
-void grpc_timers_log_add(grpc_timers_log* log, const char* tag, int seq,
+void grpc_timers_log_add(grpc_timers_log* log, const char* tag, void* id,
                          const char* file, int line) {
   grpc_timer_entry* entry;
 
@@ -118,7 +118,7 @@
 
   grpc_precise_clock_now(&entry->tm);
   entry->tag = tag;
-  entry->seq = seq;
+  entry->id = id;
   entry->file = file;
   entry->line = line;
 
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
index ef4cad1..1a6b9ff 100644
--- a/src/core/profiling/timers.h
+++ b/src/core/profiling/timers.h
@@ -44,15 +44,16 @@
 
 typedef struct grpc_timers_log grpc_timers_log;
 
-grpc_timers_log *grpc_timers_log_create(int capacity_limit, FILE *dump);
-void grpc_timers_log_add(grpc_timers_log *, const char *tag, int seq,
-                         const char *file, int line);
+grpc_timers_log* grpc_timers_log_create(int capacity_limit, FILE* dump);
+void grpc_timers_log_add(grpc_timers_log*, const char* tag, void* id,
+                         const char* file, int line);
 void grpc_timers_log_destroy(grpc_timers_log *);
 
 extern grpc_timers_log *grpc_timers_log_global;
 
 #define GRPC_TIMER_MARK(x, s) \
-  grpc_timers_log_add(grpc_timers_log_global, #x, s, __FILE__, __LINE__)
+  grpc_timers_log_add(grpc_timers_log_global, #x, ((void *)(gpr_intptr)(s)), \
+                      __FILE__, __LINE__)
 
 #else /* !GRPC_LATENCY_PROFILER */
 #define GRPC_TIMER_MARK(x, s) \
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 698e099..e6d2e9e 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -111,6 +111,11 @@
   creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
 }
 
+grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds) {
+  if (creds == NULL) return NULL;
+  return creds->vtable->get_metadata_context(creds);
+}
+
 void grpc_server_credentials_release(grpc_server_credentials *creds) {
   if (creds == NULL) return;
   creds->vtable->destroy(creds);
@@ -167,8 +172,13 @@
   return 0;
 }
 
+static grpc_mdctx *ssl_get_metadata_context(grpc_credentials *creds) {
+  return NULL;
+}
+
 static grpc_credentials_vtable ssl_vtable = {
-    ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
+    ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only,
+    ssl_get_metadata_context, NULL};
 
 static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
 
@@ -371,9 +381,14 @@
   }
 }
 
+static grpc_mdctx *jwt_get_metadata_context(grpc_credentials *creds) {
+  grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
+  return c->md_ctx;
+}
+
 static grpc_credentials_vtable jwt_vtable = {
     jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
-    jwt_get_request_metadata};
+    jwt_get_metadata_context, jwt_get_request_metadata};
 
 grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
                                               gpr_timespec token_lifetime) {
@@ -585,11 +600,19 @@
   c->fetch_func = fetch_func;
 }
 
+static grpc_mdctx *oauth2_token_fetcher_get_metadata_context(
+    grpc_credentials *creds) {
+  grpc_oauth2_token_fetcher_credentials *c =
+      (grpc_oauth2_token_fetcher_credentials *)creds;
+  return c->md_ctx;
+}
+
 /* -- ComputeEngine credentials. -- */
 
 static grpc_credentials_vtable compute_engine_vtable = {
     oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
+    oauth2_token_fetcher_get_metadata_context,
     oauth2_token_fetcher_get_request_metadata};
 
 static void compute_engine_fetch_oauth2(
@@ -633,6 +656,7 @@
 static grpc_credentials_vtable service_account_vtable = {
     service_account_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
+    oauth2_token_fetcher_get_metadata_context,
     oauth2_token_fetcher_get_request_metadata};
 
 static void service_account_fetch_oauth2(
@@ -706,6 +730,7 @@
 static grpc_credentials_vtable refresh_token_vtable = {
     refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
+    oauth2_token_fetcher_get_metadata_context,
     oauth2_token_fetcher_get_request_metadata};
 
 static void refresh_token_fetch_oauth2(
@@ -801,9 +826,15 @@
   }
 }
 
+static grpc_mdctx *fake_oauth2_get_metadata_context(grpc_credentials *creds) {
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+  return c->md_ctx;
+}
+
 static grpc_credentials_vtable fake_oauth2_vtable = {
     fake_oauth2_destroy, fake_oauth2_has_request_metadata,
-    fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
+    fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context,
+    fake_oauth2_get_request_metadata};
 
 grpc_credentials *grpc_fake_oauth2_credentials_create(
     const char *token_md_value, int is_async) {
@@ -842,10 +873,16 @@
   return 0;
 }
 
+static grpc_mdctx *fake_transport_security_get_metadata_context(
+    grpc_credentials *c) {
+  return NULL;
+}
+
 static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
     fake_transport_security_credentials_destroy,
     fake_transport_security_has_request_metadata,
-    fake_transport_security_has_request_metadata_only, NULL};
+    fake_transport_security_has_request_metadata_only,
+    fake_transport_security_get_metadata_context, NULL};
 
 static grpc_server_credentials_vtable
     fake_transport_security_server_credentials_vtable = {
@@ -995,9 +1032,26 @@
   GPR_ASSERT(0); /* Should have exited before. */
 }
 
+static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) {
+  grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
+  grpc_mdctx *ctx = NULL;
+  size_t i;
+  for (i = 0; i < c->inner.num_creds; i++) {
+    grpc_credentials *inner_creds = c->inner.creds_array[i];
+    grpc_mdctx *inner_ctx = grpc_credentials_get_metadata_context(inner_creds);
+    if (inner_ctx) {
+      GPR_ASSERT(ctx == NULL &&
+                 "can only have one metadata context per composite credential");
+      ctx = inner_ctx;
+    }
+  }
+  return ctx;
+}
+
 static grpc_credentials_vtable composite_credentials_vtable = {
     composite_destroy, composite_has_request_metadata,
-    composite_has_request_metadata_only, composite_get_request_metadata};
+    composite_has_request_metadata_only, composite_get_metadata_context,
+    composite_get_request_metadata};
 
 static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
   grpc_credentials_array result;
@@ -1102,9 +1156,14 @@
   cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK);
 }
 
+static grpc_mdctx *iam_get_metadata_context(grpc_credentials *creds) {
+  grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
+  return c->md_ctx;
+}
+
 static grpc_credentials_vtable iam_vtable = {
     iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
-    iam_get_request_metadata};
+    iam_get_metadata_context, iam_get_request_metadata};
 
 grpc_credentials *grpc_iam_credentials_create(const char *token,
                                               const char *authority_selector) {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 0f70670..562b3fa 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -94,6 +94,7 @@
   void (*destroy)(grpc_credentials *c);
   int (*has_request_metadata)(const grpc_credentials *c);
   int (*has_request_metadata_only)(const grpc_credentials *c);
+  grpc_mdctx *(*get_metadata_context)(grpc_credentials *c);
   void (*get_request_metadata)(grpc_credentials *c,
                                const char *service_url,
                                grpc_credentials_metadata_cb cb,
@@ -114,6 +115,8 @@
                                            const char *service_url,
                                            grpc_credentials_metadata_cb cb,
                                            void *user_data);
+grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds);
+
 typedef struct {
   unsigned char *pem_private_key;
   size_t pem_private_key_size;
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index e180cad..0813780 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -165,6 +165,16 @@
   return 1;
 }
 
+static grpc_mdctx *get_or_create_mdctx(grpc_credentials *creds) {
+  grpc_mdctx *mdctx = grpc_credentials_get_metadata_context(creds);
+  if (mdctx == NULL) {
+    mdctx = grpc_mdctx_create();
+  } else {
+    grpc_mdctx_ref(mdctx);
+  }
+  return mdctx;
+}
+
 /* -- Fake implementation. -- */
 
 typedef struct {
@@ -626,7 +636,8 @@
   arg.key = GRPC_ARG_HTTP2_SCHEME;
   arg.value.string = "https";
   new_args = grpc_channel_args_copy_and_add(args, &arg);
-  channel = grpc_secure_channel_create_internal(target, new_args, ctx);
+  channel = grpc_secure_channel_create_internal(
+      target, new_args, ctx, get_or_create_mdctx(request_metadata_creds));
   grpc_security_context_unref(&ctx->base);
   grpc_channel_args_destroy(new_args);
   return channel;
@@ -637,8 +648,8 @@
     const char *target, const grpc_channel_args *args) {
   grpc_channel_security_context *ctx =
       grpc_fake_channel_security_context_create(request_metadata_creds, 1);
-  grpc_channel *channel =
-      grpc_secure_channel_create_internal(target, args, ctx);
+  grpc_channel *channel = grpc_secure_channel_create_internal(
+      target, args, ctx, get_or_create_mdctx(request_metadata_creds));
   grpc_security_context_unref(&ctx->base);
   return channel;
 }
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 2b4e38f..8e7ba34 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -190,7 +190,7 @@
 
 grpc_channel *grpc_secure_channel_create_internal(
     const char *target, const grpc_channel_args *args,
-    grpc_channel_security_context *ctx);
+    grpc_channel_security_context *ctx, grpc_mdctx *mdctx);
 
 typedef grpc_channel *(*grpc_secure_channel_factory_func)(
     grpc_credentials *transport_security_creds,
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 8e56868..96b2fe0 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -205,12 +205,11 @@
                    - perform handshakes */
 grpc_channel *grpc_secure_channel_create_internal(
     const char *target, const grpc_channel_args *args,
-    grpc_channel_security_context *context) {
+    grpc_channel_security_context *context, grpc_mdctx *mdctx) {
   setup *s;
   grpc_channel *channel;
   grpc_arg context_arg;
   grpc_channel_args *args_copy;
-  grpc_mdctx *mdctx = grpc_mdctx_create();
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
   int n = 0;
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 79cce55..708bb06 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -171,13 +171,15 @@
   return gpr_slice_buffer_tiny_add(st->output, len);
 }
 
-static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
+/* add an element to the decoder table: returns metadata element to unref */
+static grpc_mdelem *add_elem(grpc_chttp2_hpack_compressor *c,
+                             grpc_mdelem *elem) {
   gpr_uint32 key_hash = elem->key->hash;
   gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1;
   gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
                          GPR_SLICE_LENGTH(elem->value->slice);
-  int drop_ref;
+  grpc_mdelem *elem_to_unref;
 
   /* Reserve space for this element in the remote table: if this overflows
      the current table, drop elements until it fits, matching the decompressor
@@ -204,34 +206,32 @@
   if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
     /* already there: update with new index */
     c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-    drop_ref = 1;
+    elem_to_unref = elem;
   } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
     /* already there (cuckoo): update with new index */
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-    drop_ref = 1;
+    elem_to_unref = elem;
   } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
     /* not there, but a free element: add */
     c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
     c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-    drop_ref = 0;
+    elem_to_unref = NULL;
   } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
     /* not there (cuckoo), but a free element: add */
     c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-    drop_ref = 0;
+    elem_to_unref = NULL;
   } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
              c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
     /* not there: replace oldest */
-    grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
+    elem_to_unref = c->entries_elems[HASH_FRAGMENT_2(elem_hash)];
     c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
     c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-    drop_ref = 0;
   } else {
     /* not there: replace oldest */
-    grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
+    elem_to_unref = c->entries_elems[HASH_FRAGMENT_3(elem_hash)];
     c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-    drop_ref = 0;
   }
 
   /* do exactly the same for the key (so we can find by that again too) */
@@ -257,9 +257,7 @@
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   }
 
-  if (drop_ref) {
-    grpc_mdelem_unref(elem);
-  }
+  return elem_to_unref;
 }
 
 static void emit_indexed(grpc_chttp2_hpack_compressor *c, gpr_uint32 index,
@@ -348,9 +346,9 @@
          c->table_elems - index;
 }
 
-/* encode an mdelem, taking ownership of it */
-static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
-                      framer_state *st) {
+/* encode an mdelem; returns metadata element to unref */
+static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
+                              grpc_mdelem *elem, framer_state *st) {
   gpr_uint32 key_hash = elem->key->hash;
   gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   size_t decoder_space_usage;
@@ -366,8 +364,7 @@
     /* HIT: complete element (first cuckoo hash) */
     emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
                  st);
-    grpc_mdelem_unref(elem);
-    return;
+    return elem;
   }
 
   if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
@@ -375,8 +372,7 @@
     /* HIT: complete element (second cuckoo hash) */
     emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
                  st);
-    grpc_mdelem_unref(elem);
-    return;
+    return elem;
   }
 
   /* should this elem be in the table? */
@@ -394,12 +390,12 @@
     /* HIT: key (first cuckoo hash) */
     if (should_add_elem) {
       emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
+      return add_elem(c, elem);
     } else {
       emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
-      grpc_mdelem_unref(elem);
+      return elem;
     }
-    return;
+    abort();
   }
 
   indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
@@ -408,23 +404,24 @@
     /* HIT: key (first cuckoo hash) */
     if (should_add_elem) {
       emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
+      return add_elem(c, elem);
     } else {
       emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
-      grpc_mdelem_unref(elem);
+      return elem;
     }
-    return;
+    abort();
   }
 
   /* no elem, key in the table... fall back to literal emission */
 
   if (should_add_elem) {
     emit_lithdr_incidx_v(c, elem, st);
-    add_elem(c, elem);
+    return add_elem(c, elem);
   } else {
     emit_lithdr_noidx_v(c, elem, st);
-    grpc_mdelem_unref(elem);
+    return elem;
   }
+  abort();
 }
 
 #define STRLEN_LIT(x) (sizeof(x) - 1)
@@ -433,11 +430,13 @@
 static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
                          framer_state *st) {
   char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
+  grpc_mdelem *mdelem;
   grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
-  hpack_enc(c, grpc_mdelem_from_metadata_strings(
-                   c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
-                   grpc_mdstr_from_string(c->mdctx, timeout_str)),
-            st);
+  mdelem = grpc_mdelem_from_metadata_strings(
+      c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
+      grpc_mdstr_from_string(c->mdctx, timeout_str));
+  mdelem = hpack_enc(c, mdelem, st);
+  if (mdelem) grpc_mdelem_unref(mdelem);
 }
 
 gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
@@ -542,6 +541,9 @@
   grpc_stream_op *op;
   gpr_uint32 max_take_size;
   gpr_uint32 curop = 0;
+  gpr_uint32 unref_op;
+  grpc_mdctx *mdctx = compressor->mdctx;
+  int need_unref = 0;
 
   GPR_ASSERT(stream_id != 0);
 
@@ -564,7 +566,12 @@
         curop++;
         break;
       case GRPC_OP_METADATA:
-        hpack_enc(compressor, op->data.metadata, &st);
+        /* Encode a metadata element; store the returned value, representing
+           a metadata element that needs to be unreffed back into the metadata
+           slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
+           updated). After this loop, we'll do a batch unref of elements. */
+        op->data.metadata = hpack_enc(compressor, op->data.metadata, &st);
+        need_unref |= op->data.metadata != NULL;
         curop++;
         break;
       case GRPC_OP_DEADLINE:
@@ -601,4 +608,15 @@
     begin_frame(&st, DATA);
   }
   finish_frame(&st, 1, eof);
+
+  if (need_unref) {
+    grpc_mdctx_lock(mdctx);
+    for (unref_op = 0; unref_op < curop; unref_op++) {
+      op = &ops[unref_op];
+      if (op->type != GRPC_OP_METADATA) continue;
+      if (!op->data.metadata) continue;
+      grpc_mdctx_locked_mdelem_unref(mdctx, op->data.metadata);
+    }
+    grpc_mdctx_unlock(mdctx);
+  }
 }
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index f4075a3..44f6591 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -555,3 +555,17 @@
   unlock(ctx);
   return slice;
 }
+
+void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); }
+
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *gmd) {
+  internal_metadata *md = (internal_metadata *)gmd;
+  grpc_mdctx *elem_ctx = md->context;
+  GPR_ASSERT(ctx == elem_ctx);
+  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+  if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
+    ctx->mdtab_free++;
+  }
+}
+
+void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); }
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index b8afbeb..21b8ae2 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -135,6 +135,18 @@
    Does not promise that the returned string has no embedded nulls however. */
 const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
 
+/* Batch mode metadata functions.
+   These API's have equivalents above, but allow taking the mdctx just once,
+   performing a bunch of work, and then leaving the mdctx. */
+
+/* Lock the metadata context: it's only safe to call _locked_ functions against
+   this context from the calling thread until grpc_mdctx_unlock is called */
+void grpc_mdctx_lock(grpc_mdctx *ctx);
+/* Unref a metadata element */
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem);
+/* Unlock the metadata context */
+void grpc_mdctx_unlock(grpc_mdctx *ctx);
+
 #define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
 
 #endif  /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 5380d3a..72123ab 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -41,6 +41,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
 
+#include "src/core/profiling/timers.h"
 #include "src/cpp/proto/proto_utils.h"
 #include <grpc++/channel_arguments.h>
 #include <grpc++/client_context.h>
@@ -65,6 +66,7 @@
                                              ? target_.c_str()
                                              : context->authority().c_str(),
                                          context->RawDeadline());
+  GRPC_TIMER_MARK(CALL_CREATED,c_call);
   context->set_call(c_call);
   return Call(c_call, this, cq);
 }
@@ -73,9 +75,11 @@
   static const size_t MAX_OPS = 8;
   size_t nops = MAX_OPS;
   grpc_op ops[MAX_OPS];
+  GRPC_TIMER_MARK(PERFORM_OPS_BEGIN, call->call());
   buf->FillOps(ops, &nops);
   GPR_ASSERT(GRPC_CALL_OK ==
              grpc_call_start_batch(call->call(), ops, nops, buf));
+  GRPC_TIMER_MARK(PERFORM_OPS_END, call->call());
 }
 
 }  // namespace grpc
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
index e75e77e..9878133 100644
--- a/src/cpp/common/call.cc
+++ b/src/cpp/common/call.cc
@@ -38,6 +38,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/channel_interface.h>
 
+#include "src/core/profiling/timers.h"
 #include "src/cpp/proto/proto_utils.h"
 
 namespace grpc {
@@ -231,11 +232,13 @@
   }
   if (send_message_ || send_message_buffer_) {
     if (send_message_) {
+      GRPC_TIMER_MARK(SER_PROTO_BEGIN, 0);
       bool success = SerializeProto(*send_message_, &send_buf_);
       if (!success) {
         abort();
         // TODO handle parse failure
       }
+      GRPC_TIMER_MARK(SER_PROTO_END, 0);
     } else {
       send_buf_ = send_message_buffer_->buffer();
     }
@@ -307,8 +310,10 @@
     if (recv_buf_) {
       got_message = *status;
       if (recv_message_) {
+        GRPC_TIMER_MARK(DESER_PROTO_BEGIN, 0);
         *status = *status && DeserializeProto(recv_buf_, recv_message_);
         grpc_byte_buffer_destroy(recv_buf_);
+        GRPC_TIMER_MARK(DESER_PROTO_END, 0);
       } else {
         recv_message_buffer_->set_buffer(recv_buf_);
       }
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
index 628822a..e1f2945 100644
--- a/src/cpp/server/async_server_context.cc
+++ b/src/cpp/server/async_server_context.cc
@@ -68,9 +68,11 @@
 bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
                                     int flags) {
   grpc_byte_buffer* buffer = nullptr;
+  GRPC_TIMER_MARK(SER_PROTO_BEGIN, call_->call());
   if (!SerializeProto(response, &buffer)) {
     return false;
   }
+  GRPC_TIMER_MARK(SER_PROTO_END, call_->call());
   grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
   grpc_byte_buffer_destroy(buffer);
   return err == GRPC_CALL_OK;
@@ -87,7 +89,9 @@
 
 bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
   GPR_ASSERT(request_);
+  GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_->call());
   bool success = DeserializeProto(read_buffer, request_);
+  GRPC_TIMER_MARK(DESER_PROTO_END, call_->call());
   request_ = nullptr;
   return success;
 }
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 046133c..b3cd1fd 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -46,6 +46,7 @@
 #include <grpc++/server_credentials.h>
 #include <grpc++/thread_pool_interface.h>
 
+#include "src/core/profiling/timers.h"
 #include "src/cpp/proto/proto_utils.h"
 #include "src/cpp/util/time.h"
 
@@ -123,10 +124,12 @@
       std::unique_ptr<grpc::protobuf::Message> req;
       std::unique_ptr<grpc::protobuf::Message> res;
       if (has_request_payload_) {
+        GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_.call());
         req.reset(method_->AllocateRequestProto());
         if (!DeserializeProto(request_payload_, req.get())) {
           abort();  // for now
         }
+        GRPC_TIMER_MARK(DESER_PROTO_END, call_.call());
       }
       if (has_response_payload_) {
         res.reset(method_->AllocateResponseProto());
@@ -340,7 +343,9 @@
     bool orig_status = *status;
     if (*status && request_) {
       if (payload_) {
+        GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_);
         *status = DeserializeProto(payload_, request_);
+        GRPC_TIMER_MARK(DESER_PROTO_END, call_);
       } else {
         *status = false;
       }
diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh
index 45f08df..a09395c 100755
--- a/tools/buildgen/generate_projects.sh
+++ b/tools/buildgen/generate_projects.sh
@@ -46,13 +46,11 @@
 $gen_build_json > $end2end_test_build
 
 global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
-  sort | grep -v __init__ |
-  while read p ; do echo -n "-p $p " ; done`
+  sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
 
 for dir in . ; do
   local_plugins=`find $dir/templates -name '*.py' |
-    sort | grep -v __init__ |
-    while read p ; do echo -n "-p $p " ; done`
+    sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
 
   plugins="$global_plugins $local_plugins"
 
@@ -60,7 +58,7 @@
     out=${dir}/${file#$dir/templates/}  # strip templates dir prefix
     out=${out%.*}  # strip template extension
     json_files="build.json $end2end_test_build"
-    data=`for i in $json_files; do echo -n "-d $i "; done`
+    data=`for i in $json_files ; do echo $i ; done | awk ' { printf "-d %s ", $0 } '`
     if [ "x$TEST" = "xtrue" ] ; then
       actual_out=$out
       out=`mktemp /tmp/gentXXXXXX`
diff --git a/tools/run_tests/run_sanity.sh b/tools/run_tests/run_sanity.sh
new file mode 100755
index 0000000..e915af9
--- /dev/null
+++ b/tools/run_tests/run_sanity.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+set -e
+
+export TEST=true
+
+cd `dirname $0`/../..
+
+./tools/buildgen/generate_projects.sh
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index c279c3e..a443b17 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -235,6 +235,24 @@
     return 'csharp'
 
 
+class Sanity(object):
+
+  def test_specs(self, config, travis):
+    return [config.job_spec('tools/run_tests/run_sanity.sh', None)]
+
+  def make_targets(self):
+    return ['run_dep_checks']
+
+  def build_steps(self):
+    return []
+
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'sanity'
+
+
 class Build(object):
 
   def test_specs(self, config, travis):
@@ -278,6 +296,7 @@
     'python': PythonLanguage(),
     'ruby': RubyLanguage(),
     'csharp': CSharpLanguage(),
+    'sanity': Sanity(),
     'build': Build(),
     }
 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index c589320..e284d17 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -696,24 +696,6 @@
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "pubsub_publisher_test", 
-    "platforms": [
-      "windows", 
-      "posix"
-    ]
-  }, 
-  {
-    "flaky": false, 
-    "language": "c++", 
-    "name": "pubsub_subscriber_test", 
-    "platforms": [
-      "windows", 
-      "posix"
-    ]
-  }, 
-  {
-    "flaky": false, 
-    "language": "c++", 
     "name": "status_test", 
     "platforms": [
       "windows",