Merge remote-tracking branch 'upstream/master' into lb_pick_error_fix
diff --git a/BUILD b/BUILD
index d0b37df..8ccc748 100644
--- a/BUILD
+++ b/BUILD
@@ -467,7 +467,6 @@
         "src/core/lib/support/arena.cc",
         "src/core/lib/support/atm.cc",
         "src/core/lib/support/avl.cc",
-        "src/core/lib/support/backoff.cc",
         "src/core/lib/support/cmdline.cc",
         "src/core/lib/support/cpu_iphone.cc",
         "src/core/lib/support/cpu_linux.cc",
@@ -514,8 +513,6 @@
         "src/core/lib/support/atomic.h",
         "src/core/lib/support/atomic_with_atm.h",
         "src/core/lib/support/atomic_with_std.h",
-        "src/core/lib/support/backoff.h",
-        "src/core/lib/support/block_annotate.h",
         "src/core/lib/support/env.h",
         "src/core/lib/support/memory.h",
         "src/core/lib/support/mpscq.h",
@@ -568,6 +565,7 @@
 grpc_cc_library(
     name = "grpc_base_c",
     srcs = [
+        "src/core/lib/backoff/backoff.cc",
         "src/core/lib/channel/channel_args.cc",
         "src/core/lib/channel/channel_stack.cc",
         "src/core/lib/channel/channel_stack_builder.cc",
@@ -762,6 +760,7 @@
         "src/core/lib/iomgr/socket_utils_posix.h",
         "src/core/lib/iomgr/socket_windows.h",
         "src/core/lib/iomgr/sys_epoll_wrapper.h",
+        "src/core/lib/iomgr/block_annotate.h",
         "src/core/lib/iomgr/tcp_client.h",
         "src/core/lib/iomgr/tcp_client_posix.h",
         "src/core/lib/iomgr/tcp_posix.h",
@@ -817,6 +816,7 @@
         "src/core/lib/transport/timeout_encoding.h",
         "src/core/lib/transport/transport.h",
         "src/core/lib/transport/transport_impl.h",
+        "src/core/lib/backoff/backoff.h",
     ],
     external_deps = [
         "zlib",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 759d49b..139d1bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -379,6 +379,7 @@
 add_dependencies(buildtests_c alloc_test)
 add_dependencies(buildtests_c alpn_test)
 add_dependencies(buildtests_c arena_test)
+add_dependencies(buildtests_c backoff_test)
 add_dependencies(buildtests_c bad_server_response_test)
 add_dependencies(buildtests_c bdp_estimator_test)
 add_dependencies(buildtests_c bin_decoder_test)
@@ -428,7 +429,6 @@
 add_dependencies(buildtests_c goaway_server_test)
 endif()
 add_dependencies(buildtests_c gpr_avl_test)
-add_dependencies(buildtests_c gpr_backoff_test)
 add_dependencies(buildtests_c gpr_cmdline_test)
 add_dependencies(buildtests_c gpr_cpu_test)
 add_dependencies(buildtests_c gpr_env_test)
@@ -786,7 +786,6 @@
   src/core/lib/support/arena.cc
   src/core/lib/support/atm.cc
   src/core/lib/support/avl.cc
-  src/core/lib/support/backoff.cc
   src/core/lib/support/cmdline.cc
   src/core/lib/support/cpu_iphone.cc
   src/core/lib/support/cpu_linux.cc
@@ -955,6 +954,7 @@
 
 add_library(grpc
   src/core/lib/surface/init.cc
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -1306,6 +1306,7 @@
 
 add_library(grpc_cronet
   src/core/lib/surface/init.cc
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -1625,6 +1626,7 @@
   test/core/util/port_server_client.c
   test/core/util/slice_splitter.c
   test/core/util/trickle_endpoint.c
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -1888,6 +1890,7 @@
   test/core/util/port_server_client.c
   test/core/util/slice_splitter.c
   test/core/util/trickle_endpoint.c
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -2137,6 +2140,7 @@
 add_library(grpc_unsecure
   src/core/lib/surface/init.cc
   src/core/lib/surface/init_unsecure.cc
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -2894,6 +2898,7 @@
   src/core/ext/transport/chttp2/transport/stream_map.cc
   src/core/ext/transport/chttp2/transport/varint.cc
   src/core/ext/transport/chttp2/transport/writing.cc
+  src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
@@ -5195,6 +5200,35 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(backoff_test
+  test/core/backoff/backoff_test.c
+)
+
+
+target_include_directories(backoff_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(backoff_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(bad_server_response_test
   test/core/end2end/bad_server_response_test.c
 )
@@ -6295,33 +6329,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(gpr_backoff_test
-  test/core/support/backoff_test.c
-)
-
-
-target_include_directories(gpr_backoff_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${BENCHMARK_ROOT_DIR}/include
-  PRIVATE ${ZLIB_ROOT_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-)
-
-target_link_libraries(gpr_backoff_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(gpr_cmdline_test
   test/core/support/cmdline_test.c
 )
diff --git a/Makefile b/Makefile
index 5ea638a..382956d 100644
--- a/Makefile
+++ b/Makefile
@@ -950,6 +950,7 @@
 alpn_test: $(BINDIR)/$(CONFIG)/alpn_test
 api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer
 arena_test: $(BINDIR)/$(CONFIG)/arena_test
+backoff_test: $(BINDIR)/$(CONFIG)/backoff_test
 bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test
 bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
 bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
@@ -988,7 +989,6 @@
 gen_percent_encoding_tables: $(BINDIR)/$(CONFIG)/gen_percent_encoding_tables
 goaway_server_test: $(BINDIR)/$(CONFIG)/goaway_server_test
 gpr_avl_test: $(BINDIR)/$(CONFIG)/gpr_avl_test
-gpr_backoff_test: $(BINDIR)/$(CONFIG)/gpr_backoff_test
 gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test
 gpr_cpu_test: $(BINDIR)/$(CONFIG)/gpr_cpu_test
 gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
@@ -1350,6 +1350,7 @@
   $(BINDIR)/$(CONFIG)/alloc_test \
   $(BINDIR)/$(CONFIG)/alpn_test \
   $(BINDIR)/$(CONFIG)/arena_test \
+  $(BINDIR)/$(CONFIG)/backoff_test \
   $(BINDIR)/$(CONFIG)/bad_server_response_test \
   $(BINDIR)/$(CONFIG)/bdp_estimator_test \
   $(BINDIR)/$(CONFIG)/bin_decoder_test \
@@ -1383,7 +1384,6 @@
   $(BINDIR)/$(CONFIG)/fling_test \
   $(BINDIR)/$(CONFIG)/goaway_server_test \
   $(BINDIR)/$(CONFIG)/gpr_avl_test \
-  $(BINDIR)/$(CONFIG)/gpr_backoff_test \
   $(BINDIR)/$(CONFIG)/gpr_cmdline_test \
   $(BINDIR)/$(CONFIG)/gpr_cpu_test \
   $(BINDIR)/$(CONFIG)/gpr_env_test \
@@ -1761,6 +1761,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 )
 	$(E) "[RUN]     Testing arena_test"
 	$(Q) $(BINDIR)/$(CONFIG)/arena_test || ( echo test arena_test failed ; exit 1 )
+	$(E) "[RUN]     Testing backoff_test"
+	$(Q) $(BINDIR)/$(CONFIG)/backoff_test || ( echo test backoff_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bad_server_response_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bdp_estimator_test"
@@ -1823,8 +1825,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/goaway_server_test || ( echo test goaway_server_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_avl_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_avl_test || ( echo test gpr_avl_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_backoff_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_backoff_test || ( echo test gpr_backoff_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cmdline_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_cmdline_test || ( echo test gpr_cmdline_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cpu_test"
@@ -2800,7 +2800,6 @@
     src/core/lib/support/arena.cc \
     src/core/lib/support/atm.cc \
     src/core/lib/support/avl.cc \
-    src/core/lib/support/backoff.cc \
     src/core/lib/support/cmdline.cc \
     src/core/lib/support/cpu_iphone.cc \
     src/core/lib/support/cpu_linux.cc \
@@ -2946,6 +2945,7 @@
 
 LIBGRPC_SRC = \
     src/core/lib/surface/init.cc \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -3297,6 +3297,7 @@
 
 LIBGRPC_CRONET_SRC = \
     src/core/lib/surface/init.cc \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -3615,6 +3616,7 @@
     test/core/util/port_server_client.c \
     test/core/util/slice_splitter.c \
     test/core/util/trickle_endpoint.c \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -3869,6 +3871,7 @@
     test/core/util/port_server_client.c \
     test/core/util/slice_splitter.c \
     test/core/util/trickle_endpoint.c \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -4096,6 +4099,7 @@
 LIBGRPC_UNSECURE_SRC = \
     src/core/lib/surface/init.cc \
     src/core/lib/surface/init_unsecure.cc \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -4836,6 +4840,7 @@
     src/core/ext/transport/chttp2/transport/stream_map.cc \
     src/core/ext/transport/chttp2/transport/varint.cc \
     src/core/ext/transport/chttp2/transport/writing.cc \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -8892,6 +8897,38 @@
 endif
 
 
+BACKOFF_TEST_SRC = \
+    test/core/backoff/backoff_test.c \
+
+BACKOFF_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BACKOFF_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/backoff_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/backoff_test: $(BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/backoff_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/backoff/backoff_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_backoff_test: $(BACKOFF_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BACKOFF_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 BAD_SERVER_RESPONSE_TEST_SRC = \
     test/core/end2end/bad_server_response_test.c \
 
@@ -10111,38 +10148,6 @@
 endif
 
 
-GPR_BACKOFF_TEST_SRC = \
-    test/core/support/backoff_test.c \
-
-GPR_BACKOFF_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_BACKOFF_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_backoff_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/gpr_backoff_test: $(GPR_BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_backoff_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/backoff_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_gpr_backoff_test: $(GPR_BACKOFF_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_BACKOFF_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 GPR_CMDLINE_TEST_SRC = \
     test/core/support/cmdline_test.c \
 
diff --git a/binding.gyp b/binding.gyp
index 1fd4301..91919c3 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -600,7 +600,6 @@
         'src/core/lib/support/arena.cc',
         'src/core/lib/support/atm.cc',
         'src/core/lib/support/avl.cc',
-        'src/core/lib/support/backoff.cc',
         'src/core/lib/support/cmdline.cc',
         'src/core/lib/support/cpu_iphone.cc',
         'src/core/lib/support/cpu_linux.cc',
@@ -658,6 +657,7 @@
       ],
       'sources': [
         'src/core/lib/surface/init.cc',
+        'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
diff --git a/build.yaml b/build.yaml
index 7033d52..d23716a 100644
--- a/build.yaml
+++ b/build.yaml
@@ -66,7 +66,6 @@
   - src/core/lib/support/arena.cc
   - src/core/lib/support/atm.cc
   - src/core/lib/support/avl.cc
-  - src/core/lib/support/backoff.cc
   - src/core/lib/support/cmdline.cc
   - src/core/lib/support/cpu_iphone.cc
   - src/core/lib/support/cpu_linux.cc
@@ -143,8 +142,6 @@
   - src/core/lib/support/atomic.h
   - src/core/lib/support/atomic_with_atm.h
   - src/core/lib/support/atomic_with_std.h
-  - src/core/lib/support/backoff.h
-  - src/core/lib/support/block_annotate.h
   - src/core/lib/support/env.h
   - src/core/lib/support/memory.h
   - src/core/lib/support/mpscq.h
@@ -185,6 +182,7 @@
   - grpc++_codegen_base
 - name: grpc_base
   src:
+  - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
   - src/core/lib/channel/channel_stack.cc
   - src/core/lib/channel/channel_stack_builder.cc
@@ -337,6 +335,7 @@
   - include/grpc/status.h
   - include/grpc/support/workaround_list.h
   headers:
+  - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
   - src/core/lib/channel/channel_stack.h
   - src/core/lib/channel/channel_stack_builder.h
@@ -355,6 +354,7 @@
   - src/core/lib/http/format_request.h
   - src/core/lib/http/httpcli.h
   - src/core/lib/http/parser.h
+  - src/core/lib/iomgr/block_annotate.h
   - src/core/lib/iomgr/call_combiner.h
   - src/core/lib/iomgr/closure.h
   - src/core/lib/iomgr/combiner.h
@@ -1775,6 +1775,16 @@
   deps:
   - gpr_test_util
   - gpr
+- name: backoff_test
+  build: test
+  language: c
+  src:
+  - test/core/backoff/backoff_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: bad_server_response_test
   build: test
   language: c
@@ -2203,14 +2213,6 @@
   deps:
   - gpr_test_util
   - gpr
-- name: gpr_backoff_test
-  build: test
-  language: c
-  src:
-  - test/core/support/backoff_test.c
-  deps:
-  - gpr_test_util
-  - gpr
 - name: gpr_cmdline_test
   build: test
   language: c
diff --git a/config.m4 b/config.m4
index 34d7116..5d92a2a 100644
--- a/config.m4
+++ b/config.m4
@@ -45,7 +45,6 @@
     src/core/lib/support/arena.cc \
     src/core/lib/support/atm.cc \
     src/core/lib/support/avl.cc \
-    src/core/lib/support/backoff.cc \
     src/core/lib/support/cmdline.cc \
     src/core/lib/support/cpu_iphone.cc \
     src/core/lib/support/cpu_linux.cc \
@@ -86,6 +85,7 @@
     src/core/lib/support/tmpfile_windows.cc \
     src/core/lib/support/wrap_memcpy.cc \
     src/core/lib/surface/init.cc \
+    src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
@@ -686,6 +686,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/inproc)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/backoff)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
diff --git a/config.w32 b/config.w32
index 3535582..67b5e2f 100644
--- a/config.w32
+++ b/config.w32
@@ -22,7 +22,6 @@
     "src\\core\\lib\\support\\arena.cc " +
     "src\\core\\lib\\support\\atm.cc " +
     "src\\core\\lib\\support\\avl.cc " +
-    "src\\core\\lib\\support\\backoff.cc " +
     "src\\core\\lib\\support\\cmdline.cc " +
     "src\\core\\lib\\support\\cpu_iphone.cc " +
     "src\\core\\lib\\support\\cpu_linux.cc " +
@@ -63,6 +62,7 @@
     "src\\core\\lib\\support\\tmpfile_windows.cc " +
     "src\\core\\lib\\support\\wrap_memcpy.cc " +
     "src\\core\\lib\\surface\\init.cc " +
+    "src\\core\\lib\\backoff\\backoff.cc " +
     "src\\core\\lib\\channel\\channel_args.cc " +
     "src\\core\\lib\\channel\\channel_stack.cc " +
     "src\\core\\lib\\channel\\channel_stack_builder.cc " +
@@ -699,6 +699,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\chttp2\\transport");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\inproc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\backoff");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\debug");
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index ca5301a..f19b672 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -106,6 +106,8 @@
     ss.source_files = 'include/grpc/support/alloc.h',
                       'include/grpc/support/atm.h',
                       'include/grpc/support/atm_gcc_atomic.h',
+                      'include/grpc/support/atm_gcc_sync.h',
+                      'include/grpc/support/atm_windows.h',
                       'include/grpc/support/avl.h',
                       'include/grpc/support/cmdline.h',
                       'include/grpc/support/cpu.h',
@@ -120,13 +122,18 @@
                       'include/grpc/support/sync_custom.h',
                       'include/grpc/support/sync_generic.h',
                       'include/grpc/support/sync_posix.h',
+                      'include/grpc/support/sync_windows.h',
                       'include/grpc/support/thd.h',
                       'include/grpc/support/time.h',
                       'include/grpc/support/tls.h',
+                      'include/grpc/support/tls_gcc.h',
+                      'include/grpc/support/tls_msvc.h',
                       'include/grpc/support/tls_pthread.h',
                       'include/grpc/support/useful.h',
                       'include/grpc/impl/codegen/atm.h',
                       'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_windows.h',
                       'include/grpc/impl/codegen/gpr_slice.h',
                       'include/grpc/impl/codegen/gpr_types.h',
                       'include/grpc/impl/codegen/port_platform.h',
@@ -134,6 +141,7 @@
                       'include/grpc/impl/codegen/sync_custom.h',
                       'include/grpc/impl/codegen/sync_generic.h',
                       'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_windows.h',
                       'include/grpc/impl/codegen/byte_buffer.h',
                       'include/grpc/impl/codegen/byte_buffer_reader.h',
                       'include/grpc/impl/codegen/compression_types.h',
@@ -145,6 +153,8 @@
                       'include/grpc/impl/codegen/status.h',
                       'include/grpc/impl/codegen/atm.h',
                       'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_windows.h',
                       'include/grpc/impl/codegen/gpr_slice.h',
                       'include/grpc/impl/codegen/gpr_types.h',
                       'include/grpc/impl/codegen/port_platform.h',
@@ -152,6 +162,7 @@
                       'include/grpc/impl/codegen/sync_custom.h',
                       'include/grpc/impl/codegen/sync_generic.h',
                       'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_windows.h',
                       'include/grpc/grpc_security.h',
                       'include/grpc/byte_buffer.h',
                       'include/grpc/byte_buffer_reader.h',
@@ -179,8 +190,6 @@
                       'src/core/lib/support/atomic.h',
                       'src/core/lib/support/atomic_with_atm.h',
                       'src/core/lib/support/atomic_with_std.h',
-                      'src/core/lib/support/backoff.h',
-                      'src/core/lib/support/block_annotate.h',
                       'src/core/lib/support/env.h',
                       'src/core/lib/support/memory.h',
                       'src/core/lib/support/mpscq.h',
@@ -197,7 +206,6 @@
                       'src/core/lib/support/arena.cc',
                       'src/core/lib/support/atm.cc',
                       'src/core/lib/support/avl.cc',
-                      'src/core/lib/support/backoff.cc',
                       'src/core/lib/support/cmdline.cc',
                       'src/core/lib/support/cpu_iphone.cc',
                       'src/core/lib/support/cpu_linux.cc',
@@ -309,6 +317,7 @@
                       'src/core/ext/filters/deadline/deadline_filter.h',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                       'src/core/ext/transport/inproc/inproc_transport.h',
+                      'src/core/lib/backoff/backoff.h',
                       'src/core/lib/channel/channel_args.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
@@ -327,6 +336,7 @@
                       'src/core/lib/http/format_request.h',
                       'src/core/lib/http/httpcli.h',
                       'src/core/lib/http/parser.h',
+                      'src/core/lib/iomgr/block_annotate.h',
                       'src/core/lib/iomgr/call_combiner.h',
                       'src/core/lib/iomgr/closure.h',
                       'src/core/lib/iomgr/combiner.h',
@@ -461,6 +471,7 @@
                       'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
                       'src/core/ext/filters/workarounds/workaround_utils.h',
                       'src/core/lib/surface/init.cc',
+                      'src/core/lib/backoff/backoff.cc',
                       'src/core/lib/channel/channel_args.cc',
                       'src/core/lib/channel/channel_stack.cc',
                       'src/core/lib/channel/channel_stack_builder.cc',
@@ -724,8 +735,6 @@
                               'src/core/lib/support/atomic.h',
                               'src/core/lib/support/atomic_with_atm.h',
                               'src/core/lib/support/atomic_with_std.h',
-                              'src/core/lib/support/backoff.h',
-                              'src/core/lib/support/block_annotate.h',
                               'src/core/lib/support/env.h',
                               'src/core/lib/support/memory.h',
                               'src/core/lib/support/mpscq.h',
@@ -808,6 +817,7 @@
                               'src/core/ext/filters/deadline/deadline_filter.h',
                               'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                               'src/core/ext/transport/inproc/inproc_transport.h',
+                              'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
@@ -826,6 +836,7 @@
                               'src/core/lib/http/format_request.h',
                               'src/core/lib/http/httpcli.h',
                               'src/core/lib/http/parser.h',
+                              'src/core/lib/iomgr/block_annotate.h',
                               'src/core/lib/iomgr/call_combiner.h',
                               'src/core/lib/iomgr/closure.h',
                               'src/core/lib/iomgr/combiner.h',
diff --git a/gRPC.podspec b/gRPC.podspec
index 6bec50f..4c6cd35 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -63,10 +63,13 @@
   end
 
   s.subspec 'GID' do |ss|
+    ss.ios.deployment_target = '7.0'
+
     ss.header_mappings_dir = "#{src_dir}"
 
     ss.source_files = "#{src_dir}/GRPCCall+GID.{h,m}"
 
+    ss.dependency "#{s.name}/Main", version
     ss.dependency 'Google/SignIn'
   end
 end
diff --git a/grpc.gemspec b/grpc.gemspec
index c37859f..ce23e6f 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -88,8 +88,6 @@
   s.files += %w( src/core/lib/support/atomic.h )
   s.files += %w( src/core/lib/support/atomic_with_atm.h )
   s.files += %w( src/core/lib/support/atomic_with_std.h )
-  s.files += %w( src/core/lib/support/backoff.h )
-  s.files += %w( src/core/lib/support/block_annotate.h )
   s.files += %w( src/core/lib/support/env.h )
   s.files += %w( src/core/lib/support/memory.h )
   s.files += %w( src/core/lib/support/mpscq.h )
@@ -106,7 +104,6 @@
   s.files += %w( src/core/lib/support/arena.cc )
   s.files += %w( src/core/lib/support/atm.cc )
   s.files += %w( src/core/lib/support/avl.cc )
-  s.files += %w( src/core/lib/support/backoff.cc )
   s.files += %w( src/core/lib/support/cmdline.cc )
   s.files += %w( src/core/lib/support/cpu_iphone.cc )
   s.files += %w( src/core/lib/support/cpu_linux.cc )
@@ -252,6 +249,7 @@
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
   s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
+  s.files += %w( src/core/lib/backoff/backoff.h )
   s.files += %w( src/core/lib/channel/channel_args.h )
   s.files += %w( src/core/lib/channel/channel_stack.h )
   s.files += %w( src/core/lib/channel/channel_stack_builder.h )
@@ -270,6 +268,7 @@
   s.files += %w( src/core/lib/http/format_request.h )
   s.files += %w( src/core/lib/http/httpcli.h )
   s.files += %w( src/core/lib/http/parser.h )
+  s.files += %w( src/core/lib/iomgr/block_annotate.h )
   s.files += %w( src/core/lib/iomgr/call_combiner.h )
   s.files += %w( src/core/lib/iomgr/closure.h )
   s.files += %w( src/core/lib/iomgr/combiner.h )
@@ -408,6 +407,7 @@
   s.files += %w( src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h )
   s.files += %w( src/core/ext/filters/workarounds/workaround_utils.h )
   s.files += %w( src/core/lib/surface/init.cc )
+  s.files += %w( src/core/lib/backoff/backoff.cc )
   s.files += %w( src/core/lib/channel/channel_args.cc )
   s.files += %w( src/core/lib/channel/channel_stack.cc )
   s.files += %w( src/core/lib/channel/channel_stack_builder.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 5579f02..53e3885 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -164,7 +164,6 @@
         'src/core/lib/support/arena.cc',
         'src/core/lib/support/atm.cc',
         'src/core/lib/support/avl.cc',
-        'src/core/lib/support/backoff.cc',
         'src/core/lib/support/cmdline.cc',
         'src/core/lib/support/cpu_iphone.cc',
         'src/core/lib/support/cpu_linux.cc',
@@ -224,6 +223,7 @@
       ],
       'sources': [
         'src/core/lib/surface/init.cc',
+        'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
@@ -525,6 +525,7 @@
         'test/core/util/port_server_client.c',
         'test/core/util/slice_splitter.c',
         'test/core/util/trickle_endpoint.c',
+        'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
@@ -731,6 +732,7 @@
         'test/core/util/port_server_client.c',
         'test/core/util/slice_splitter.c',
         'test/core/util/trickle_endpoint.c',
+        'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
@@ -922,6 +924,7 @@
       'sources': [
         'src/core/lib/surface/init.cc',
         'src/core/lib/surface/init_unsecure.cc',
+        'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
diff --git a/include/grpc/impl/codegen/atm_gcc_atomic.h b/include/grpc/impl/codegen/atm_gcc_atomic.h
index 1793ec2..76ce863 100644
--- a/include/grpc/impl/codegen/atm_gcc_atomic.h
+++ b/include/grpc/impl/codegen/atm_gcc_atomic.h
@@ -25,6 +25,7 @@
 
 typedef intptr_t gpr_atm;
 #define GPR_ATM_MAX INTPTR_MAX
+#define GPR_ATM_MIN INTPTR_MIN
 
 #ifdef GPR_LOW_LEVEL_COUNTERS
 extern gpr_atm gpr_counter_atm_cas;
diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h
index 27ae0f6..a9e4da3 100644
--- a/include/grpc/impl/codegen/atm_gcc_sync.h
+++ b/include/grpc/impl/codegen/atm_gcc_sync.h
@@ -25,6 +25,7 @@
 
 typedef intptr_t gpr_atm;
 #define GPR_ATM_MAX INTPTR_MAX
+#define GPR_ATM_MIN INTPTR_MIN
 
 #define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory")
 
diff --git a/include/grpc/impl/codegen/atm_windows.h b/include/grpc/impl/codegen/atm_windows.h
index dfcaa4c..b868d79 100644
--- a/include/grpc/impl/codegen/atm_windows.h
+++ b/include/grpc/impl/codegen/atm_windows.h
@@ -24,6 +24,7 @@
 
 typedef intptr_t gpr_atm;
 #define GPR_ATM_MAX INTPTR_MAX
+#define GPR_ATM_MIN INTPTR_MIN
 
 #define gpr_atm_full_barrier MemoryBarrier
 
diff --git a/include/grpc/module.modulemap b/include/grpc/module.modulemap
index 226cc6c..342adc0 100644
--- a/include/grpc/module.modulemap
+++ b/include/grpc/module.modulemap
@@ -4,7 +4,6 @@
 
   header "support/alloc.h"
   header "support/atm.h"
-  header "support/atm_gcc_atomic.h"
   header "support/avl.h"
   header "support/cmdline.h"
   header "support/cpu.h"
@@ -16,23 +15,17 @@
   header "support/string_util.h"
   header "support/subprocess.h"
   header "support/sync.h"
-  header "support/sync_custom.h"
   header "support/sync_generic.h"
-  header "support/sync_posix.h"
   header "support/thd.h"
   header "support/time.h"
   header "support/tls.h"
-  header "support/tls_pthread.h"
   header "support/useful.h"
   header "impl/codegen/atm.h"
-  header "impl/codegen/atm_gcc_atomic.h"
   header "impl/codegen/gpr_slice.h"
   header "impl/codegen/gpr_types.h"
   header "impl/codegen/port_platform.h"
   header "impl/codegen/sync.h"
-  header "impl/codegen/sync_custom.h"
   header "impl/codegen/sync_generic.h"
-  header "impl/codegen/sync_posix.h"
   header "impl/codegen/byte_buffer.h"
   header "impl/codegen/byte_buffer_reader.h"
   header "impl/codegen/compression_types.h"
@@ -43,14 +36,11 @@
   header "impl/codegen/slice.h"
   header "impl/codegen/status.h"
   header "impl/codegen/atm.h"
-  header "impl/codegen/atm_gcc_atomic.h"
   header "impl/codegen/gpr_slice.h"
   header "impl/codegen/gpr_types.h"
   header "impl/codegen/port_platform.h"
   header "impl/codegen/sync.h"
-  header "impl/codegen/sync_custom.h"
   header "impl/codegen/sync_generic.h"
-  header "impl/codegen/sync_posix.h"
   header "grpc_security.h"
   header "byte_buffer.h"
   header "byte_buffer_reader.h"
@@ -65,6 +55,28 @@
   header "support/workaround_list.h"
   header "census.h"
 
+  textual header "support/atm_gcc_atomic.h"
+  textual header "support/atm_gcc_sync.h"
+  textual header "support/atm_windows.h"
+  textual header "support/sync_custom.h"
+  textual header "support/sync_posix.h"
+  textual header "support/sync_windows.h"
+  textual header "support/tls_gcc.h"
+  textual header "support/tls_msvc.h"
+  textual header "support/tls_pthread.h"
+  textual header "impl/codegen/atm_gcc_atomic.h"
+  textual header "impl/codegen/atm_gcc_sync.h"
+  textual header "impl/codegen/atm_windows.h"
+  textual header "impl/codegen/sync_custom.h"
+  textual header "impl/codegen/sync_posix.h"
+  textual header "impl/codegen/sync_windows.h"
+  textual header "impl/codegen/atm_gcc_atomic.h"
+  textual header "impl/codegen/atm_gcc_sync.h"
+  textual header "impl/codegen/atm_windows.h"
+  textual header "impl/codegen/sync_custom.h"
+  textual header "impl/codegen/sync_posix.h"
+  textual header "impl/codegen/sync_windows.h"
+
   export *
   module * { export * }
 }
diff --git a/package.xml b/package.xml
index 3620689..df01421 100644
--- a/package.xml
+++ b/package.xml
@@ -100,8 +100,6 @@
     <file baseinstalldir="/" name="src/core/lib/support/atomic.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atomic_with_atm.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atomic_with_std.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/memory.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/mpscq.h" role="src" />
@@ -118,7 +116,6 @@
     <file baseinstalldir="/" name="src/core/lib/support/arena.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atm.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/avl.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/backoff.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cmdline.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cpu_iphone.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cpu_linux.cc" role="src" />
@@ -264,6 +261,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/backoff/backoff.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
@@ -282,6 +280,7 @@
     <file baseinstalldir="/" name="src/core/lib/http/format_request.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/block_annotate.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/call_combiner.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/combiner.h" role="src" />
@@ -420,6 +419,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/backoff/backoff.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc
index a05a11d..31a8fc3 100644
--- a/src/core/ext/filters/client_channel/channel_connectivity.cc
+++ b/src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -188,8 +188,8 @@
   watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg;
 
   grpc_timer_init(exec_ctx, &wa->w->alarm,
-                  gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC),
-                  &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
+                  grpc_timespec_to_millis_round_up(wa->deadline),
+                  &wa->w->on_timeout);
   gpr_free(wa);
 }
 
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 8bff754..22c2bc8 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -71,7 +71,7 @@
 
 typedef struct {
   gpr_refcount refs;
-  gpr_timespec timeout;
+  grpc_millis timeout;
   wait_for_ready_value wait_for_ready;
 } method_parameters;
 
@@ -101,17 +101,18 @@
   return true;
 }
 
-static bool parse_timeout(grpc_json *field, gpr_timespec *timeout) {
+static bool parse_timeout(grpc_json *field, grpc_millis *timeout) {
   if (field->type != GRPC_JSON_STRING) return false;
   size_t len = strlen(field->value);
   if (field->value[len - 1] != 's') return false;
   char *buf = gpr_strdup(field->value);
   buf[len - 1] = '\0';  // Remove trailing 's'.
   char *decimal_point = strchr(buf, '.');
+  int nanos = 0;
   if (decimal_point != NULL) {
     *decimal_point = '\0';
-    timeout->tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1);
-    if (timeout->tv_nsec == -1) {
+    nanos = gpr_parse_nonnegative_int(decimal_point + 1);
+    if (nanos == -1) {
       gpr_free(buf);
       return false;
     }
@@ -130,24 +131,25 @@
         gpr_free(buf);
         return false;
     }
-    timeout->tv_nsec *= multiplier;
+    nanos *= multiplier;
   }
-  timeout->tv_sec = gpr_parse_nonnegative_int(buf);
+  int seconds = gpr_parse_nonnegative_int(buf);
   gpr_free(buf);
-  if (timeout->tv_sec == -1) return false;
+  if (seconds == -1) return false;
+  *timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
   return true;
 }
 
 static void *method_parameters_create_from_json(const grpc_json *json) {
   wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
-  gpr_timespec timeout = {0, 0, GPR_TIMESPAN};
+  grpc_millis timeout = 0;
   for (grpc_json *field = json->child; field != NULL; field = field->next) {
     if (field->key == NULL) continue;
     if (strcmp(field->key, "waitForReady") == 0) {
       if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL;  // Duplicate.
       if (!parse_wait_for_ready(field, &wait_for_ready)) return NULL;
     } else if (strcmp(field->key, "timeout") == 0) {
-      if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL;  // Duplicate.
+      if (timeout > 0) return NULL;  // Duplicate.
       if (!parse_timeout(field, &timeout)) return NULL;
     }
   }
@@ -826,7 +828,7 @@
 
   grpc_slice path;  // Request path.
   gpr_timespec call_start_time;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   gpr_arena *arena;
   grpc_call_stack *owning_call;
   grpc_call_combiner *call_combiner;
@@ -979,11 +981,11 @@
       // If the deadline from the service config is shorter than the one
       // from the client API, reset the deadline timer.
       if (chand->deadline_checking_enabled &&
-          gpr_time_cmp(calld->method_params->timeout,
-                       gpr_time_0(GPR_TIMESPAN)) != 0) {
-        const gpr_timespec per_method_deadline =
-            gpr_time_add(calld->call_start_time, calld->method_params->timeout);
-        if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
+          calld->method_params->timeout != 0) {
+        const grpc_millis per_method_deadline =
+            grpc_timespec_to_millis_round_up(calld->call_start_time) +
+            calld->method_params->timeout;
+        if (per_method_deadline < calld->deadline) {
           calld->deadline = per_method_deadline;
           grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
         }
@@ -1422,7 +1424,7 @@
   // Initialize data members.
   calld->path = grpc_slice_ref_internal(args->path);
   calld->call_start_time = args->start_time;
-  calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
+  calld->deadline = args->deadline;
   calld->arena = args->arena;
   calld->owning_call = args->call_stack;
   calld->call_combiner = args->call_combiner;
diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
index 79ccb0d..b91c93e 100644
--- a/src/core/ext/filters/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -38,7 +38,7 @@
   /** set of pollsets interested in this connection */
   grpc_pollset_set *interested_parties;
   /** deadline for connection */
-  gpr_timespec deadline;
+  grpc_millis deadline;
   /** channel arguments (to be passed to transport) */
   const grpc_channel_args *channel_args;
 } grpc_connect_in_args;
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index d417bd1..d4037fd 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -103,6 +103,7 @@
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/subchannel_index.h"
+#include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -112,7 +113,6 @@
 #include "src/core/lib/slice/slice_hash_table.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
-#include "src/core/lib/support/backoff.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/channel.h"
@@ -397,7 +397,7 @@
   grpc_slice lb_call_status_details;
 
   /** LB call retry backoff state */
-  gpr_backoff lb_call_backoff_state;
+  grpc_backoff lb_call_backoff_state;
 
   /** LB call retry timer */
   grpc_timer lb_call_retry_timer;
@@ -411,7 +411,7 @@
    * recreated whenever lb_call is replaced. */
   grpc_grpclb_client_stats *client_stats;
   /* Interval and timer for next client load report. */
-  gpr_timespec client_stats_report_interval;
+  grpc_millis client_stats_report_interval;
   grpc_timer client_load_report_timer;
   bool client_load_report_timer_pending;
   bool last_client_load_report_counters_were_zero;
@@ -1010,6 +1010,10 @@
     grpc_timer_cancel(exec_ctx, &glb_policy->lb_call_retry_timer);
     glb_policy->retry_timer_active = false;
   }
+  if (glb_policy->fallback_timer_active) {
+    grpc_timer_cancel(exec_ctx, &glb_policy->lb_fallback_timer);
+    glb_policy->fallback_timer_active = false;
+  }
 
   pending_pick *pp = glb_policy->pending_picks;
   glb_policy->pending_picks = NULL;
@@ -1134,21 +1138,19 @@
   /* start a timer to fall back */
   if (glb_policy->lb_fallback_timeout_ms > 0 &&
       glb_policy->serverlist == NULL && !glb_policy->fallback_timer_active) {
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec deadline = gpr_time_add(
-        now,
-        gpr_time_from_millis(glb_policy->lb_fallback_timeout_ms, GPR_TIMESPAN));
+    grpc_millis deadline =
+        grpc_exec_ctx_now(exec_ctx) + glb_policy->lb_fallback_timeout_ms;
     GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_fallback_timer");
     GRPC_CLOSURE_INIT(&glb_policy->lb_on_fallback, lb_on_fallback_timer_locked,
                       glb_policy,
                       grpc_combiner_scheduler(glb_policy->base.combiner));
     glb_policy->fallback_timer_active = true;
     grpc_timer_init(exec_ctx, &glb_policy->lb_fallback_timer, deadline,
-                    &glb_policy->lb_on_fallback, now);
+                    &glb_policy->lb_on_fallback);
   }
 
   glb_policy->started_picking = true;
-  gpr_backoff_reset(&glb_policy->lb_call_backoff_state);
+  grpc_backoff_reset(&glb_policy->lb_call_backoff_state);
   query_for_backends_locked(exec_ctx, glb_policy);
 }
 
@@ -1274,17 +1276,15 @@
     glb_policy->updating_lb_call = false;
   } else if (!glb_policy->shutting_down) {
     /* if we aren't shutting down, restart the LB client call after some time */
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec next_try =
-        gpr_backoff_step(&glb_policy->lb_call_backoff_state, now);
+    grpc_millis next_try =
+        grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state);
     if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
       gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...",
               (void *)glb_policy);
-      gpr_timespec timeout = gpr_time_sub(next_try, now);
-      if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
-        gpr_log(GPR_DEBUG,
-                "... retry_timer_active in %" PRId64 ".%09d seconds.",
-                timeout.tv_sec, timeout.tv_nsec);
+      grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
+      if (timeout > 0) {
+        gpr_log(GPR_DEBUG, "... retry_timer_active in %" PRIdPTR "ms.",
+                timeout);
       } else {
         gpr_log(GPR_DEBUG, "... retry_timer_active immediately.");
       }
@@ -1295,7 +1295,7 @@
                       grpc_combiner_scheduler(glb_policy->base.combiner));
     glb_policy->retry_timer_active = true;
     grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try,
-                    &glb_policy->lb_on_call_retry, now);
+                    &glb_policy->lb_on_call_retry);
   }
   GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
                             "lb_on_server_status_received_locked");
@@ -1306,15 +1306,14 @@
 
 static void schedule_next_client_load_report(grpc_exec_ctx *exec_ctx,
                                              glb_lb_policy *glb_policy) {
-  const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  const gpr_timespec next_client_load_report_time =
-      gpr_time_add(now, glb_policy->client_stats_report_interval);
+  const grpc_millis next_client_load_report_time =
+      grpc_exec_ctx_now(exec_ctx) + glb_policy->client_stats_report_interval;
   GRPC_CLOSURE_INIT(&glb_policy->client_load_report_closure,
                     send_client_load_report_locked, glb_policy,
                     grpc_combiner_scheduler(glb_policy->base.combiner));
   grpc_timer_init(exec_ctx, &glb_policy->client_load_report_timer,
                   next_client_load_report_time,
-                  &glb_policy->client_load_report_closure, now);
+                  &glb_policy->client_load_report_closure);
 }
 
 static void client_load_report_done_locked(grpc_exec_ctx *exec_ctx, void *arg,
@@ -1408,12 +1407,10 @@
    * glb_policy->base.interested_parties, which is comprised of the polling
    * entities from \a client_channel. */
   grpc_slice host = grpc_slice_from_copied_string(glb_policy->server_name);
-  gpr_timespec deadline =
+  grpc_millis deadline =
       glb_policy->lb_call_timeout_ms == 0
-          ? gpr_inf_future(GPR_CLOCK_MONOTONIC)
-          : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                         gpr_time_from_millis(glb_policy->lb_call_timeout_ms,
-                                              GPR_TIMESPAN));
+          ? GRPC_MILLIS_INF_FUTURE
+          : grpc_exec_ctx_now(exec_ctx) + glb_policy->lb_call_timeout_ms;
   glb_policy->lb_call = grpc_channel_create_pollset_set_call(
       exec_ctx, glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
       glb_policy->base.interested_parties,
@@ -1444,12 +1441,12 @@
                     lb_on_response_received_locked, glb_policy,
                     grpc_combiner_scheduler(glb_policy->base.combiner));
 
-  gpr_backoff_init(&glb_policy->lb_call_backoff_state,
-                   GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
-                   GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
-                   GRPC_GRPCLB_RECONNECT_JITTER,
-                   GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
-                   GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  grpc_backoff_init(&glb_policy->lb_call_backoff_state,
+                    GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
+                    GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
+                    GRPC_GRPCLB_RECONNECT_JITTER,
+                    GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+                    GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
 
   glb_policy->seen_initial_response = false;
   glb_policy->last_client_load_report_counters_were_zero = false;
@@ -1557,7 +1554,7 @@
   memset(ops, 0, sizeof(ops));
   grpc_op *op = ops;
   if (glb_policy->lb_response_payload != NULL) {
-    gpr_backoff_reset(&glb_policy->lb_call_backoff_state);
+    grpc_backoff_reset(&glb_policy->lb_call_backoff_state);
     /* Received data from the LB server. Look inside
      * glb_policy->lb_response_payload, for a serverlist. */
     grpc_byte_buffer_reader bbr;
@@ -1571,16 +1568,14 @@
         (response = grpc_grpclb_initial_response_parse(response_slice)) !=
             NULL) {
       if (response->has_client_stats_report_interval) {
-        glb_policy->client_stats_report_interval =
-            gpr_time_max(gpr_time_from_seconds(1, GPR_TIMESPAN),
-                         grpc_grpclb_duration_to_timespec(
-                             &response->client_stats_report_interval));
+        glb_policy->client_stats_report_interval = GPR_MAX(
+            GPR_MS_PER_SEC, grpc_grpclb_duration_to_millis(
+                                &response->client_stats_report_interval));
         if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
           gpr_log(GPR_INFO,
                   "received initial LB response message; "
-                  "client load reporting interval = %" PRId64 ".%09d sec",
-                  glb_policy->client_stats_report_interval.tv_sec,
-                  glb_policy->client_stats_report_interval.tv_nsec);
+                  "client load reporting interval = %" PRIdPTR " milliseconds",
+                  glb_policy->client_stats_report_interval);
         }
         /* take a weak ref (won't prevent calling of \a glb_shutdown() if the
          * strong ref count goes to zero) to be unref'd in
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
index 8ef6dfc..4d5fb20 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
@@ -299,13 +299,10 @@
   return 0;
 }
 
-gpr_timespec grpc_grpclb_duration_to_timespec(
-    grpc_grpclb_duration *duration_pb) {
-  gpr_timespec duration;
-  duration.tv_sec = duration_pb->has_seconds ? duration_pb->seconds : 0;
-  duration.tv_nsec = duration_pb->has_nanos ? duration_pb->nanos : 0;
-  duration.clock_type = GPR_TIMESPAN;
-  return duration;
+grpc_millis grpc_grpclb_duration_to_millis(grpc_grpclb_duration *duration_pb) {
+  return (grpc_millis)(
+      (duration_pb->has_seconds ? duration_pb->seconds : 0) * GPR_MS_PER_SEC +
+      (duration_pb->has_nanos ? duration_pb->nanos : 0) / GPR_NS_PER_MS);
 }
 
 void grpc_grpclb_initial_response_destroy(
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
index c4a9849..56b9c09 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -81,8 +81,7 @@
 int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
                                  const grpc_grpclb_duration *rhs);
 
-gpr_timespec grpc_grpclb_duration_to_timespec(
-    grpc_grpclb_duration *duration_pb);
+grpc_millis grpc_grpclb_duration_to_millis(grpc_grpclb_duration *duration_pb);
 
 /** Destroy \a initial_response */
 void grpc_grpclb_initial_response_destroy(
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 69f5877..5f7ab98 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -32,13 +32,13 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/gethostname.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/json/json.h"
-#include "src/core/lib/support/backoff.h"
 #include "src/core/lib/support/env.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/service_config.h"
@@ -89,7 +89,7 @@
   bool have_retry_timer;
   grpc_timer retry_timer;
   /** retry backoff state */
-  gpr_backoff backoff_state;
+  grpc_backoff backoff_state;
 
   /** currently resolving addresses */
   grpc_lb_addresses *lb_addresses;
@@ -137,7 +137,7 @@
                                               grpc_resolver *resolver) {
   ares_dns_resolver *r = (ares_dns_resolver *)resolver;
   if (!r->resolving) {
-    gpr_backoff_reset(&r->backoff_state);
+    grpc_backoff_reset(&r->backoff_state);
     dns_ares_start_resolving_locked(exec_ctx, r);
   }
 }
@@ -271,22 +271,20 @@
   } else {
     const char *msg = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
-    gpr_timespec timeout = gpr_time_sub(next_try, now);
+    grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+    grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
     GPR_ASSERT(!r->have_retry_timer);
     r->have_retry_timer = true;
     GRPC_RESOLVER_REF(&r->base, "retry-timer");
-    if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
-      gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
-              timeout.tv_nsec);
+    if (timeout > 0) {
+      gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
     grpc_timer_init(exec_ctx, &r->retry_timer, next_try,
-                    &r->dns_ares_on_retry_timer_locked, now);
+                    &r->dns_ares_on_retry_timer_locked);
   }
   if (r->resolved_result != NULL) {
     grpc_channel_args_destroy(exec_ctx, r->resolved_result);
@@ -307,7 +305,7 @@
   r->next_completion = on_complete;
   r->target_result = target_result;
   if (r->resolved_version == 0 && !r->resolving) {
-    gpr_backoff_reset(&r->backoff_state);
+    grpc_backoff_reset(&r->backoff_state);
     dns_ares_start_resolving_locked(exec_ctx, r);
   } else {
     dns_ares_maybe_finish_next_locked(exec_ctx, r);
@@ -381,11 +379,11 @@
     grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
                                      args->pollset_set);
   }
-  gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
-                   GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
-                   GRPC_DNS_RECONNECT_JITTER,
-                   GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
-                   GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
+                    GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
+                    GRPC_DNS_RECONNECT_JITTER,
+                    GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+                    GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
   GRPC_CLOSURE_INIT(&r->dns_ares_on_retry_timer_locked,
                     dns_ares_on_retry_timer_locked, r,
                     grpc_combiner_scheduler(r->base.combiner));
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 1c093d0..e669b6d 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -27,11 +27,11 @@
 
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/timer.h"
-#include "src/core/lib/support/backoff.h"
 #include "src/core/lib/support/env.h"
 #include "src/core/lib/support/string.h"
 
@@ -70,7 +70,7 @@
   grpc_timer retry_timer;
   grpc_closure on_retry;
   /** retry backoff state */
-  gpr_backoff backoff_state;
+  grpc_backoff backoff_state;
 
   /** currently resolving addresses */
   grpc_resolved_addresses *addresses;
@@ -113,7 +113,7 @@
                                          grpc_resolver *resolver) {
   dns_resolver *r = (dns_resolver *)resolver;
   if (!r->resolving) {
-    gpr_backoff_reset(&r->backoff_state);
+    grpc_backoff_reset(&r->backoff_state);
     dns_start_resolving_locked(exec_ctx, r);
   }
 }
@@ -126,7 +126,7 @@
   r->next_completion = on_complete;
   r->target_result = target_result;
   if (r->resolved_version == 0 && !r->resolving) {
-    gpr_backoff_reset(&r->backoff_state);
+    grpc_backoff_reset(&r->backoff_state);
     dns_start_resolving_locked(exec_ctx, r);
   } else {
     dns_maybe_finish_next_locked(exec_ctx, r);
@@ -153,6 +153,9 @@
   grpc_channel_args *result = NULL;
   GPR_ASSERT(r->resolving);
   r->resolving = false;
+  GRPC_ERROR_REF(error);
+  error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
+                             grpc_slice_from_copied_string(r->name_to_resolve));
   if (r->addresses != NULL) {
     grpc_lb_addresses *addresses = grpc_lb_addresses_create(
         r->addresses->naddrs, NULL /* user_data_vtable */);
@@ -167,23 +170,21 @@
     grpc_resolved_addresses_destroy(r->addresses);
     grpc_lb_addresses_destroy(exec_ctx, addresses);
   } else {
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
-    gpr_timespec timeout = gpr_time_sub(next_try, now);
+    grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+    grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
     GPR_ASSERT(!r->have_retry_timer);
     r->have_retry_timer = true;
     GRPC_RESOLVER_REF(&r->base, "retry-timer");
-    if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
-      gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
-              timeout.tv_nsec);
+    if (timeout > 0) {
+      gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
     GRPC_CLOSURE_INIT(&r->on_retry, dns_on_retry_timer_locked, r,
                       grpc_combiner_scheduler(r->base.combiner));
-    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now);
+    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry);
   }
   if (r->resolved_result != NULL) {
     grpc_channel_args_destroy(exec_ctx, r->resolved_result);
@@ -191,6 +192,7 @@
   r->resolved_result = result;
   r->resolved_version++;
   dns_maybe_finish_next_locked(exec_ctx, r);
+  GRPC_ERROR_UNREF(error);
 
   GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving");
 }
@@ -254,11 +256,11 @@
     grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
                                      args->pollset_set);
   }
-  gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
-                   GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
-                   GRPC_DNS_RECONNECT_JITTER,
-                   GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
-                   GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
+                    GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
+                    GRPC_DNS_RECONNECT_JITTER,
+                    GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+                    GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
   return &r->base;
 }
 
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index bff5001..5710a22 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -31,6 +31,7 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/subchannel_index.h"
 #include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/debug/stats.h"
@@ -38,7 +39,6 @@
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/support/backoff.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/connectivity_state.h"
@@ -118,9 +118,9 @@
   external_state_watcher root_external_state_watcher;
 
   /** next connect attempt time */
-  gpr_timespec next_attempt;
+  grpc_millis next_attempt;
   /** backoff state */
-  gpr_backoff backoff_state;
+  grpc_backoff backoff_state;
   /** do we have an active alarm? */
   bool have_alarm;
   /** have we started the backoff loop */
@@ -364,7 +364,7 @@
       }
     }
   }
-  gpr_backoff_init(
+  grpc_backoff_init(
       &c->backoff_state, initial_backoff_ms,
       fixed_reconnect_backoff ? 1.0
                               : GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
@@ -428,8 +428,7 @@
   }
   if (error == GRPC_ERROR_NONE) {
     gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
-    c->next_attempt =
-        gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
+    c->next_attempt = grpc_backoff_step(exec_ctx, &c->backoff_state);
     continue_connect_locked(exec_ctx, c);
     gpr_mu_unlock(&c->mu);
   } else {
@@ -464,24 +463,22 @@
   c->connecting = true;
   GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
 
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
   if (!c->backoff_begun) {
     c->backoff_begun = true;
-    c->next_attempt = gpr_backoff_begin(&c->backoff_state, now);
+    c->next_attempt = grpc_backoff_begin(exec_ctx, &c->backoff_state);
     continue_connect_locked(exec_ctx, c);
   } else {
     GPR_ASSERT(!c->have_alarm);
     c->have_alarm = true;
-    gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
-    if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
-        0) {
+    const grpc_millis time_til_next =
+        c->next_attempt - grpc_exec_ctx_now(exec_ctx);
+    if (time_til_next <= 0) {
       gpr_log(GPR_INFO, "Retry immediately");
     } else {
-      gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
-              time_til_next.tv_sec, time_til_next.tv_nsec);
+      gpr_log(GPR_INFO, "Retry in %" PRIdPTR " milliseconds", time_til_next);
     }
     GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx);
-    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm, now);
+    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm);
   }
 }
 
diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
index c67ff97..46b29f1 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -107,7 +107,7 @@
   grpc_polling_entity *pollent;
   grpc_slice path;
   gpr_timespec start_time;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   gpr_arena *arena;
   grpc_call_context_element *context;
   grpc_call_combiner *call_combiner;
diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc
index 866ce46..dc194ec 100644
--- a/src/core/ext/filters/deadline/deadline_filter.cc
+++ b/src/core/ext/filters/deadline/deadline_filter.cc
@@ -86,9 +86,8 @@
 // synchronized.
 static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
                                   grpc_call_element* elem,
-                                  gpr_timespec deadline) {
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-  if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) == 0) {
+                                  grpc_millis deadline) {
+  if (deadline == GRPC_MILLIS_INF_FUTURE) {
     return;
   }
   grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
@@ -114,8 +113,7 @@
   }
   GPR_ASSERT(closure != NULL);
   GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
-  grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, closure,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, closure);
 }
 
 // Cancels the deadline timer.
@@ -155,7 +153,7 @@
 struct start_timer_after_init_state {
   bool in_call_combiner;
   grpc_call_element* elem;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   grpc_closure closure;
 };
 static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
@@ -182,14 +180,13 @@
 void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                               grpc_call_stack* call_stack,
                               grpc_call_combiner* call_combiner,
-                              gpr_timespec deadline) {
+                              grpc_millis deadline) {
   grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
   deadline_state->call_stack = call_stack;
   deadline_state->call_combiner = call_combiner;
   // Deadline will always be infinite on servers, so the timer will only be
   // set on clients with a finite deadline.
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-  if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
+  if (deadline != GRPC_MILLIS_INF_FUTURE) {
     // When the deadline passes, we indicate the failure by sending down
     // an op with cancel_error set.  However, we can't send down any ops
     // until after the call stack is fully initialized.  If we start the
@@ -214,7 +211,7 @@
 }
 
 void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                               gpr_timespec new_deadline) {
+                               grpc_millis new_deadline) {
   grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
   cancel_timer_if_needed(exec_ctx, deadline_state);
   start_timer_if_needed(exec_ctx, elem, new_deadline);
diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h
index f4a1110..4a80535 100644
--- a/src/core/ext/filters/deadline/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -56,7 +56,8 @@
 void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                               grpc_call_stack* call_stack,
                               grpc_call_combiner* call_combiner,
-                              gpr_timespec deadline);
+                              grpc_millis deadline);
+
 void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
                                  grpc_call_element* elem);
 
@@ -70,7 +71,7 @@
 //
 // Note: Must be called while holding the call combiner.
 void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                               gpr_timespec new_deadline);
+                               grpc_millis new_deadline);
 
 // To be called from the client-side filter's start_transport_stream_op_batch()
 // method.  Ensures that the deadline timer is cancelled when the call
diff --git a/src/core/ext/filters/max_age/max_age_filter.cc b/src/core/ext/filters/max_age/max_age_filter.cc
index f4d5b14..ade2e5b 100644
--- a/src/core/ext/filters/max_age/max_age_filter.cc
+++ b/src/core/ext/filters/max_age/max_age_filter.cc
@@ -56,11 +56,11 @@
      max_connection_idle */
   grpc_timer max_idle_timer;
   /* Allowed max time a channel may have no outstanding rpcs */
-  gpr_timespec max_connection_idle;
+  grpc_millis max_connection_idle;
   /* Allowed max time a channel may exist */
-  gpr_timespec max_connection_age;
+  grpc_millis max_connection_age;
   /* Allowed grace period after the channel reaches its max age */
-  gpr_timespec max_connection_age_grace;
+  grpc_millis max_connection_age_grace;
   /* Closure to run when the channel's idle duration reaches max_connection_idle
      and should be closed gracefully */
   grpc_closure close_max_idle_channel;
@@ -99,10 +99,9 @@
 static void decrease_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) {
   if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
     GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_idle_timer");
-    grpc_timer_init(
-        exec_ctx, &chand->max_idle_timer,
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_idle),
-        &chand->close_max_idle_channel, gpr_now(GPR_CLOCK_MONOTONIC));
+    grpc_timer_init(exec_ctx, &chand->max_idle_timer,
+                    grpc_exec_ctx_now(exec_ctx) + chand->max_connection_idle,
+                    &chand->close_max_idle_channel);
   }
 }
 
@@ -123,10 +122,9 @@
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_timer_pending = true;
   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
-  grpc_timer_init(
-      exec_ctx, &chand->max_age_timer,
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_age),
-      &chand->close_max_age_channel, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &chand->max_age_timer,
+                  grpc_exec_ctx_now(exec_ctx) + chand->max_connection_age,
+                  &chand->close_max_age_channel);
   gpr_mu_unlock(&chand->max_age_timer_mu);
   grpc_transport_op* op = grpc_make_transport_op(NULL);
   op->on_connectivity_state_change = &chand->channel_connectivity_changed,
@@ -144,11 +142,12 @@
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_grace_timer_pending = true;
   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
-  grpc_timer_init(exec_ctx, &chand->max_age_grace_timer,
-                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                               chand->max_connection_age_grace),
-                  &chand->force_close_max_age_channel,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(
+      exec_ctx, &chand->max_age_grace_timer,
+      chand->max_connection_age_grace == GRPC_MILLIS_INF_FUTURE
+          ? GRPC_MILLIS_INF_FUTURE
+          : grpc_exec_ctx_now(exec_ctx) + chand->max_connection_age_grace,
+      &chand->force_close_max_age_channel);
   gpr_mu_unlock(&chand->max_age_timer_mu);
   GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
                            "max_age start_max_age_grace_timer_after_goaway_op");
@@ -249,7 +248,8 @@
    connection storms. Note that the MAX_CONNECTION_AGE option without jitter
    would not create connection storms by itself, but if there happened to be a
    connection storm it could cause it to repeat at a fixed period. */
-static int add_random_max_connection_age_jitter(int value) {
+static grpc_millis
+add_random_max_connection_age_jitter_and_convert_to_grpc_millis(int value) {
   /* generate a random number between 1 - MAX_CONNECTION_AGE_JITTER and
      1 + MAX_CONNECTION_AGE_JITTER */
   double multiplier = rand() * MAX_CONNECTION_AGE_JITTER * 2.0 / RAND_MAX +
@@ -257,7 +257,9 @@
   double result = multiplier * value;
   /* INT_MAX - 0.5 converts the value to float, so that result will not be
      cast to int implicitly before the comparison. */
-  return result > INT_MAX - 0.5 ? INT_MAX : (int)result;
+  return result > ((double)GRPC_MILLIS_INF_FUTURE) - 0.5
+             ? GRPC_MILLIS_INF_FUTURE
+             : (grpc_millis)result;
 }
 
 /* Constructor for call_data. */
@@ -287,45 +289,36 @@
   chand->max_age_grace_timer_pending = false;
   chand->channel_stack = args->channel_stack;
   chand->max_connection_age =
-      DEFAULT_MAX_CONNECTION_AGE_MS == INT_MAX
-          ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_millis(add_random_max_connection_age_jitter(
-                                     DEFAULT_MAX_CONNECTION_AGE_MS),
-                                 GPR_TIMESPAN);
+      add_random_max_connection_age_jitter_and_convert_to_grpc_millis(
+          DEFAULT_MAX_CONNECTION_AGE_MS);
   chand->max_connection_age_grace =
       DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX
-          ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_GRACE_MS,
-                                 GPR_TIMESPAN);
-  chand->max_connection_idle =
-      DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX
-          ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_millis(DEFAULT_MAX_CONNECTION_IDLE_MS, GPR_TIMESPAN);
+          ? GRPC_MILLIS_INF_FUTURE
+          : DEFAULT_MAX_CONNECTION_AGE_GRACE_MS;
+  chand->max_connection_idle = DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX
+                                   ? GRPC_MILLIS_INF_FUTURE
+                                   : DEFAULT_MAX_CONNECTION_IDLE_MS;
   for (size_t i = 0; i < args->channel_args->num_args; ++i) {
     if (0 == strcmp(args->channel_args->args[i].key,
                     GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
       const int value = grpc_channel_arg_get_integer(
           &args->channel_args->args[i], MAX_CONNECTION_AGE_INTEGER_OPTIONS);
       chand->max_connection_age =
-          value == INT_MAX
-              ? gpr_inf_future(GPR_TIMESPAN)
-              : gpr_time_from_millis(
-                    add_random_max_connection_age_jitter(value), GPR_TIMESPAN);
+          add_random_max_connection_age_jitter_and_convert_to_grpc_millis(
+              value);
     } else if (0 == strcmp(args->channel_args->args[i].key,
                            GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) {
       const int value = grpc_channel_arg_get_integer(
           &args->channel_args->args[i],
           {DEFAULT_MAX_CONNECTION_AGE_GRACE_MS, 0, INT_MAX});
       chand->max_connection_age_grace =
-          value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
-                           : gpr_time_from_millis(value, GPR_TIMESPAN);
+          value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
     } else if (0 == strcmp(args->channel_args->args[i].key,
                            GRPC_ARG_MAX_CONNECTION_IDLE_MS)) {
       const int value = grpc_channel_arg_get_integer(
           &args->channel_args->args[i], MAX_CONNECTION_IDLE_INTEGER_OPTIONS);
       chand->max_connection_idle =
-          value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
-                           : gpr_time_from_millis(value, GPR_TIMESPAN);
+          value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
     }
   }
   GRPC_CLOSURE_INIT(&chand->close_max_idle_channel, close_max_idle_channel,
@@ -348,8 +341,7 @@
                     channel_connectivity_changed, chand,
                     grpc_schedule_on_exec_ctx);
 
-  if (gpr_time_cmp(chand->max_connection_age, gpr_inf_future(GPR_TIMESPAN)) !=
-      0) {
+  if (chand->max_connection_age != GRPC_MILLIS_INF_FUTURE) {
     /* When the channel reaches its max age, we send down an op with
        goaway_error set.  However, we can't send down any ops until after the
        channel stack is fully initialized.  If we start the timer here, we have
@@ -366,8 +358,7 @@
   /* Initialize the number of calls as 1, so that the max_idle_timer will not
      start until start_max_idle_timer_after_init is invoked. */
   gpr_atm_rel_store(&chand->call_count, 1);
-  if (gpr_time_cmp(chand->max_connection_idle, gpr_inf_future(GPR_TIMESPAN)) !=
-      0) {
+  if (chand->max_connection_idle != GRPC_MILLIS_INF_FUTURE) {
     GRPC_CHANNEL_STACK_REF(chand->channel_stack,
                            "max_age start_max_idle_timer_after_init");
     GRPC_CLOSURE_SCHED(exec_ctx, &chand->start_max_idle_timer_after_init,
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc
index a51959b..7ac7f4e 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.cc
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc
@@ -134,8 +134,8 @@
                        connection_state->handshake_mgr);
   // TODO(roth): We should really get this timeout value from channel
   // args instead of hard-coding it.
-  const gpr_timespec deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
+  const grpc_millis deadline =
+      grpc_exec_ctx_now(exec_ctx) + 120 * GPR_MS_PER_SEC;
   grpc_handshake_manager_do_handshake(exec_ctx, connection_state->handshake_mgr,
                                       tcp, state->args, deadline, acceptor,
                                       on_handshake_done, connection_state);
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 65167c0..e4b19a2 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -159,11 +159,9 @@
 
 static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                          grpc_error *error);
-static void send_ping_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-    grpc_chttp2_ping_type ping_type, grpc_closure *on_initiate,
-    grpc_closure *on_complete,
-    grpc_chttp2_initiate_write_reason initiate_write_reason);
+static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                             grpc_closure *on_initiate,
+                             grpc_closure *on_complete);
 static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
                                        grpc_error *error);
 
@@ -279,6 +277,7 @@
   t->is_client = is_client;
   t->flow_control.remote_window = DEFAULT_WINDOW;
   t->flow_control.announced_window = DEFAULT_WINDOW;
+  t->flow_control.target_initial_window_size = DEFAULT_WINDOW;
   t->flow_control.t = t;
   t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
   t->is_first_frame = true;
@@ -317,17 +316,6 @@
                     grpc_combiner_scheduler(t->combiner));
 
   grpc_bdp_estimator_init(&t->flow_control.bdp_estimator, t->peer_string);
-  t->flow_control.last_pid_update = gpr_now(GPR_CLOCK_MONOTONIC);
-  grpc_pid_controller_init(&t->flow_control.pid_controller,
-                           {
-                               4,                    /* gain_p */
-                               8,                    /* gain_t */
-                               0,                    /* gain_d */
-                               log2(DEFAULT_WINDOW), /* initial_control_value */
-                               -1,                   /* min_control_value */
-                               25,                   /* max_control_value */
-                               10                    /* integral_range */
-                           });
 
   grpc_chttp2_goaway_parser_init(&t->goaway_parser);
   grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
@@ -366,43 +354,33 @@
     queue_setting_update(exec_ctx, t,
                          GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
   }
-  queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
-                       DEFAULT_WINDOW);
   queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
                        DEFAULT_MAX_HEADER_LIST_SIZE);
   queue_setting_update(exec_ctx, t,
                        GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1);
 
   t->ping_policy.max_pings_without_data = g_default_max_pings_without_data;
-  t->ping_policy.min_sent_ping_interval_without_data = gpr_time_from_millis(
-      g_default_min_sent_ping_interval_without_data_ms, GPR_TIMESPAN);
+  t->ping_policy.min_sent_ping_interval_without_data =
+      g_default_min_sent_ping_interval_without_data_ms;
   t->ping_policy.max_ping_strikes = g_default_max_ping_strikes;
-  t->ping_policy.min_recv_ping_interval_without_data = gpr_time_from_millis(
-      g_default_min_recv_ping_interval_without_data_ms, GPR_TIMESPAN);
+  t->ping_policy.min_recv_ping_interval_without_data =
+      g_default_min_recv_ping_interval_without_data_ms;
 
   /* Keepalive setting */
   if (t->is_client) {
-    t->keepalive_time =
-        g_default_client_keepalive_time_ms == INT_MAX
-            ? gpr_inf_future(GPR_TIMESPAN)
-            : gpr_time_from_millis(g_default_client_keepalive_time_ms,
-                                   GPR_TIMESPAN);
-    t->keepalive_timeout =
-        g_default_client_keepalive_timeout_ms == INT_MAX
-            ? gpr_inf_future(GPR_TIMESPAN)
-            : gpr_time_from_millis(g_default_client_keepalive_timeout_ms,
-                                   GPR_TIMESPAN);
+    t->keepalive_time = g_default_client_keepalive_time_ms == INT_MAX
+                            ? GRPC_MILLIS_INF_FUTURE
+                            : g_default_client_keepalive_time_ms;
+    t->keepalive_timeout = g_default_client_keepalive_timeout_ms == INT_MAX
+                               ? GRPC_MILLIS_INF_FUTURE
+                               : g_default_client_keepalive_timeout_ms;
   } else {
-    t->keepalive_time =
-        g_default_server_keepalive_time_ms == INT_MAX
-            ? gpr_inf_future(GPR_TIMESPAN)
-            : gpr_time_from_millis(g_default_server_keepalive_time_ms,
-                                   GPR_TIMESPAN);
-    t->keepalive_timeout =
-        g_default_server_keepalive_timeout_ms == INT_MAX
-            ? gpr_inf_future(GPR_TIMESPAN)
-            : gpr_time_from_millis(g_default_server_keepalive_timeout_ms,
-                                   GPR_TIMESPAN);
+    t->keepalive_time = g_default_server_keepalive_time_ms == INT_MAX
+                            ? GRPC_MILLIS_INF_FUTURE
+                            : g_default_server_keepalive_time_ms;
+    t->keepalive_timeout = g_default_server_keepalive_timeout_ms == INT_MAX
+                               ? GRPC_MILLIS_INF_FUTURE
+                               : g_default_server_keepalive_timeout_ms;
   }
   t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls;
 
@@ -447,23 +425,21 @@
                      channel_args->args[i].key,
                      GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS)) {
         t->ping_policy.min_sent_ping_interval_without_data =
-            gpr_time_from_millis(
-                grpc_channel_arg_get_integer(
-                    &channel_args->args[i],
-                    {g_default_min_sent_ping_interval_without_data_ms, 0,
-                     INT_MAX}),
-                GPR_TIMESPAN);
+            grpc_channel_arg_get_integer(
+                &channel_args->args[i],
+                grpc_integer_options{
+                    g_default_min_sent_ping_interval_without_data_ms, 0,
+                    INT_MAX});
       } else if (0 ==
                  strcmp(
                      channel_args->args[i].key,
                      GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)) {
         t->ping_policy.min_recv_ping_interval_without_data =
-            gpr_time_from_millis(
-                grpc_channel_arg_get_integer(
-                    &channel_args->args[i],
-                    {g_default_min_recv_ping_interval_without_data_ms, 0,
-                     INT_MAX}),
-                GPR_TIMESPAN);
+            grpc_channel_arg_get_integer(
+                &channel_args->args[i],
+                grpc_integer_options{
+                    g_default_min_recv_ping_interval_without_data_ms, 0,
+                    INT_MAX});
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
         t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
@@ -476,22 +452,21 @@
                              GRPC_ARG_KEEPALIVE_TIME_MS)) {
         const int value = grpc_channel_arg_get_integer(
             &channel_args->args[i],
-            {t->is_client ? g_default_client_keepalive_time_ms
-                          : g_default_server_keepalive_time_ms,
-             1, INT_MAX});
-        t->keepalive_time = value == INT_MAX
-                                ? gpr_inf_future(GPR_TIMESPAN)
-                                : gpr_time_from_millis(value, GPR_TIMESPAN);
+            grpc_integer_options{t->is_client
+                                     ? g_default_client_keepalive_time_ms
+                                     : g_default_server_keepalive_time_ms,
+                                 1, INT_MAX});
+        t->keepalive_time = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
         const int value = grpc_channel_arg_get_integer(
             &channel_args->args[i],
-            {t->is_client ? g_default_client_keepalive_timeout_ms
-                          : g_default_server_keepalive_timeout_ms,
-             0, INT_MAX});
-        t->keepalive_timeout = value == INT_MAX
-                                   ? gpr_inf_future(GPR_TIMESPAN)
-                                   : gpr_time_from_millis(value, GPR_TIMESPAN);
+            grpc_integer_options{t->is_client
+                                     ? g_default_client_keepalive_timeout_ms
+                                     : g_default_server_keepalive_timeout_ms,
+                                 0, INT_MAX});
+        t->keepalive_timeout =
+            value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
         t->keepalive_permit_without_calls =
@@ -571,23 +546,27 @@
   t->ping_state.pings_before_data_required = 0;
   t->ping_state.is_delayed_ping_timer_set = false;
 
-  t->ping_recv_state.last_ping_recv_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+  t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
   t->ping_recv_state.ping_strikes = 0;
 
   /* Start keepalive pings */
-  if (gpr_time_cmp(t->keepalive_time, gpr_inf_future(GPR_TIMESPAN)) != 0) {
+  if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) {
     t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
     GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
-    grpc_timer_init(
-        exec_ctx, &t->keepalive_ping_timer,
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
-        &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+    grpc_timer_init(exec_ctx, &t->keepalive_ping_timer,
+                    grpc_exec_ctx_now(exec_ctx) + t->keepalive_time,
+                    &t->init_keepalive_ping_locked);
   } else {
     /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no
        inflight keeaplive timers */
     t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
   }
 
+  grpc_chttp2_act_on_flowctl_action(
+      exec_ctx,
+      grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
+      NULL);
+
   grpc_chttp2_initiate_write(exec_ctx, t,
                              GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE);
   post_benign_reclaimer(exec_ctx, t);
@@ -698,7 +677,7 @@
   grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena);
   grpc_chttp2_data_parser_init(&s->data_parser);
   grpc_slice_buffer_init(&s->flow_controlled_buffer);
-  s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  s->deadline = GRPC_MILLIS_INF_FUTURE;
   GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s,
                     grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer);
@@ -902,9 +881,6 @@
     case GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS:
       GRPC_STATS_INC_HTTP2_INITIATE_WRITE_DUE_TO_SEND_SETTINGS(exec_ctx);
       break;
-    case GRPC_CHTTP2_INITIATE_WRITE_BDP_ESTIMATOR_PING:
-      GRPC_STATS_INC_HTTP2_INITIATE_WRITE_DUE_TO_BDP_ESTIMATOR_PING(exec_ctx);
-      break;
     case GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING:
       GRPC_STATS_INC_HTTP2_INITIATE_WRITE_DUE_TO_FLOW_CONTROL_UNSTALLED_BY_SETTING(
           exec_ctx);
@@ -1042,6 +1018,7 @@
                                                    write_action, t, scheduler),
                        GRPC_ERROR_NONE);
   } else {
+    GRPC_STATS_INC_HTTP2_SPURIOUS_WRITES_BEGUN(exec_ctx);
     set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE,
                     "begin writing nothing");
     GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
@@ -1140,14 +1117,12 @@
     gpr_log(GPR_ERROR,
             "Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug "
             "data equal to \"too_many_pings\"");
-    double current_keepalive_time_ms =
-        gpr_timespec_to_micros(t->keepalive_time) / 1000;
+    double current_keepalive_time_ms = (double)t->keepalive_time;
     t->keepalive_time =
         current_keepalive_time_ms > INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER
-            ? gpr_inf_future(GPR_TIMESPAN)
-            : gpr_time_from_millis((int64_t)(current_keepalive_time_ms *
-                                             KEEPALIVE_TIME_BACKOFF_MULTIPLIER),
-                                   GPR_TIMESPAN);
+            ? GRPC_MILLIS_INF_FUTURE
+            : (grpc_millis)(current_keepalive_time_ms *
+                            KEEPALIVE_TIME_BACKOFF_MULTIPLIER);
   }
 
   /* lie: use transient failure from the transport to indicate goaway has been
@@ -1461,8 +1436,7 @@
         t->settings[GRPC_PEER_SETTINGS]
                    [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
     if (t->is_client) {
-      s->deadline =
-          gpr_time_min(s->deadline, s->send_initial_metadata->deadline);
+      s->deadline = GPR_MIN(s->deadline, s->send_initial_metadata->deadline);
     }
     if (metadata_size > metadata_peer_limit) {
       grpc_chttp2_cancel_stream(
@@ -1646,8 +1620,8 @@
             &t->flow_control, &s->flow_control, GRPC_HEADER_SIZE_IN_BYTES,
             already_received);
         grpc_chttp2_act_on_flowctl_action(
-            exec_ctx,
-            grpc_chttp2_flowctl_get_action(&t->flow_control, &s->flow_control),
+            exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
+                                                     &s->flow_control),
             t, s);
       }
     }
@@ -1680,16 +1654,14 @@
 
   if (!t->is_client) {
     if (op->send_initial_metadata) {
-      gpr_timespec deadline =
+      grpc_millis deadline =
           op->payload->send_initial_metadata.send_initial_metadata->deadline;
-      GPR_ASSERT(0 ==
-                 gpr_time_cmp(gpr_inf_future(deadline.clock_type), deadline));
+      GPR_ASSERT(deadline == GRPC_MILLIS_INF_FUTURE);
     }
     if (op->send_trailing_metadata) {
-      gpr_timespec deadline =
+      grpc_millis deadline =
           op->payload->send_trailing_metadata.send_trailing_metadata->deadline;
-      GPR_ASSERT(0 ==
-                 gpr_time_cmp(gpr_inf_future(deadline.clock_type), deadline));
+      GPR_ASSERT(deadline == GRPC_MILLIS_INF_FUTURE);
     }
   }
 
@@ -1713,28 +1685,21 @@
                          grpc_error *error) {
   /* callback remaining pings: they're not allowed to call into the transpot,
      and maybe they hold resources that need to be freed */
-  for (size_t i = 0; i < GRPC_CHTTP2_PING_TYPE_COUNT; i++) {
-    grpc_chttp2_ping_queue *pq = &t->ping_queues[i];
-    for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) {
-      grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
-      GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]);
-    }
+  grpc_chttp2_ping_queue *pq = &t->ping_queue;
+  for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) {
+    grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
+    GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]);
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void send_ping_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-    grpc_chttp2_ping_type ping_type, grpc_closure *on_initiate,
-    grpc_closure *on_ack,
-    grpc_chttp2_initiate_write_reason initiate_write_reason) {
-  grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type];
+static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                             grpc_closure *on_initiate, grpc_closure *on_ack) {
+  grpc_chttp2_ping_queue *pq = &t->ping_queue;
   grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate,
                            GRPC_ERROR_NONE);
-  if (grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT], on_ack,
-                               GRPC_ERROR_NONE)) {
-    grpc_chttp2_initiate_write(exec_ctx, t, initiate_write_reason);
-  }
+  grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT], on_ack,
+                           GRPC_ERROR_NONE);
 }
 
 static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
@@ -1749,8 +1714,7 @@
 
 void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           uint64_t id) {
-  grpc_chttp2_ping_queue *pq =
-      &t->ping_queues[id % GRPC_CHTTP2_PING_TYPE_COUNT];
+  grpc_chttp2_ping_queue *pq = &t->ping_queue;
   if (pq->inflight_id != id) {
     char *from = grpc_endpoint_get_peer(t->ep);
     gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, from, id);
@@ -1769,8 +1733,8 @@
   t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
   grpc_http2_error_code http_error;
   grpc_slice slice;
-  grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL,
-                        &slice, &http_error);
+  grpc_error_get_status(exec_ctx, error, GRPC_MILLIS_INF_FUTURE, NULL, &slice,
+                        &http_error);
   grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
                             grpc_slice_ref_internal(slice), &t->qbuf);
   grpc_chttp2_initiate_write(exec_ctx, t,
@@ -1780,7 +1744,7 @@
 
 void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
                                  grpc_chttp2_transport *t) {
-  gpr_log(GPR_DEBUG, "PING strike");
+  t->ping_recv_state.ping_strikes++;
   if (++t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes &&
       t->ping_policy.max_ping_strikes != 0) {
     send_goaway(exec_ctx, t,
@@ -1820,9 +1784,9 @@
   }
 
   if (op->send_ping) {
-    send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, NULL,
-                     op->send_ping,
-                     GRPC_CHTTP2_INITIATE_WRITE_APPLICATION_PING);
+    send_ping_locked(exec_ctx, t, NULL, op->send_ping);
+    grpc_chttp2_initiate_write(exec_ctx, t,
+                               GRPC_CHTTP2_INITIATE_WRITE_APPLICATION_PING);
   }
 
   if (op->on_connectivity_state_change != NULL) {
@@ -2069,7 +2033,8 @@
   if (!s->read_closed || !s->write_closed) {
     if (s->id != 0) {
       grpc_http2_error_code http_error;
-      grpc_error_get_status(due_to_error, s->deadline, NULL, NULL, &http_error);
+      grpc_error_get_status(exec_ctx, due_to_error, s->deadline, NULL, NULL,
+                            &http_error);
       grpc_slice_buffer_add(
           &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
                                                   &s->stats.outgoing));
@@ -2087,7 +2052,7 @@
                              grpc_chttp2_stream *s, grpc_error *error) {
   grpc_status_code status;
   grpc_slice slice;
-  grpc_error_get_status(error, s->deadline, &status, &slice, NULL);
+  grpc_error_get_status(exec_ctx, error, s->deadline, &status, &slice, NULL);
 
   if (status != GRPC_STATUS_OK) {
     s->seen_error = true;
@@ -2252,7 +2217,8 @@
   uint32_t len = 0;
   grpc_status_code grpc_status;
   grpc_slice slice;
-  grpc_error_get_status(error, s->deadline, &grpc_status, &slice, NULL);
+  grpc_error_get_status(exec_ctx, error, s->deadline, &grpc_status, &slice,
+                        NULL);
 
   GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
 
@@ -2469,10 +2435,8 @@
   if (action.need_ping) {
     GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
     grpc_bdp_estimator_schedule_ping(&t->flow_control.bdp_estimator);
-    send_ping_locked(exec_ctx, t,
-                     GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE,
-                     &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked,
-                     GRPC_CHTTP2_INITIATE_WRITE_BDP_ESTIMATOR_PING);
+    send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
+                     &t->finish_bdp_ping_locked);
   }
 }
 
@@ -2580,7 +2544,8 @@
     grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer,
                        &t->read_action_locked);
     grpc_chttp2_act_on_flowctl_action(
-        exec_ctx, grpc_chttp2_flowctl_get_bdp_action(&t->flow_control), t,
+        exec_ctx,
+        grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
         NULL);
     GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
   } else {
@@ -2613,7 +2578,7 @@
   if (GRPC_TRACER_ON(grpc_http_trace)) {
     gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string);
   }
-  grpc_bdp_estimator_complete_ping(&t->flow_control.bdp_estimator);
+  grpc_bdp_estimator_complete_ping(exec_ctx, &t->flow_control.bdp_estimator);
 
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 }
@@ -2687,24 +2652,22 @@
         grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
       GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end");
-      send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE,
-                       &t->start_keepalive_ping_locked,
-                       &t->finish_keepalive_ping_locked,
-                       GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING);
+      send_ping_locked(exec_ctx, t, &t->start_keepalive_ping_locked,
+                       &t->finish_keepalive_ping_locked);
+      grpc_chttp2_initiate_write(exec_ctx, t,
+                                 GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING);
     } else {
       GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
-      grpc_timer_init(
-          exec_ctx, &t->keepalive_ping_timer,
-          gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
-          &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+      grpc_timer_init(exec_ctx, &t->keepalive_ping_timer,
+                      grpc_exec_ctx_now(exec_ctx) + t->keepalive_time,
+                      &t->init_keepalive_ping_locked);
     }
   } else if (error == GRPC_ERROR_CANCELLED) {
     /* The keepalive ping timer may be cancelled by bdp */
     GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
-    grpc_timer_init(
-        exec_ctx, &t->keepalive_ping_timer,
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
-        &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+    grpc_timer_init(exec_ctx, &t->keepalive_ping_timer,
+                    grpc_exec_ctx_now(exec_ctx) + t->keepalive_time,
+                    &t->init_keepalive_ping_locked);
   }
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "init keepalive ping");
 }
@@ -2713,10 +2676,9 @@
                                         grpc_error *error) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg;
   GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog");
-  grpc_timer_init(
-      exec_ctx, &t->keepalive_watchdog_timer,
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_timeout),
-      &t->keepalive_watchdog_fired_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &t->keepalive_watchdog_timer,
+                  grpc_exec_ctx_now(exec_ctx) + t->keepalive_time,
+                  &t->keepalive_watchdog_fired_locked);
 }
 
 static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
@@ -2727,10 +2689,9 @@
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
       grpc_timer_cancel(exec_ctx, &t->keepalive_watchdog_timer);
       GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
-      grpc_timer_init(
-          exec_ctx, &t->keepalive_ping_timer,
-          gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
-          &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+      grpc_timer_init(exec_ctx, &t->keepalive_ping_timer,
+                      grpc_exec_ctx_now(exec_ctx) + t->keepalive_time,
+                      &t->init_keepalive_ping_locked);
     }
   }
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive ping end");
@@ -2830,9 +2791,9 @@
                                            bs->next_action.max_size_hint,
                                            cur_length);
     grpc_chttp2_act_on_flowctl_action(
-        exec_ctx,
-        grpc_chttp2_flowctl_get_action(&t->flow_control, &s->flow_control), t,
-        s);
+        exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
+                                                 &s->flow_control),
+        t, s);
   }
   GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
   if (s->frame_storage.length > 0) {
@@ -3180,8 +3141,6 @@
       return "TRANSPORT_FLOW_CONTROL";
     case GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS:
       return "SEND_SETTINGS";
-    case GRPC_CHTTP2_INITIATE_WRITE_BDP_ESTIMATOR_PING:
-      return "BDP_ESTIMATOR_PING";
     case GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING:
       return "FLOW_CONTROL_UNSTALLED_BY_SETTING";
     case GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_UPDATE:
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 75eae1f..2428e25 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -176,11 +176,9 @@
 /* How many bytes of incoming flow control would we like to advertise */
 static uint32_t grpc_chttp2_target_announced_window(
     const grpc_chttp2_transport_flowctl* tfc) {
-  return (uint32_t)GPR_MIN(
-      (int64_t)((1u << 31) - 1),
-      tfc->announced_stream_total_over_incoming_window +
-          tfc->t->settings[GRPC_SENT_SETTINGS]
-                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
+  return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1),
+                           tfc->announced_stream_total_over_incoming_window +
+                               tfc->target_initial_window_size);
 }
 
 // we have sent data on the wire, we must track this in our bookkeeping for the
@@ -282,13 +280,14 @@
 // Returns a non zero announce integer if we should send a transport window
 // update
 uint32_t grpc_chttp2_flowctl_maybe_send_transport_update(
-    grpc_chttp2_transport_flowctl* tfc) {
+    grpc_chttp2_transport_flowctl* tfc, bool writing_anyway) {
   PRETRACE(tfc, NULL);
   uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc);
   uint32_t threshold_to_send_transport_window_update =
       tfc->t->outbuf.count > 0 ? 3 * target_announced_window / 4
                                : target_announced_window / 2;
-  if (tfc->announced_window <= threshold_to_send_transport_window_update &&
+  if ((writing_anyway ||
+       tfc->announced_window <= threshold_to_send_transport_window_update) &&
       tfc->announced_window != target_announced_window) {
     uint32_t announce = (uint32_t)GPR_CLAMP(
         target_announced_window - tfc->announced_window, 0, UINT32_MAX);
@@ -393,15 +392,27 @@
 
 // Takes in a target and uses the pid controller to return a stabilized
 // guess at the new bdp.
-static double get_pid_controller_guess(grpc_chttp2_transport_flowctl* tfc,
+static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx,
+                                       grpc_chttp2_transport_flowctl* tfc,
                                        double target) {
-  double bdp_error = target - grpc_pid_controller_last(&tfc->pid_controller);
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  gpr_timespec dt_timespec = gpr_time_sub(now, tfc->last_pid_update);
-  double dt = (double)dt_timespec.tv_sec + dt_timespec.tv_nsec * 1e-9;
-  if (dt > 0.1) {
-    dt = 0.1;
+  grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+  if (!tfc->pid_controller_initialized) {
+    tfc->last_pid_update = now;
+    tfc->pid_controller_initialized = true;
+    grpc_pid_controller_args args;
+    memset(&args, 0, sizeof(args));
+    args.gain_p = 4;
+    args.gain_i = 8;
+    args.gain_d = 0;
+    args.initial_control_value = target;
+    args.min_control_value = -1;
+    args.max_control_value = 25;
+    args.integral_range = 10;
+    grpc_pid_controller_init(&tfc->pid_controller, args);
+    return pow(2, target);
   }
+  double bdp_error = target - grpc_pid_controller_last(&tfc->pid_controller);
+  double dt = (double)(now - tfc->last_pid_update) * 1e-3;
   double log2_bdp_guess =
       grpc_pid_controller_update(&tfc->pid_controller, bdp_error, dt);
   tfc->last_pid_update = now;
@@ -414,20 +425,25 @@
   // do not increase window under heavy memory pressure.
   double memory_pressure = grpc_resource_quota_get_memory_pressure(
       grpc_resource_user_quota(grpc_endpoint_get_resource_user(tfc->t->ep)));
-  if (memory_pressure > 0.8) {
-    target *= 1 - GPR_MIN(1, (memory_pressure - 0.8) / 0.1);
+  static const double kLowMemPressure = 0.1;
+  static const double kZeroTarget = 22;
+  static const double kHighMemPressure = 0.8;
+  static const double kMaxMemPressure = 0.9;
+  if (memory_pressure < kLowMemPressure && target < kZeroTarget) {
+    target = (target - kZeroTarget) * memory_pressure / kLowMemPressure +
+             kZeroTarget;
+  } else if (memory_pressure > kHighMemPressure) {
+    target *= 1 - GPR_MIN(1, (memory_pressure - kHighMemPressure) /
+                                 (kMaxMemPressure - kHighMemPressure));
   }
   return target;
 }
 
 grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action(
-    grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) {
+    grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc,
+    grpc_chttp2_stream_flowctl* sfc) {
   grpc_chttp2_flowctl_action action;
   memset(&action, 0, sizeof(action));
-  uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc);
-  if (tfc->announced_window < target_announced_window / 2) {
-    action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY;
-  }
   // TODO(ncteisen): tune this
   if (sfc != NULL && !sfc->s->read_closed) {
     uint32_t sent_init_window =
@@ -442,20 +458,12 @@
       action.send_stream_update = GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE;
     }
   }
-  TRACEACTION(tfc, action);
-  return action;
-}
-
-grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_bdp_action(
-    grpc_chttp2_transport_flowctl* tfc) {
-  grpc_chttp2_flowctl_action action;
-  memset(&action, 0, sizeof(action));
   if (tfc->enable_bdp_probe) {
-    action.need_ping = grpc_bdp_estimator_need_ping(&tfc->bdp_estimator);
+    action.need_ping =
+        grpc_bdp_estimator_need_ping(exec_ctx, &tfc->bdp_estimator);
 
     // get bdp estimate and update initial_window accordingly.
     int64_t estimate = -1;
-    int32_t bdp = -1;
     if (grpc_bdp_estimator_get_estimate(&tfc->bdp_estimator, &estimate)) {
       double target = 1 + log2((double)estimate);
 
@@ -466,17 +474,18 @@
 
       // run our target through the pid controller to stabilize change.
       // TODO(ncteisen): experiment with other controllers here.
-      double bdp_guess = get_pid_controller_guess(tfc, target);
+      double bdp_guess = get_pid_controller_guess(exec_ctx, tfc, target);
 
       // Though initial window 'could' drop to 0, we keep the floor at 128
-      bdp = GPR_MAX((int32_t)bdp_guess, 128);
+      tfc->target_initial_window_size =
+          (int32_t)GPR_CLAMP(bdp_guess, 128, INT32_MAX);
 
       grpc_chttp2_flowctl_urgency init_window_update_urgency =
-          delta_is_significant(tfc, bdp,
+          delta_is_significant(tfc, tfc->target_initial_window_size,
                                GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
       if (init_window_update_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) {
         action.send_setting_update = init_window_update_urgency;
-        action.initial_window_size = (uint32_t)bdp;
+        action.initial_window_size = (uint32_t)tfc->target_initial_window_size;
       }
     }
 
@@ -485,8 +494,9 @@
     if (grpc_bdp_estimator_get_bw(&tfc->bdp_estimator, &bw_dbl)) {
       // we target the max of BDP or bandwidth in microseconds.
       int32_t frame_size = (int32_t)GPR_CLAMP(
-          GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000, bdp), 16384,
-          16777215);
+          GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
+                  tfc->target_initial_window_size),
+          16384, 16777215);
       grpc_chttp2_flowctl_urgency frame_size_urgency = delta_is_significant(
           tfc, frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE);
       if (frame_size_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) {
@@ -497,7 +507,10 @@
       }
     }
   }
-
+  uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc);
+  if (tfc->announced_window < target_announced_window / 2) {
+    action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY;
+  }
   TRACEACTION(tfc, action);
   return action;
 }
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.cc b/src/core/ext/transport/chttp2/transport/frame_ping.cc
index d431d6b..1cfa883 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -89,10 +89,10 @@
       grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
     } else {
       if (!t->is_client) {
-        gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-        gpr_timespec next_allowed_ping =
-            gpr_time_add(t->ping_recv_state.last_ping_recv_time,
-                         t->ping_policy.min_recv_ping_interval_without_data);
+        grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+        grpc_millis next_allowed_ping =
+            t->ping_recv_state.last_ping_recv_time +
+            t->ping_policy.min_recv_ping_interval_without_data;
 
         if (t->keepalive_permit_without_calls == 0 &&
             grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
@@ -100,11 +100,10 @@
              no less than two hours. When there is no outstanding streams, we
              restrict the number of PINGS equivalent to TCP Keep-Alive. */
           next_allowed_ping =
-              gpr_time_add(t->ping_recv_state.last_ping_recv_time,
-                           gpr_time_from_seconds(7200, GPR_TIMESPAN));
+              t->ping_recv_state.last_ping_recv_time + 7200 * GPR_MS_PER_SEC;
         }
 
-        if (gpr_time_cmp(next_allowed_ping, now) > 0) {
+        if (next_allowed_ping > now) {
           grpc_chttp2_add_ping_strike(exec_ctx, t);
         }
 
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 5f1a270..17b8c4a 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -535,12 +535,12 @@
 #define TIMEOUT_KEY "grpc-timeout"
 
 static void deadline_enc(grpc_exec_ctx *exec_ctx,
-                         grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
+                         grpc_chttp2_hpack_compressor *c, grpc_millis deadline,
                          framer_state *st) {
   char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_mdelem mdelem;
-  grpc_http2_encode_timeout(
-      gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
+  grpc_http2_encode_timeout(deadline - grpc_exec_ctx_now(exec_ctx),
+                            timeout_str);
   mdelem = grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT,
                                    grpc_slice_from_copied_string(timeout_str));
   hpack_enc(exec_ctx, c, mdelem, st);
@@ -660,8 +660,8 @@
   for (grpc_linked_mdelem *l = metadata->list.head; l; l = l->next) {
     hpack_enc(exec_ctx, c, l->md, &st);
   }
-  gpr_timespec deadline = metadata->deadline;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) {
+  grpc_millis deadline = metadata->deadline;
+  if (deadline != GRPC_MILLIS_INF_FUTURE) {
     deadline_enc(exec_ctx, c, deadline, &st);
   }
 
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
index ba680a8..187ce0e 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
@@ -29,7 +29,7 @@
     grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena) {
   buffer->arena = arena;
   grpc_metadata_batch_init(&buffer->batch);
-  buffer->batch.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  buffer->batch.deadline = GRPC_MILLIS_INF_FUTURE;
 }
 
 void grpc_chttp2_incoming_metadata_buffer_destroy(
@@ -62,7 +62,7 @@
 }
 
 void grpc_chttp2_incoming_metadata_buffer_set_deadline(
-    grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) {
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_millis deadline) {
   buffer->batch.deadline = deadline;
 }
 
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index 9ffcabd..995e800 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -47,7 +47,7 @@
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
     grpc_mdelem elem) GRPC_MUST_USE_RESULT;
 void grpc_chttp2_incoming_metadata_buffer_set_deadline(
-    grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline);
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_millis deadline);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 96af18f..b51854f 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -66,12 +66,6 @@
 } grpc_chttp2_write_state;
 
 typedef enum {
-  GRPC_CHTTP2_PING_ON_NEXT_WRITE = 0,
-  GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE,
-  GRPC_CHTTP2_PING_TYPE_COUNT /* must be last */
-} grpc_chttp2_ping_type;
-
-typedef enum {
   GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY,
   GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT,
 } grpc_chttp2_optimization_target;
@@ -97,7 +91,6 @@
   GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL,
   GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL,
   GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS,
-  GRPC_CHTTP2_INITIATE_WRITE_BDP_ESTIMATOR_PING,
   GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING,
   GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_UPDATE,
   GRPC_CHTTP2_INITIATE_WRITE_APPLICATION_PING,
@@ -118,19 +111,19 @@
 typedef struct {
   int max_pings_without_data;
   int max_ping_strikes;
-  gpr_timespec min_sent_ping_interval_without_data;
-  gpr_timespec min_recv_ping_interval_without_data;
+  grpc_millis min_sent_ping_interval_without_data;
+  grpc_millis min_recv_ping_interval_without_data;
 } grpc_chttp2_repeated_ping_policy;
 
 typedef struct {
-  gpr_timespec last_ping_sent_time;
+  grpc_millis last_ping_sent_time;
   int pings_before_data_required;
   grpc_timer delayed_ping_timer;
   bool is_delayed_ping_timer_set;
 } grpc_chttp2_repeated_ping_state;
 
 typedef struct {
-  gpr_timespec last_ping_recv_time;
+  grpc_millis last_ping_recv_time;
   int ping_strikes;
 } grpc_chttp2_server_ping_recv_state;
 
@@ -269,6 +262,8 @@
    * to send WINDOW_UPDATE frames. */
   int64_t announced_window;
 
+  int32_t target_initial_window_size;
+
   /** should we probe bdp? */
   bool enable_bdp_probe;
 
@@ -276,8 +271,9 @@
   grpc_bdp_estimator bdp_estimator;
 
   /* pid controller */
+  bool pid_controller_initialized;
   grpc_pid_controller pid_controller;
-  gpr_timespec last_pid_update;
+  grpc_millis last_pid_update;
 
   // pointer back to transport for tracing
   const grpc_chttp2_transport *t;
@@ -374,7 +370,7 @@
   uint32_t last_new_stream_id;
 
   /** ping queues for various ping insertion points */
-  grpc_chttp2_ping_queue ping_queues[GRPC_CHTTP2_PING_TYPE_COUNT];
+  grpc_chttp2_ping_queue ping_queue;
   grpc_chttp2_repeated_ping_policy ping_policy;
   grpc_chttp2_repeated_ping_state ping_state;
   uint64_t ping_ctr; /* unique id for pings */
@@ -459,9 +455,9 @@
   /** watchdog to kill the transport when waiting for the keepalive ping */
   grpc_timer keepalive_watchdog_timer;
   /** time duration in between pings */
-  gpr_timespec keepalive_time;
+  grpc_millis keepalive_time;
   /** grace period for a ping to complete before watchdog kicks in */
-  gpr_timespec keepalive_timeout;
+  grpc_millis keepalive_timeout;
   /** if keepalive pings are allowed when there's no outstanding streams */
   bool keepalive_permit_without_calls;
   /** keep-alive state machine state */
@@ -570,7 +566,7 @@
   grpc_error *byte_stream_error; /* protected by t combiner */
   bool received_last_frame;      /* protected by t combiner */
 
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   /** saw some stream level error */
   grpc_error *forced_close_error;
@@ -711,7 +707,7 @@
 // returns an announce if we should send a transport update to our peer,
 // else returns zero
 uint32_t grpc_chttp2_flowctl_maybe_send_transport_update(
-    grpc_chttp2_transport_flowctl *tfc);
+    grpc_chttp2_transport_flowctl *tfc, bool writing_anyway);
 
 // returns an announce if we should send a stream update to our peer, else
 // returns zero
@@ -758,10 +754,8 @@
 // Reads the flow control data and returns and actionable struct that will tell
 // chttp2 exactly what it needs to do
 grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action(
-    grpc_chttp2_transport_flowctl *tfc, grpc_chttp2_stream_flowctl *sfc);
-
-grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_bdp_action(
-    grpc_chttp2_transport_flowctl *tfc);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_flowctl *tfc,
+    grpc_chttp2_stream_flowctl *sfc);
 
 // Takes in a flow control action and performs all the needed operations.
 void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 3db1ad4..78886b4 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -359,8 +359,9 @@
                                       s == NULL ? NULL : &s->flow_control,
                                       t->incoming_frame_size);
   grpc_chttp2_act_on_flowctl_action(
-      exec_ctx, grpc_chttp2_flowctl_get_action(
-                    &t->flow_control, s == NULL ? NULL : &s->flow_control),
+      exec_ctx,
+      grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
+                                     s == NULL ? NULL : &s->flow_control),
       t, s);
   if (err != GRPC_ERROR_NONE) {
     goto error_handler;
@@ -385,7 +386,7 @@
     t->parser_data = &s->data_parser;
     t->ping_state.pings_before_data_required =
         t->ping_policy.max_pings_without_data;
-    t->ping_state.last_ping_sent_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+    t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
     return GRPC_ERROR_NONE;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
     /* handle stream errors by closing the stream */
@@ -430,26 +431,27 @@
   }
 
   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
-    gpr_timespec *cached_timeout =
-        (gpr_timespec *)grpc_mdelem_get_user_data(md, free_timeout);
-    gpr_timespec timeout;
+    grpc_millis *cached_timeout =
+        static_cast<grpc_millis *>(grpc_mdelem_get_user_data(md, free_timeout));
+    grpc_millis timeout;
     if (cached_timeout == NULL) {
       /* not already parsed: parse it now, and store the result away */
-      cached_timeout = (gpr_timespec *)gpr_malloc(sizeof(gpr_timespec));
+      cached_timeout = (grpc_millis *)gpr_malloc(sizeof(grpc_millis));
       if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) {
         char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
         gpr_free(val);
-        *cached_timeout = gpr_inf_future(GPR_TIMESPAN);
+        *cached_timeout = GRPC_MILLIS_INF_FUTURE;
       }
       timeout = *cached_timeout;
       grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
     } else {
       timeout = *cached_timeout;
     }
-    grpc_chttp2_incoming_metadata_buffer_set_deadline(
-        &s->metadata_buffer[0],
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout));
+    if (timeout != GRPC_MILLIS_INF_FUTURE) {
+      grpc_chttp2_incoming_metadata_buffer_set_deadline(
+          &s->metadata_buffer[0], grpc_exec_ctx_now(exec_ctx) + timeout);
+    }
     GRPC_MDELEM_UNREF(exec_ctx, md);
   } else {
     const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
@@ -564,7 +566,7 @@
 
   t->ping_state.pings_before_data_required =
       t->ping_policy.max_pings_without_data;
-  t->ping_state.last_ping_sent_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+  t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
 
   /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
   s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index ba3d55a..4134890 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -42,18 +42,9 @@
   t->write_cb_pool = cb;
 }
 
-static void collapse_pings_from_into(grpc_chttp2_transport *t,
-                                     grpc_chttp2_ping_type ping_type,
-                                     grpc_chttp2_ping_queue *pq) {
-  for (size_t i = 0; i < GRPC_CHTTP2_PCL_COUNT; i++) {
-    grpc_closure_list_move(&t->ping_queues[ping_type].lists[i], &pq->lists[i]);
-  }
-}
-
 static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_transport *t,
-                                grpc_chttp2_ping_type ping_type) {
-  grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type];
+                                grpc_chttp2_transport *t) {
+  grpc_chttp2_ping_queue *pq = &t->ping_queue;
   if (grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) {
     /* no ping needed: wait */
     return;
@@ -62,7 +53,8 @@
     /* ping already in-flight: wait */
     if (GRPC_TRACER_ON(grpc_http_trace) ||
         GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-      gpr_log(GPR_DEBUG, "Ping delayed [%p]: already pinging", t->peer_string);
+      gpr_log(GPR_DEBUG, "%s: Ping delayed [%p]: already pinging",
+              t->is_client ? "CLIENT" : "SERVER", t->peer_string);
     }
     return;
   }
@@ -71,51 +63,38 @@
     /* need to receive something of substance before sending a ping again */
     if (GRPC_TRACER_ON(grpc_http_trace) ||
         GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-      gpr_log(GPR_DEBUG, "Ping delayed [%p]: too many recent pings: %d/%d",
-              t->peer_string, t->ping_state.pings_before_data_required,
+      gpr_log(GPR_DEBUG, "%s: Ping delayed [%p]: too many recent pings: %d/%d",
+              t->is_client ? "CLIENT" : "SERVER", t->peer_string,
+              t->ping_state.pings_before_data_required,
               t->ping_policy.max_pings_without_data);
     }
     return;
   }
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  gpr_timespec next_allowed_ping =
-      gpr_time_add(t->ping_state.last_ping_sent_time,
-                   t->ping_policy.min_sent_ping_interval_without_data);
+  grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+  grpc_millis next_allowed_ping =
+      t->ping_state.last_ping_sent_time +
+      t->ping_policy.min_sent_ping_interval_without_data;
   if (t->keepalive_permit_without_calls == 0 &&
       grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
-    next_allowed_ping = gpr_time_add(t->ping_recv_state.last_ping_recv_time,
-                                     gpr_time_from_seconds(7200, GPR_TIMESPAN));
+    next_allowed_ping =
+        t->ping_recv_state.last_ping_recv_time + 7200 * GPR_MS_PER_SEC;
   }
-  /* gpr_log(GPR_DEBUG, "next_allowed_ping:%d.%09d now:%d.%09d",
-          (int)next_allowed_ping.tv_sec, (int)next_allowed_ping.tv_nsec,
-          (int)now.tv_sec, (int)now.tv_nsec); */
-  if (gpr_time_cmp(next_allowed_ping, now) > 0) {
+  if (next_allowed_ping > now) {
     /* not enough elapsed time between successive pings */
     if (GRPC_TRACER_ON(grpc_http_trace) ||
         GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
       gpr_log(GPR_DEBUG,
-              "Ping delayed [%p]: not enough time elapsed since last ping",
-              t->peer_string);
+              "%s: Ping delayed [%p]: not enough time elapsed since last ping",
+              t->is_client ? "CLIENT" : "SERVER", t->peer_string);
     }
     if (!t->ping_state.is_delayed_ping_timer_set) {
       t->ping_state.is_delayed_ping_timer_set = true;
       grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer,
-                      next_allowed_ping, &t->retry_initiate_ping_locked,
-                      gpr_now(GPR_CLOCK_MONOTONIC));
+                      next_allowed_ping, &t->retry_initiate_ping_locked);
     }
     return;
   }
-  /* coalesce equivalent pings into this one */
-  switch (ping_type) {
-    case GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE:
-      collapse_pings_from_into(t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, pq);
-      break;
-    case GRPC_CHTTP2_PING_ON_NEXT_WRITE:
-      break;
-    case GRPC_CHTTP2_PING_TYPE_COUNT:
-      GPR_UNREACHABLE_CODE(break);
-  }
-  pq->inflight_id = t->ping_ctr * GRPC_CHTTP2_PING_TYPE_COUNT + ping_type;
+  pq->inflight_id = t->ping_ctr;
   t->ping_ctr++;
   GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INITIATE]);
   grpc_closure_list_move(&pq->lists[GRPC_CHTTP2_PCL_NEXT],
@@ -126,7 +105,8 @@
   t->ping_state.last_ping_sent_time = now;
   if (GRPC_TRACER_ON(grpc_http_trace) ||
       GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-    gpr_log(GPR_DEBUG, "Ping sent [%p]: %d/%d", t->peer_string,
+    gpr_log(GPR_DEBUG, "%s: Ping sent [%p]: %d/%d",
+            t->is_client ? "CLIENT" : "SERVER", t->peer_string,
             t->ping_state.pings_before_data_required,
             t->ping_policy.max_pings_without_data);
   }
@@ -156,6 +136,25 @@
   return sched_any;
 }
 
+static void report_stall(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                         const char *staller) {
+  gpr_log(
+      GPR_DEBUG,
+      "%s:%p stream %d stalled by %s [fc:pending=%" PRIdPTR ":flowed=%" PRId64
+      ":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]",
+      t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length,
+      s->flow_controlled_bytes_flowed,
+      t->settings[GRPC_ACKED_SETTINGS]
+                 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+      t->flow_control.remote_window,
+      (uint32_t)GPR_MAX(
+          0,
+          s->flow_control.remote_window_delta +
+              (int64_t)t->settings[GRPC_PEER_SETTINGS]
+                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]),
+      s->flow_control.remote_window_delta);
+}
+
 static bool stream_ref_if_not_destroyed(gpr_refcount *r) {
   gpr_atm count;
   do {
@@ -202,6 +201,12 @@
     GRPC_STATS_INC_HTTP2_SETTINGS_WRITES(exec_ctx);
   }
 
+  for (size_t i = 0; i < t->ping_ack_count; i++) {
+    grpc_slice_buffer_add(&t->outbuf,
+                          grpc_chttp2_ping_create(1, t->ping_acks[i]));
+  }
+  t->ping_ack_count = 0;
+
   /* simple writes are queued to qbuf, and flushed here */
   grpc_slice_buffer_move_into(&t->qbuf, &t->outbuf);
   GPR_ASSERT(t->qbuf.count == 0);
@@ -270,8 +275,7 @@
                                   s->send_initial_metadata, &hopt, &t->outbuf);
         now_writing = true;
         if (!t->is_client) {
-          t->ping_recv_state.last_ping_recv_time =
-              gpr_inf_past(GPR_CLOCK_MONOTONIC);
+          t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
           t->ping_recv_state.ping_strikes = 0;
         }
         initial_metadata_writes++;
@@ -300,6 +304,7 @@
           exec_ctx, t, s, &s->send_initial_metadata_finished, GRPC_ERROR_NONE,
           "send_initial_metadata_finished");
     }
+
     /* send any window updates */
     uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update(
         &t->flow_control, &s->flow_control);
@@ -308,8 +313,7 @@
           &t->outbuf, grpc_chttp2_window_update_create(s->id, stream_announce,
                                                        &s->stats.outgoing));
       if (!t->is_client) {
-        t->ping_recv_state.last_ping_recv_time =
-            gpr_inf_past(GPR_CLOCK_MONOTONIC);
+        t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
         t->ping_recv_state.ping_strikes = 0;
       }
       flow_control_writes++;
@@ -386,8 +390,7 @@
             }
           }
           if (!t->is_client) {
-            t->ping_recv_state.last_ping_recv_time =
-                gpr_inf_past(GPR_CLOCK_MONOTONIC);
+            t->ping_recv_state.last_ping_recv_time = 0;
             t->ping_recv_state.ping_strikes = 0;
           }
           if (is_last_frame) {
@@ -414,9 +417,11 @@
           }
           message_writes++;
         } else if (t->flow_control.remote_window == 0) {
+          report_stall(t, s, "transport");
           grpc_chttp2_list_add_stalled_by_transport(t, s);
           now_writing = true;
         } else if (stream_remote_window == 0) {
+          report_stall(t, s, "stream");
           grpc_chttp2_list_add_stalled_by_stream(t, s);
           now_writing = true;
         }
@@ -450,6 +455,10 @@
         }
         s->send_trailing_metadata = NULL;
         s->sent_trailing_metadata = true;
+        if (!t->is_client) {
+          t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
+          t->ping_recv_state.ping_strikes = 0;
+        }
         if (!t->is_client && !s->read_closed) {
           grpc_slice_buffer_add(
               &t->outbuf, grpc_chttp2_rst_stream_create(
@@ -483,30 +492,21 @@
     }
   }
 
-  uint32_t transport_announce =
-      grpc_chttp2_flowctl_maybe_send_transport_update(&t->flow_control);
+  maybe_initiate_ping(exec_ctx, t);
+
+  uint32_t transport_announce = grpc_chttp2_flowctl_maybe_send_transport_update(
+      &t->flow_control, t->outbuf.count > 0);
   if (transport_announce) {
-    maybe_initiate_ping(exec_ctx, t,
-                        GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE);
     grpc_transport_one_way_stats throwaway_stats;
     grpc_slice_buffer_add(
         &t->outbuf, grpc_chttp2_window_update_create(0, transport_announce,
                                                      &throwaway_stats));
     if (!t->is_client) {
-      t->ping_recv_state.last_ping_recv_time =
-          gpr_inf_past(GPR_CLOCK_MONOTONIC);
+      t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
       t->ping_recv_state.ping_strikes = 0;
     }
   }
 
-  for (size_t i = 0; i < t->ping_ack_count; i++) {
-    grpc_slice_buffer_add(&t->outbuf,
-                          grpc_chttp2_ping_create(1, t->ping_acks[i]));
-  }
-  t->ping_ack_count = 0;
-
-  maybe_initiate_ping(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE);
-
   GPR_TIMER_END("grpc_chttp2_begin_write", 0);
 
   result.writing = t->outbuf.count > 0;
diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc
index 31739d0..1001d74 100644
--- a/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/src/core/ext/transport/inproc/inproc_transport.cc
@@ -150,7 +150,7 @@
   grpc_metadata_batch write_buffer_initial_md;
   bool write_buffer_initial_md_filled;
   uint32_t write_buffer_initial_md_flags;
-  gpr_timespec write_buffer_deadline;
+  grpc_millis write_buffer_deadline;
   slice_buffer_list write_buffer_message;
   grpc_metadata_batch write_buffer_trailing_md;
   bool write_buffer_trailing_md_filled;
@@ -180,7 +180,7 @@
   grpc_error *cancel_self_error;
   grpc_error *cancel_other_error;
 
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   bool listed;
   struct inproc_stream *stream_list_prev;
@@ -377,8 +377,8 @@
   s->cancel_self_error = GRPC_ERROR_NONE;
   s->cancel_other_error = GRPC_ERROR_NONE;
   s->write_buffer_cancel_error = GRPC_ERROR_NONE;
-  s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
-  s->write_buffer_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  s->deadline = GRPC_MILLIS_INF_FUTURE;
+  s->write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
 
   s->stream_list_prev = NULL;
   gpr_mu_lock(&t->mu->mu);
@@ -421,7 +421,7 @@
                        cs->write_buffer_initial_md_flags,
                        &s->to_read_initial_md, &s->to_read_initial_md_flags,
                        &s->to_read_initial_md_filled);
-      s->deadline = gpr_time_min(s->deadline, cs->write_buffer_deadline);
+      s->deadline = GPR_MIN(s->deadline, cs->write_buffer_deadline);
       grpc_metadata_batch_clear(exec_ctx, &cs->write_buffer_initial_md);
       cs->write_buffer_initial_md_filled = false;
     }
@@ -956,10 +956,10 @@
               dest, destflags, destfilled);
         }
         if (s->t->is_client) {
-          gpr_timespec *dl =
+          grpc_millis *dl =
               (other == NULL) ? &s->write_buffer_deadline : &other->deadline;
-          *dl = gpr_time_min(*dl, op->payload->send_initial_metadata
-                                      .send_initial_metadata->deadline);
+          *dl = GPR_MIN(*dl, op->payload->send_initial_metadata
+                                 .send_initial_metadata->deadline);
           s->initial_md_sent = true;
         }
       }
diff --git a/src/core/lib/support/backoff.cc b/src/core/lib/backoff/backoff.cc
similarity index 63%
rename from src/core/lib/support/backoff.cc
rename to src/core/lib/backoff/backoff.cc
index 6dc0df4..fe0a751 100644
--- a/src/core/lib/support/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -16,13 +16,14 @@
  *
  */
 
-#include "src/core/lib/support/backoff.h"
+#include "src/core/lib/backoff/backoff.h"
 
 #include <grpc/support/useful.h>
 
-void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
-                      double multiplier, double jitter,
-                      int64_t min_timeout_millis, int64_t max_timeout_millis) {
+void grpc_backoff_init(grpc_backoff *backoff,
+                       grpc_millis initial_connect_timeout, double multiplier,
+                       double jitter, grpc_millis min_timeout_millis,
+                       grpc_millis max_timeout_millis) {
   backoff->initial_connect_timeout = initial_connect_timeout;
   backoff->multiplier = multiplier;
   backoff->jitter = jitter;
@@ -31,11 +32,11 @@
   backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
 }
 
-gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) {
+grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
   backoff->current_timeout_millis = backoff->initial_connect_timeout;
-  const int64_t first_timeout =
+  const grpc_millis first_timeout =
       GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
-  return gpr_time_add(now, gpr_time_from_millis(first_timeout, GPR_TIMESPAN));
+  return grpc_exec_ctx_now(exec_ctx) + first_timeout;
 }
 
 /* Generate a random number between 0 and 1. */
@@ -44,11 +45,11 @@
   return *rng_state / (double)((uint32_t)1 << 31);
 }
 
-gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) {
+grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
   const double new_timeout_millis =
       backoff->multiplier * (double)backoff->current_timeout_millis;
   backoff->current_timeout_millis =
-      GPR_MIN((int64_t)new_timeout_millis, backoff->max_timeout_millis);
+      GPR_MIN((grpc_millis)new_timeout_millis, backoff->max_timeout_millis);
 
   const double jitter_range_width = backoff->jitter * new_timeout_millis;
   const double jitter =
@@ -56,17 +57,17 @@
       jitter_range_width;
 
   backoff->current_timeout_millis =
-      (int64_t)((double)(backoff->current_timeout_millis) + jitter);
+      (grpc_millis)((double)(backoff->current_timeout_millis) + jitter);
 
-  const gpr_timespec current_deadline = gpr_time_add(
-      now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
+  const grpc_millis current_deadline =
+      grpc_exec_ctx_now(exec_ctx) + backoff->current_timeout_millis;
 
-  const gpr_timespec min_deadline = gpr_time_add(
-      now, gpr_time_from_millis(backoff->min_timeout_millis, GPR_TIMESPAN));
+  const grpc_millis min_deadline =
+      grpc_exec_ctx_now(exec_ctx) + backoff->min_timeout_millis;
 
-  return gpr_time_max(current_deadline, min_deadline);
+  return GPR_MAX(current_deadline, min_deadline);
 }
 
-void gpr_backoff_reset(gpr_backoff *backoff) {
+void grpc_backoff_reset(grpc_backoff *backoff) {
   backoff->current_timeout_millis = backoff->initial_connect_timeout;
 }
diff --git a/src/core/lib/support/backoff.h b/src/core/lib/backoff/backoff.h
similarity index 60%
rename from src/core/lib/support/backoff.h
rename to src/core/lib/backoff/backoff.h
index 31ec28f..80e49ea 100644
--- a/src/core/lib/support/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -16,10 +16,10 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_SUPPORT_BACKOFF_H
-#define GRPC_CORE_LIB_SUPPORT_BACKOFF_H
+#ifndef GRPC_CORE_LIB_BACKOFF_BACKOFF_H
+#define GRPC_CORE_LIB_BACKOFF_BACKOFF_H
 
-#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -27,38 +27,40 @@
 
 typedef struct {
   /// const:  how long to wait after the first failure before retrying
-  int64_t initial_connect_timeout;
+  grpc_millis initial_connect_timeout;
   /// const: factor with which to multiply backoff after a failed retry
   double multiplier;
   /// const: amount to randomize backoffs
   double jitter;
   /// const: minimum time between retries in milliseconds
-  int64_t min_timeout_millis;
+  grpc_millis min_timeout_millis;
   /// const: maximum time between retries in milliseconds
-  int64_t max_timeout_millis;
+  grpc_millis max_timeout_millis;
 
   /// random number generator
   uint32_t rng_state;
 
   /// current retry timeout in milliseconds
-  int64_t current_timeout_millis;
-} gpr_backoff;
+  grpc_millis current_timeout_millis;
+} grpc_backoff;
 
 /// Initialize backoff machinery - does not need to be destroyed
-void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
-                      double multiplier, double jitter,
-                      int64_t min_timeout_millis, int64_t max_timeout_millis);
+void grpc_backoff_init(grpc_backoff *backoff,
+                       grpc_millis initial_connect_timeout, double multiplier,
+                       double jitter, grpc_millis min_timeout_millis,
+                       grpc_millis max_timeout_millis);
 
 /// Begin retry loop: returns a timespec for the NEXT retry
-gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now);
+grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
 /// Step a retry loop: returns a timespec for the NEXT retry
-gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now);
-/// Reset the backoff, so the next gpr_backoff_step will be a gpr_backoff_begin
+grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
+/// Reset the backoff, so the next grpc_backoff_step will be a
+/// grpc_backoff_begin
 /// instead
-void gpr_backoff_reset(gpr_backoff *backoff);
+void grpc_backoff_reset(grpc_backoff *backoff);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* GRPC_CORE_LIB_SUPPORT_BACKOFF_H */
+#endif /* GRPC_CORE_LIB_BACKOFF_BACKOFF_H */
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index f0de80f..5c00c09 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -70,7 +70,7 @@
   grpc_call_context_element *context;
   grpc_slice path;
   gpr_timespec start_time;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   gpr_arena *arena;
   grpc_call_combiner *call_combiner;
 } grpc_call_element_args;
diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc
index 1753da5..b27ee37 100644
--- a/src/core/lib/channel/handshaker.cc
+++ b/src/core/lib/channel/handshaker.cc
@@ -232,7 +232,7 @@
 void grpc_handshake_manager_do_handshake(
     grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
     grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
-    gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
+    grpc_millis deadline, grpc_tcp_server_acceptor* acceptor,
     grpc_iomgr_cb_func on_handshake_done, void* user_data) {
   gpr_mu_lock(&mgr->mu);
   GPR_ASSERT(mgr->index == 0);
@@ -255,9 +255,7 @@
   gpr_ref(&mgr->refs);
   GRPC_CLOSURE_INIT(&mgr->on_timeout, on_timeout, mgr,
                     grpc_schedule_on_exec_ctx);
-  grpc_timer_init(exec_ctx, &mgr->deadline_timer,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &mgr->deadline_timer, deadline, &mgr->on_timeout);
   // Start first handshaker, which also owns a ref.
   gpr_ref(&mgr->refs);
   bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index a857cde..51ee56a 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -149,7 +149,7 @@
 void grpc_handshake_manager_do_handshake(
     grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
     grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
-    gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
+    grpc_millis deadline, grpc_tcp_server_acceptor* acceptor,
     grpc_iomgr_cb_func on_handshake_done, void* user_data);
 
 /// Add \a mgr to the server side list of all pending handshake managers, the
diff --git a/src/core/lib/debug/stats_data.cc b/src/core/lib/debug/stats_data.cc
index c0aec63..5bd7884 100644
--- a/src/core/lib/debug/stats_data.cc
+++ b/src/core/lib/debug/stats_data.cc
@@ -77,6 +77,7 @@
     "http2_initiate_write_due_to_transport_flow_control_unstalled",
     "http2_initiate_write_due_to_ping_response",
     "http2_initiate_write_due_to_force_rst_stream",
+    "http2_spurious_writes_begun",
     "hpack_recv_indexed",
     "hpack_recv_lithdr_incidx",
     "hpack_recv_lithdr_incidx_v",
@@ -177,6 +178,7 @@
     "'transport_flow_control_unstalled'",
     "Number of HTTP2 writes initiated due to 'ping_response'",
     "Number of HTTP2 writes initiated due to 'force_rst_stream'",
+    "Number of HTTP2 writes initiated with nothing to write",
     "Number of HPACK indexed fields received",
     "Number of HPACK literal headers received with incremental indexing",
     "Number of HPACK literal headers received with incremental indexing and "
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
index cf5bafb..d8e4e7d 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -83,6 +83,7 @@
   GRPC_STATS_COUNTER_HTTP2_INITIATE_WRITE_DUE_TO_TRANSPORT_FLOW_CONTROL_UNSTALLED,
   GRPC_STATS_COUNTER_HTTP2_INITIATE_WRITE_DUE_TO_PING_RESPONSE,
   GRPC_STATS_COUNTER_HTTP2_INITIATE_WRITE_DUE_TO_FORCE_RST_STREAM,
+  GRPC_STATS_COUNTER_HTTP2_SPURIOUS_WRITES_BEGUN,
   GRPC_STATS_COUNTER_HPACK_RECV_INDEXED,
   GRPC_STATS_COUNTER_HPACK_RECV_LITHDR_INCIDX,
   GRPC_STATS_COUNTER_HPACK_RECV_LITHDR_INCIDX_V,
@@ -330,6 +331,9 @@
   GRPC_STATS_INC_COUNTER(                                                     \
       (exec_ctx),                                                             \
       GRPC_STATS_COUNTER_HTTP2_INITIATE_WRITE_DUE_TO_FORCE_RST_STREAM)
+#define GRPC_STATS_INC_HTTP2_SPURIOUS_WRITES_BEGUN(exec_ctx) \
+  GRPC_STATS_INC_COUNTER((exec_ctx),                         \
+                         GRPC_STATS_COUNTER_HTTP2_SPURIOUS_WRITES_BEGUN)
 #define GRPC_STATS_INC_HPACK_RECV_INDEXED(exec_ctx) \
   GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HPACK_RECV_INDEXED)
 #define GRPC_STATS_INC_HPACK_RECV_LITHDR_INCIDX(exec_ctx) \
diff --git a/src/core/lib/debug/stats_data.yaml b/src/core/lib/debug/stats_data.yaml
index b5c15ff..5c0ab22 100644
--- a/src/core/lib/debug/stats_data.yaml
+++ b/src/core/lib/debug/stats_data.yaml
@@ -189,6 +189,8 @@
   doc: Number of HTTP2 writes initiated due to 'ping_response'
 - counter: http2_initiate_write_due_to_force_rst_stream
   doc: Number of HTTP2 writes initiated due to 'force_rst_stream'
+- counter: http2_spurious_writes_begun
+  doc: Number of HTTP2 writes initiated with nothing to write
 - counter: hpack_recv_indexed
   doc: Number of HPACK indexed fields received
 - counter: hpack_recv_lithdr_incidx
@@ -270,3 +272,4 @@
 - counter: server_slowpath_requests_queued
   doc: How many times was the server slow path taken (indicates too few
        outstanding requests)
+
diff --git a/src/core/lib/debug/stats_data_bq_schema.sql b/src/core/lib/debug/stats_data_bq_schema.sql
index f96e40c..5486997 100644
--- a/src/core/lib/debug/stats_data_bq_schema.sql
+++ b/src/core/lib/debug/stats_data_bq_schema.sql
@@ -52,6 +52,7 @@
 http2_initiate_write_due_to_transport_flow_control_unstalled_per_iteration:FLOAT,
 http2_initiate_write_due_to_ping_response_per_iteration:FLOAT,
 http2_initiate_write_due_to_force_rst_stream_per_iteration:FLOAT,
+http2_spurious_writes_begun_per_iteration:FLOAT,
 hpack_recv_indexed_per_iteration:FLOAT,
 hpack_recv_lithdr_incidx_per_iteration:FLOAT,
 hpack_recv_lithdr_incidx_v_per_iteration:FLOAT,
diff --git a/src/core/lib/http/httpcli.cc b/src/core/lib/http/httpcli.cc
index db99594..c96800b 100644
--- a/src/core/lib/http/httpcli.cc
+++ b/src/core/lib/http/httpcli.cc
@@ -44,7 +44,7 @@
   grpc_endpoint *ep;
   char *host;
   char *ssl_host_override;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   int have_read_byte;
   const grpc_httpcli_handshaker *handshaker;
   grpc_closure *on_done;
@@ -65,7 +65,7 @@
 
 static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
                                 grpc_endpoint *endpoint, const char *host,
-                                gpr_timespec deadline,
+                                grpc_millis deadline,
                                 void (*on_done)(grpc_exec_ctx *exec_ctx,
                                                 void *arg,
                                                 grpc_endpoint *endpoint)) {
@@ -240,7 +240,7 @@
                                    grpc_polling_entity *pollent,
                                    grpc_resource_quota *resource_quota,
                                    const grpc_httpcli_request *request,
-                                   gpr_timespec deadline, grpc_closure *on_done,
+                                   grpc_millis deadline, grpc_closure *on_done,
                                    grpc_httpcli_response *response,
                                    const char *name, grpc_slice request_text) {
   internal_request *req =
@@ -278,9 +278,8 @@
 void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
                       grpc_polling_entity *pollent,
                       grpc_resource_quota *resource_quota,
-                      const grpc_httpcli_request *request,
-                      gpr_timespec deadline, grpc_closure *on_done,
-                      grpc_httpcli_response *response) {
+                      const grpc_httpcli_request *request, grpc_millis deadline,
+                      grpc_closure *on_done, grpc_httpcli_response *response) {
   char *name;
   if (g_get_override &&
       g_get_override(exec_ctx, request, deadline, on_done, response)) {
@@ -298,7 +297,7 @@
                        grpc_resource_quota *resource_quota,
                        const grpc_httpcli_request *request,
                        const char *body_bytes, size_t body_size,
-                       gpr_timespec deadline, grpc_closure *on_done,
+                       grpc_millis deadline, grpc_closure *on_done,
                        grpc_httpcli_response *response) {
   char *name;
   if (g_post_override &&
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 630481d..3e6bdc0 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -46,7 +46,7 @@
 typedef struct {
   const char *default_port;
   void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
-                    const char *host, gpr_timespec deadline,
+                    const char *host, grpc_millis deadline,
                     void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
                                     grpc_endpoint *endpoint));
 } grpc_httpcli_handshaker;
@@ -87,8 +87,8 @@
 void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
                       grpc_polling_entity *pollent,
                       grpc_resource_quota *resource_quota,
-                      const grpc_httpcli_request *request,
-                      gpr_timespec deadline, grpc_closure *on_complete,
+                      const grpc_httpcli_request *request, grpc_millis deadline,
+                      grpc_closure *on_complete,
                       grpc_httpcli_response *response);
 
 /* Asynchronously perform a HTTP POST.
@@ -110,18 +110,18 @@
                        grpc_resource_quota *resource_quota,
                        const grpc_httpcli_request *request,
                        const char *body_bytes, size_t body_size,
-                       gpr_timespec deadline, grpc_closure *on_complete,
+                       grpc_millis deadline, grpc_closure *on_complete,
                        grpc_httpcli_response *response);
 
 /* override functions return 1 if they handled the request, 0 otherwise */
 typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
                                          const grpc_httpcli_request *request,
-                                         gpr_timespec deadline,
+                                         grpc_millis deadline,
                                          grpc_closure *on_complete,
                                          grpc_httpcli_response *response);
 typedef int (*grpc_httpcli_post_override)(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    const char *body_bytes, size_t body_size, gpr_timespec deadline,
+    const char *body_bytes, size_t body_size, grpc_millis deadline,
     grpc_closure *on_complete, grpc_httpcli_response *response);
 
 void grpc_httpcli_set_override(grpc_httpcli_get_override get,
diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc
index 8a0f225..ef6c4a5 100644
--- a/src/core/lib/http/httpcli_security_connector.cc
+++ b/src/core/lib/http/httpcli_security_connector.cc
@@ -157,7 +157,7 @@
 
 static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
                           grpc_endpoint *tcp, const char *host,
-                          gpr_timespec deadline,
+                          grpc_millis deadline,
                           void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
                                           grpc_endpoint *endpoint)) {
   on_done_closure *c = (on_done_closure *)gpr_malloc(sizeof(*c));
diff --git a/src/core/lib/iomgr/block_annotate.h b/src/core/lib/iomgr/block_annotate.h
new file mode 100644
index 0000000..fcbfe9e
--- /dev/null
+++ b/src/core/lib/iomgr/block_annotate.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
+#define GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpr_thd_start_blocking_region();
+void gpr_thd_end_blocking_region();
+
+#ifdef __cplusplus
+}
+#endif
+
+/* These annotations identify the beginning and end of regions where
+   the code may block for reasons other than synchronization functions.
+   These include poll, epoll, and getaddrinfo. */
+
+#ifdef GRPC_SCHEDULING_MARK_BLOCKING_REGION
+#define GRPC_SCHEDULING_START_BLOCKING_REGION \
+  do {                                        \
+    gpr_thd_start_blocking_region();          \
+  } while (0)
+#define GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX \
+  do {                                                  \
+    gpr_thd_end_blocking_region();                      \
+  } while (0)
+#define GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(ec) \
+  do {                                                        \
+    gpr_thd_end_blocking_region();                            \
+    grpc_exec_ctx_invalidate_now((ec));                       \
+  } while (0)
+#else
+#define GRPC_SCHEDULING_START_BLOCKING_REGION \
+  do {                                        \
+  } while (0)
+#define GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX \
+  do {                                                  \
+  } while (0)
+#define GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(ec) \
+  do {                                                        \
+    grpc_exec_ctx_invalidate_now((ec));                       \
+  } while (0)
+#endif
+
+#endif /* GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H */
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index 689aac1..6126e27 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <pthread.h>
 #include <string.h>
@@ -39,12 +40,12 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/lockfree_event.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/string.h"
 
 static grpc_wakeup_fd global_wakeup_fd;
@@ -561,25 +562,17 @@
   GPR_TIMER_END("pollset_shutdown", 0);
 }
 
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                           gpr_timespec now) {
-  gpr_timespec timeout;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
-    return -1;
-  }
-
-  if (gpr_time_cmp(deadline, now) <= 0) {
+static int poll_deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                           grpc_millis millis) {
+  if (millis == GRPC_MILLIS_INF_FUTURE) return -1;
+  grpc_millis delta = millis - grpc_exec_ctx_now(exec_ctx);
+  if (delta > INT_MAX) {
+    return INT_MAX;
+  } else if (delta < 0) {
     return 0;
+  } else {
+    return (int)delta;
   }
-
-  static const gpr_timespec round_up = {
-      0,                 /* tv_sec */
-      GPR_NS_PER_MS - 1, /* tv_nsec */
-      GPR_TIMESPAN       /* clock_type */
-  };
-  timeout = gpr_time_sub(deadline, now);
-  int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up));
-  return millis >= 1 ? millis : 1;
 }
 
 /* Process the epoll events found by do_epoll_wait() function.
@@ -636,11 +629,11 @@
    (i.e the designated poller thread) will be calling this function. So there is
    no need for any synchronization when accesing fields in g_epoll_set */
 static grpc_error *do_epoll_wait(grpc_exec_ctx *exec_ctx, grpc_pollset *ps,
-                                 gpr_timespec now, gpr_timespec deadline) {
+                                 grpc_millis deadline) {
   GPR_TIMER_BEGIN("do_epoll_wait", 0);
 
   int r;
-  int timeout = poll_deadline_to_millis_timeout(deadline, now);
+  int timeout = poll_deadline_to_millis_timeout(exec_ctx, deadline);
   if (timeout != 0) {
     GRPC_SCHEDULING_START_BLOCKING_REGION;
   }
@@ -650,7 +643,7 @@
                    timeout);
   } while (r < 0 && errno == EINTR);
   if (timeout != 0) {
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
+    GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
   }
 
   if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
@@ -668,9 +661,10 @@
   return GRPC_ERROR_NONE;
 }
 
-static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker,
-                         grpc_pollset_worker **worker_hdl, gpr_timespec *now,
-                         gpr_timespec deadline) {
+static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                         grpc_pollset_worker *worker,
+                         grpc_pollset_worker **worker_hdl,
+                         grpc_millis deadline) {
   GPR_TIMER_BEGIN("begin_worker", 0);
   if (worker_hdl != NULL) *worker_hdl = worker;
   worker->initialized_cv = false;
@@ -755,14 +749,15 @@
                 pollset->shutting_down);
       }
 
-      if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) &&
+      if (gpr_cv_wait(&worker->cv, &pollset->mu,
+                      grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME)) &&
           worker->state == UNKICKED) {
         /* If gpr_cv_wait returns true (i.e a timeout), pretend that the worker
            received a kick */
         SET_KICK_STATE(worker, KICKED);
       }
     }
-    *now = gpr_now(now->clock_type);
+    grpc_exec_ctx_invalidate_now(exec_ctx);
   }
 
   if (GRPC_TRACER_ON(grpc_polling_trace)) {
@@ -941,7 +936,7 @@
    ensure that it is held by the time the function returns */
 static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *ps,
                                 grpc_pollset_worker **worker_hdl,
-                                gpr_timespec now, gpr_timespec deadline) {
+                                grpc_millis deadline) {
   grpc_pollset_worker worker;
   grpc_error *error = GRPC_ERROR_NONE;
   static const char *err_desc = "pollset_work";
@@ -952,7 +947,7 @@
     return GRPC_ERROR_NONE;
   }
 
-  if (begin_worker(ps, &worker, worker_hdl, &now, deadline)) {
+  if (begin_worker(exec_ctx, ps, &worker, worker_hdl, deadline)) {
     gpr_tls_set(&g_current_thread_pollset, (intptr_t)ps);
     gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
     GPR_ASSERT(!ps->shutting_down);
@@ -975,8 +970,7 @@
        designated poller */
     if (gpr_atm_acq_load(&g_epoll_set.cursor) ==
         gpr_atm_acq_load(&g_epoll_set.num_events)) {
-      append_error(&error, do_epoll_wait(exec_ctx, ps, now, deadline),
-                   err_desc);
+      append_error(&error, do_epoll_wait(exec_ctx, ps, deadline), err_desc);
     }
     append_error(&error, process_epoll_events(exec_ctx, ps), err_desc);
 
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index bed47e4..59dd8fd 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <pthread.h>
 #include <string.h>
@@ -38,7 +39,7 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
-#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/is_epollexclusive_available.h"
 #include "src/core/lib/iomgr/lockfree_event.h"
@@ -46,19 +47,18 @@
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/spinlock.h"
 
 /*******************************************************************************
  * Polling object
  */
-
 typedef enum {
   PO_POLLING_GROUP,
   PO_POLLSET_SET,
   PO_POLLSET,
-  PO_FD, /* ordering is important: we always want to lock pollsets before fds:
-            this guarantees that using an fd as a pollable is safe */
+  PO_FD,
+  /* ordering is important: we always want to lock pollsets before fds:
+     this guarantees that using an fd as a pollable is safe */
   PO_EMPTY_POLLABLE,
   PO_COUNT
 } polling_obj_type;
@@ -690,32 +690,16 @@
   *mu = &pollset->pollable_obj.po.mu;
 }
 
-/* Convert a timespec to milliseconds:
-   - Very small or negative poll times are clamped to zero to do a non-blocking
-     poll (which becomes spin polling)
-   - Other small values are rounded up to one millisecond
-   - Longer than a millisecond polls are rounded up to the next nearest
-     millisecond to avoid spinning
-   - Infinite timeouts are converted to -1 */
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                           gpr_timespec now) {
-  gpr_timespec timeout;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
-    return -1;
-  }
-
-  if (gpr_time_cmp(deadline, now) <= 0) {
+static int poll_deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                           grpc_millis millis) {
+  if (millis == GRPC_MILLIS_INF_FUTURE) return -1;
+  grpc_millis delta = millis - grpc_exec_ctx_now(exec_ctx);
+  if (delta > INT_MAX)
+    return INT_MAX;
+  else if (delta < 0)
     return 0;
-  }
-
-  static const gpr_timespec round_up = {
-      0,                 /* tv_sec */
-      GPR_NS_PER_MS - 1, /* tv_nsec */
-      GPR_TIMESPAN       /* clock_type */
-  };
-  timeout = gpr_time_sub(deadline, now);
-  int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up));
-  return millis >= 1 ? millis : 1;
+  else
+    return (int)delta;
 }
 
 static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
@@ -810,9 +794,8 @@
 }
 
 static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                                 pollable *p, gpr_timespec now,
-                                 gpr_timespec deadline) {
-  int timeout = poll_deadline_to_millis_timeout(deadline, now);
+                                 pollable *p, grpc_millis deadline) {
+  int timeout = poll_deadline_to_millis_timeout(exec_ctx, deadline);
 
   if (GRPC_TRACER_ON(grpc_polling_trace)) {
     char *desc = pollable_desc(p);
@@ -829,7 +812,7 @@
     r = epoll_wait(p->epfd, pollset->events, MAX_EPOLL_EVENTS, timeout);
   } while (r < 0 && errno == EINTR);
   if (timeout != 0) {
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
+    GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
   }
 
   if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
@@ -884,9 +867,10 @@
 }
 
 /* Return true if this thread should poll */
-static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker,
-                         grpc_pollset_worker **worker_hdl, gpr_timespec *now,
-                         gpr_timespec deadline) {
+static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                         grpc_pollset_worker *worker,
+                         grpc_pollset_worker **worker_hdl,
+                         grpc_millis deadline) {
   bool do_poll = true;
   if (worker_hdl != NULL) *worker_hdl = worker;
   worker->initialized_cv = false;
@@ -910,10 +894,11 @@
         worker->pollable_obj->root_worker != worker) {
       gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset,
               worker->pollable_obj, worker,
-              poll_deadline_to_millis_timeout(deadline, *now));
+              poll_deadline_to_millis_timeout(exec_ctx, deadline));
     }
     while (do_poll && worker->pollable_obj->root_worker != worker) {
-      if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->po.mu, deadline)) {
+      if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->po.mu,
+                      grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
         if (GRPC_TRACER_ON(grpc_polling_trace)) {
           gpr_log(GPR_DEBUG, "PS:%p timeout_wait %p w=%p", pollset,
                   worker->pollable_obj, worker);
@@ -936,7 +921,7 @@
       gpr_mu_lock(&pollset->pollable_obj.po.mu);
       gpr_mu_lock(&worker->pollable_obj->po.mu);
     }
-    *now = gpr_now(now->clock_type);
+    grpc_exec_ctx_invalidate_now(exec_ctx);
   }
 
   return do_poll && pollset->shutdown_closure == NULL &&
@@ -967,14 +952,13 @@
    ensure that it is held by the time the function returns */
 static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 grpc_pollset_worker **worker_hdl,
-                                gpr_timespec now, gpr_timespec deadline) {
+                                grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (0 && GRPC_TRACER_ON(grpc_polling_trace)) {
-    gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64
-                       ".%09d deadline=%" PRId64 ".%09d kwp=%d root_worker=%p",
-            pollset, worker_hdl, &worker, now.tv_sec, now.tv_nsec,
-            deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller,
-            pollset->root_worker);
+    gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRIdPTR
+                       " deadline=%" PRIdPTR " kwp=%d root_worker=%p",
+            pollset, worker_hdl, &worker, grpc_exec_ctx_now(exec_ctx), deadline,
+            pollset->kicked_without_poller, pollset->root_worker);
   }
   grpc_error *error = GRPC_ERROR_NONE;
   static const char *err_desc = "pollset_work";
@@ -985,7 +969,7 @@
   if (pollset->current_pollable_obj != &pollset->pollable_obj) {
     gpr_mu_lock(&pollset->current_pollable_obj->po.mu);
   }
-  if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) {
+  if (begin_worker(exec_ctx, pollset, &worker, worker_hdl, deadline)) {
     gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
     gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
     GPR_ASSERT(!pollset->shutdown_closure);
@@ -996,7 +980,7 @@
     gpr_mu_unlock(&pollset->pollable_obj.po.mu);
     if (pollset->event_cursor == pollset->event_count) {
       append_error(&error, pollset_epoll(exec_ctx, pollset, worker.pollable_obj,
-                                         now, deadline),
+                                         deadline),
                    err_desc);
     }
     append_error(&error, pollset_process_events(exec_ctx, pollset, false),
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
index c8e07c6..370ea1d 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ b/src/core/lib/iomgr/ev_epollsig_linux.cc
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <pthread.h>
 #include <signal.h>
@@ -40,13 +41,13 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/lockfree_event.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
 
 #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
 
@@ -1089,30 +1090,16 @@
   pollset->shutdown_done = NULL;
 }
 
-/* Convert a timespec to milliseconds:
-   - Very small or negative poll times are clamped to zero to do a non-blocking
-     poll (which becomes spin polling)
-   - Other small values are rounded up to one millisecond
-   - Longer than a millisecond polls are rounded up to the next nearest
-     millisecond to avoid spinning
-   - Infinite timeouts are converted to -1 */
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                           gpr_timespec now) {
-  gpr_timespec timeout;
-  static const int64_t max_spin_polling_us = 10;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
-    return -1;
-  }
-
-  if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
-                                                   max_spin_polling_us,
-                                                   GPR_TIMESPAN))) <= 0) {
+static int poll_deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                           grpc_millis millis) {
+  if (millis == GRPC_MILLIS_INF_FUTURE) return -1;
+  grpc_millis delta = millis - grpc_exec_ctx_now(exec_ctx);
+  if (delta > INT_MAX)
+    return INT_MAX;
+  else if (delta < 0)
     return 0;
-  }
-  timeout = gpr_time_sub(deadline, now);
-  int millis = gpr_time_to_millis(gpr_time_add(
-      timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
-  return millis >= 1 ? millis : 1;
+  else
+    return (int)delta;
 }
 
 static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
@@ -1243,7 +1230,7 @@
   GRPC_STATS_INC_SYSCALL_POLL(exec_ctx);
   ep_rv =
       epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
   if (ep_rv < 0) {
     if (errno != EINTR) {
       gpr_asprintf(&err_msg,
@@ -1310,10 +1297,10 @@
    ensure that it is held by the time the function returns */
 static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 grpc_pollset_worker **worker_hdl,
-                                gpr_timespec now, gpr_timespec deadline) {
+                                grpc_millis deadline) {
   GPR_TIMER_BEGIN("pollset_work", 0);
   grpc_error *error = GRPC_ERROR_NONE;
-  int timeout_ms = poll_deadline_to_millis_timeout(deadline, now);
+  int timeout_ms = poll_deadline_to_millis_timeout(exec_ctx, deadline);
 
   sigset_t new_mask;
 
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index e170702..036a356 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <string.h>
 #include <sys/socket.h>
@@ -37,12 +38,11 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_cv.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/murmur_hash.h"
 
 #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
@@ -50,7 +50,6 @@
 /*******************************************************************************
  * FD declarations
  */
-
 typedef struct grpc_fd_watcher {
   struct grpc_fd_watcher *next;
   struct grpc_fd_watcher *prev;
@@ -200,8 +199,8 @@
    - longer than a millisecond polls are rounded up to the next nearest
      millisecond to avoid spinning
    - infinite timeouts are converted to -1 */
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                           gpr_timespec now);
+static int poll_deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                           grpc_millis deadline);
 
 /* Allow kick to wakeup the currently polling worker */
 #define GRPC_POLLSET_CAN_KICK_SELF 1
@@ -876,7 +875,7 @@
 
 static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 grpc_pollset_worker **worker_hdl,
-                                gpr_timespec now, gpr_timespec deadline) {
+                                grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
   grpc_error *error = GRPC_ERROR_NONE;
@@ -945,7 +944,7 @@
       grpc_fd_watcher *watchers;
       struct pollfd *pfds;
 
-      timeout = poll_deadline_to_millis_timeout(deadline, now);
+      timeout = poll_deadline_to_millis_timeout(exec_ctx, deadline);
 
       if (pollset->fd_count + 2 <= inline_elements) {
         pfds = pollfd_space;
@@ -991,7 +990,7 @@
       GRPC_SCHEDULING_START_BLOCKING_REGION;
       GRPC_STATS_INC_SYSCALL_POLL(exec_ctx);
       r = grpc_poll_function(pfds, pfd_count, timeout);
-      GRPC_SCHEDULING_END_BLOCKING_REGION;
+      GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
 
       if (GRPC_TRACER_ON(grpc_polling_trace)) {
         gpr_log(GPR_DEBUG, "%p poll=%d", pollset, r);
@@ -1068,13 +1067,10 @@
       if (queued_work || worker.kicked_specifically) {
         /* If there's queued work on the list, then set the deadline to be
            immediate so we get back out of the polling loop quickly */
-        deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+        deadline = 0;
       }
       keep_polling = 1;
     }
-    if (keep_polling) {
-      now = gpr_now(now.clock_type);
-    }
   }
   gpr_tls_set(&g_current_thread_poller, 0);
   if (added_worker) {
@@ -1126,21 +1122,14 @@
   }
 }
 
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                           gpr_timespec now) {
-  gpr_timespec timeout;
-  static const int64_t max_spin_polling_us = 10;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
-    return -1;
-  }
-  if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
-                                                   max_spin_polling_us,
-                                                   GPR_TIMESPAN))) <= 0) {
-    return 0;
-  }
-  timeout = gpr_time_sub(deadline, now);
-  return gpr_time_to_millis(gpr_time_add(
-      timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
+static int poll_deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                           grpc_millis deadline) {
+  if (deadline == GRPC_MILLIS_INF_FUTURE) return -1;
+  if (deadline == 0) return 0;
+  grpc_millis n = deadline - grpc_exec_ctx_now(exec_ctx);
+  if (n < 0) return 0;
+  if (n > INT_MAX) return -1;
+  return (int)n;
 }
 
 /*******************************************************************************
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index 4d3ae22..e4033fa 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -205,9 +205,9 @@
 }
 
 grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                              grpc_pollset_worker **worker, gpr_timespec now,
-                              gpr_timespec deadline) {
-  return g_event_engine->pollset_work(exec_ctx, pollset, worker, now, deadline);
+                              grpc_pollset_worker **worker,
+                              grpc_millis deadline) {
+  return g_event_engine->pollset_work(exec_ctx, pollset, worker, deadline);
 }
 
 grpc_error *grpc_pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 5ad1c13..955326c 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -56,8 +56,8 @@
                            grpc_closure *closure);
   void (*pollset_destroy)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset);
   grpc_error *(*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                              grpc_pollset_worker **worker, gpr_timespec now,
-                              gpr_timespec deadline);
+                              grpc_pollset_worker **worker,
+                              grpc_millis deadline);
   grpc_error *(*pollset_kick)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                               grpc_pollset_worker *specific_worker);
   void (*pollset_add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc
index 41c69ad..3d17afc 100644
--- a/src/core/lib/iomgr/exec_ctx.cc
+++ b/src/core/lib/iomgr/exec_ctx.cc
@@ -104,9 +104,69 @@
   grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
 }
 
-void grpc_exec_ctx_global_init(void) {}
+static gpr_timespec
+    g_start_time[GPR_TIMESPAN + 1];  // assumes GPR_TIMESPAN is the
+                                     // last enum value in
+                                     // gpr_clock_type
+
+void grpc_exec_ctx_global_init(void) {
+  for (int i = 0; i < GPR_TIMESPAN; i++) {
+    g_start_time[i] = gpr_now((gpr_clock_type)i);
+  }
+  // allows uniform treatment in conversion functions
+  g_start_time[GPR_TIMESPAN] = gpr_time_0(GPR_TIMESPAN);
+}
+
 void grpc_exec_ctx_global_shutdown(void) {}
 
+static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
+  ts = gpr_time_sub(ts, g_start_time[ts.clock_type]);
+  double x =
+      GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
+  if (x < 0) return 0;
+  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+  return (gpr_atm)x;
+}
+
+static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
+  ts = gpr_time_sub(ts, g_start_time[ts.clock_type]);
+  double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
+             (double)ts.tv_nsec / GPR_NS_PER_MS +
+             (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
+  if (x < 0) return 0;
+  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+  return (gpr_atm)x;
+}
+
+grpc_millis grpc_exec_ctx_now(grpc_exec_ctx *exec_ctx) {
+  if (!exec_ctx->now_is_valid) {
+    exec_ctx->now = timespec_to_atm_round_down(gpr_now(GPR_CLOCK_MONOTONIC));
+    exec_ctx->now_is_valid = true;
+  }
+  return exec_ctx->now;
+}
+
+void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx) {
+  exec_ctx->now_is_valid = false;
+}
+
+gpr_timespec grpc_millis_to_timespec(grpc_millis millis,
+                                     gpr_clock_type clock_type) {
+  if (clock_type == GPR_TIMESPAN) {
+    return gpr_time_from_millis(millis, GPR_TIMESPAN);
+  }
+  return gpr_time_add(g_start_time[clock_type],
+                      gpr_time_from_millis(millis, GPR_TIMESPAN));
+}
+
+grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec ts) {
+  return timespec_to_atm_round_down(ts);
+}
+
+grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec ts) {
+  return timespec_to_atm_round_up(ts);
+}
+
 static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
     exec_ctx_run, exec_ctx_sched, "exec_ctx"};
 static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable};
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index a93728f..44b9be7 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -19,14 +19,19 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 #define GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 
+#include <grpc/support/atm.h>
 #include <grpc/support/cpu.h>
+
 #include "src/core/lib/iomgr/closure.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */
+typedef gpr_atm grpc_millis;
+
+#define GRPC_MILLIS_INF_FUTURE GPR_ATM_MAX
+#define GRPC_MILLIS_INF_PAST GPR_ATM_MIN
 
 /** A workqueue represents a list of work to be executed asynchronously.
     Forward declared here to avoid a circular dependency with workqueue.h. */
@@ -70,6 +75,9 @@
   unsigned starting_cpu;
   void *check_ready_to_finish_arg;
   bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
+
+  bool now_is_valid;
+  grpc_millis now;
 };
 
 /* initializer for grpc_exec_ctx:
@@ -77,7 +85,7 @@
 #define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \
   {                                                                      \
     GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, gpr_cpu_current_cpu(),    \
-        finish_check_arg, finish_check                                   \
+        finish_check_arg, finish_check, false, 0                         \
   }
 
 /* initialize an execution context at the top level of an API call into grpc
@@ -110,6 +118,12 @@
 void grpc_exec_ctx_global_init(void);
 void grpc_exec_ctx_global_shutdown(void);
 
+grpc_millis grpc_exec_ctx_now(grpc_exec_ctx *exec_ctx);
+void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx);
+gpr_timespec grpc_millis_to_timespec(grpc_millis millis, gpr_clock_type clock);
+grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec timespec);
+grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec timespec);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc
index ebe7f24..92c3e70 100644
--- a/src/core/lib/iomgr/executor.cc
+++ b/src/core/lib/iomgr/executor.cc
@@ -178,6 +178,7 @@
       gpr_log(GPR_DEBUG, "EXECUTOR[%d]: execute", (int)(ts - g_thread_state));
     }
 
+    grpc_exec_ctx_invalidate_now(&exec_ctx);
     subtract_depth = run_closures(&exec_ctx, exec);
   }
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/iomgr/iocp_windows.cc b/src/core/lib/iomgr/iocp_windows.cc
index c082179..336cc86 100644
--- a/src/core/lib/iomgr/iocp_windows.cc
+++ b/src/core/lib/iomgr/iocp_windows.cc
@@ -26,6 +26,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 #include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
@@ -40,25 +41,17 @@
 
 static HANDLE g_iocp;
 
-static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
-                                        gpr_timespec now) {
+static DWORD deadline_to_millis_timeout(grpc_exec_ctx *exec_ctx,
+                                        grpc_millis deadline) {
   gpr_timespec timeout;
-  static const int64_t max_spin_polling_us = 10;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
+  if (deadline == GRPC_MILLIS_INF_FUTURE) {
     return INFINITE;
   }
-  if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
-                                                   max_spin_polling_us,
-                                                   GPR_TIMESPAN))) <= 0) {
-    return 0;
-  }
-  timeout = gpr_time_sub(deadline, now);
-  return (DWORD)gpr_time_to_millis(gpr_time_add(
-      timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
+  return (DWORD)GPR_MAX(0, deadline - grpc_exec_ctx_now(exec_ctx));
 }
 
 grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
-                                     gpr_timespec deadline) {
+                                     grpc_millis deadline) {
   BOOL success;
   DWORD bytes = 0;
   DWORD flags = 0;
@@ -67,9 +60,9 @@
   grpc_winsocket *socket;
   grpc_winsocket_callback_info *info;
   GRPC_STATS_INC_SYSCALL_POLL(exec_ctx);
-  success = GetQueuedCompletionStatus(
-      g_iocp, &bytes, &completion_key, &overlapped,
-      deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
+  success =
+      GetQueuedCompletionStatus(g_iocp, &bytes, &completion_key, &overlapped,
+                                deadline_to_millis_timeout(exec_ctx, deadline));
   if (success == 0 && overlapped == NULL) {
     return GRPC_IOCP_WORK_TIMEOUT;
   }
@@ -121,7 +114,7 @@
   grpc_iocp_work_status work_status;
 
   do {
-    work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
+    work_status = grpc_iocp_work(&exec_ctx, GRPC_MILLIS_INF_PAST);
   } while (work_status == GRPC_IOCP_WORK_KICK ||
            grpc_exec_ctx_flush(&exec_ctx));
 }
@@ -129,7 +122,7 @@
 void grpc_iocp_shutdown(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   while (gpr_atm_acq_load(&g_custom_events)) {
-    grpc_iocp_work(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+    grpc_iocp_work(&exec_ctx, GRPC_MILLIS_INF_FUTURE);
     grpc_exec_ctx_flush(&exec_ctx);
   }
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h
index 341c159..aefe7a2 100644
--- a/src/core/lib/iomgr/iocp_windows.h
+++ b/src/core/lib/iomgr/iocp_windows.h
@@ -34,7 +34,7 @@
 } grpc_iocp_work_status;
 
 grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
-                                     gpr_timespec deadline);
+                                     grpc_millis deadline);
 void grpc_iocp_init(void);
 void grpc_iocp_kick(void);
 void grpc_iocp_flush(void);
diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc
index 3a06058..d6a5b4a 100644
--- a/src/core/lib/iomgr/iomgr.cc
+++ b/src/core/lib/iomgr/iomgr.cc
@@ -51,7 +51,7 @@
   gpr_cv_init(&g_rcv);
   grpc_exec_ctx_global_init();
   grpc_executor_init(exec_ctx);
-  grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_list_init(exec_ctx);
   g_root_object.next = g_root_object.prev = &g_root_object;
   g_root_object.name = (char *)"root";
   grpc_network_status_init();
@@ -98,8 +98,9 @@
       }
       last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
     }
-    if (grpc_timer_check(exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL) ==
-        GRPC_TIMERS_FIRED) {
+    exec_ctx->now_is_valid = true;
+    exec_ctx->now = GRPC_MILLIS_INF_FUTURE;
+    if (grpc_timer_check(exec_ctx, NULL) == GRPC_TIMERS_FIRED) {
       gpr_mu_unlock(&g_mu);
       grpc_exec_ctx_flush(exec_ctx);
       grpc_iomgr_platform_flush();
diff --git a/src/core/lib/iomgr/load_file.cc b/src/core/lib/iomgr/load_file.cc
index 0b4d41e..5cb4099 100644
--- a/src/core/lib/iomgr/load_file.cc
+++ b/src/core/lib/iomgr/load_file.cc
@@ -25,7 +25,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/support/string.h"
 
 grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
@@ -73,6 +73,6 @@
     GRPC_ERROR_UNREF(error);
     error = error_out;
   }
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
   return error;
 }
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index 28d6394..799fae1 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -75,8 +75,8 @@
    pollset
    lock */
 grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                              grpc_pollset_worker **worker, gpr_timespec now,
-                              gpr_timespec deadline) GRPC_MUST_USE_RESULT;
+                              grpc_pollset_worker **worker,
+                              grpc_millis deadline) GRPC_MUST_USE_RESULT;
 
 /* Break one polling thread out of polling work for this pollset.
    If specific_worker is non-NULL, then kick that worker. */
diff --git a/src/core/lib/iomgr/pollset_uv.cc b/src/core/lib/iomgr/pollset_uv.cc
index 7ea5019..b9901bf 100644
--- a/src/core/lib/iomgr/pollset_uv.cc
+++ b/src/core/lib/iomgr/pollset_uv.cc
@@ -116,13 +116,14 @@
 
 grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                               grpc_pollset_worker **worker_hdl,
-                              gpr_timespec now, gpr_timespec deadline) {
+                              grpc_millis deadline) {
   uint64_t timeout;
   GRPC_UV_ASSERT_SAME_THREAD();
   gpr_mu_unlock(&grpc_polling_mu);
   if (grpc_pollset_work_run_loop) {
-    if (gpr_time_cmp(deadline, now) >= 0) {
-      timeout = (uint64_t)gpr_time_to_millis(gpr_time_sub(deadline, now));
+    grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+    if (deadline >= now) {
+      timeout = deadline - now;
     } else {
       timeout = 0;
     }
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index eb295d3..bb4df83 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -110,7 +110,7 @@
 
 grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                               grpc_pollset_worker **worker_hdl,
-                              gpr_timespec now, gpr_timespec deadline) {
+                              grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
 
@@ -159,7 +159,8 @@
                       &worker);
     added_worker = 1;
     while (!worker.kicked) {
-      if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) {
+      if (gpr_cv_wait(&worker.cv, &grpc_polling_mu,
+                      grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
         break;
       }
     }
diff --git a/src/core/lib/iomgr/resolve_address_posix.cc b/src/core/lib/iomgr/resolve_address_posix.cc
index 60cfeeb..1b78349 100644
--- a/src/core/lib/iomgr/resolve_address_posix.cc
+++ b/src/core/lib/iomgr/resolve_address_posix.cc
@@ -33,10 +33,10 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/string.h"
 
 static grpc_error *blocking_resolve_address_impl(
@@ -81,7 +81,7 @@
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   s = getaddrinfo(host, port, &hints, &result);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
 
   if (s != 0) {
     /* Retry if well-known service name is recognized */
@@ -90,7 +90,7 @@
       if (strcmp(port, svc[i][0]) == 0) {
         GRPC_SCHEDULING_START_BLOCKING_REGION;
         s = getaddrinfo(host, svc[i][1], &hints, &result);
-        GRPC_SCHEDULING_END_BLOCKING_REGION;
+        GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
         break;
       }
     }
diff --git a/src/core/lib/iomgr/resolve_address_windows.cc b/src/core/lib/iomgr/resolve_address_windows.cc
index abcfc21..451f01a 100644
--- a/src/core/lib/iomgr/resolve_address_windows.cc
+++ b/src/core/lib/iomgr/resolve_address_windows.cc
@@ -34,10 +34,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/string.h"
 
 typedef struct {
@@ -87,7 +87,7 @@
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   s = getaddrinfo(host, port, &hints, &result);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
   if (s != 0) {
     error = GRPC_WSA_ERROR(WSAGetLastError(), "getaddrinfo");
     goto done;
diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc
index 6026243..ecb5747 100644
--- a/src/core/lib/iomgr/resource_quota.cc
+++ b/src/core/lib/iomgr/resource_quota.cc
@@ -89,6 +89,8 @@
   grpc_closure_list on_allocated;
   /* True if we are currently trying to allocate from the quota, false if not */
   bool allocating;
+  /* How many bytes of allocations are outstanding */
+  int64_t outstanding_allocations;
   /* True if we are currently trying to add ourselves to the non-free quota
      list, false otherwise */
   bool added_to_free_pool;
@@ -153,6 +155,9 @@
   char *name;
 };
 
+static void ru_unref_by(grpc_exec_ctx *exec_ctx,
+                        grpc_resource_user *resource_user, gpr_atm amount);
+
 /*******************************************************************************
  * list management
  */
@@ -289,6 +294,25 @@
   while ((resource_user = rulist_pop_head(resource_quota,
                                           GRPC_RULIST_AWAITING_ALLOCATION))) {
     gpr_mu_lock(&resource_user->mu);
+    if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+      gpr_log(GPR_DEBUG, "RQ: check allocation for user %p shutdown=%" PRIdPTR
+                         " free_pool=%" PRId64,
+              resource_user, gpr_atm_no_barrier_load(&resource_user->shutdown),
+              resource_user->free_pool);
+    }
+    if (gpr_atm_no_barrier_load(&resource_user->shutdown)) {
+      resource_user->allocating = false;
+      grpc_closure_list_fail_all(
+          &resource_user->on_allocated,
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource user shutdown"));
+      int64_t aborted_allocations = resource_user->outstanding_allocations;
+      resource_user->outstanding_allocations = 0;
+      resource_user->free_pool += aborted_allocations;
+      GRPC_CLOSURE_LIST_SCHED(exec_ctx, &resource_user->on_allocated);
+      gpr_mu_unlock(&resource_user->mu);
+      ru_unref_by(exec_ctx, resource_user, (gpr_atm)aborted_allocations);
+      continue;
+    }
     if (resource_user->free_pool < 0 &&
         -resource_user->free_pool <= resource_quota->free_pool) {
       int64_t amt = -resource_user->free_pool;
@@ -308,6 +332,7 @@
     }
     if (resource_user->free_pool >= 0) {
       resource_user->allocating = false;
+      resource_user->outstanding_allocations = 0;
       GRPC_CLOSURE_LIST_SCHED(exec_ctx, &resource_user->on_allocated);
       gpr_mu_unlock(&resource_user->mu);
     } else {
@@ -488,6 +513,9 @@
 }
 
 static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
+  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+    gpr_log(GPR_DEBUG, "RU shutdown %p", ru);
+  }
   grpc_resource_user *resource_user = (grpc_resource_user *)ru;
   GRPC_CLOSURE_SCHED(exec_ctx, resource_user->reclaimers[0],
                      GRPC_ERROR_CANCELLED);
@@ -497,6 +525,9 @@
   resource_user->reclaimers[1] = NULL;
   rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
   rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
+  if (resource_user->allocating) {
+    rq_step_sched(exec_ctx, resource_user->resource_quota);
+  }
 }
 
 static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
@@ -718,6 +749,7 @@
   resource_user->reclaimers[1] = NULL;
   resource_user->new_reclaimers[0] = NULL;
   resource_user->new_reclaimers[1] = NULL;
+  resource_user->outstanding_allocations = 0;
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
     resource_user->links[i].next = resource_user->links[i].prev = NULL;
   }
@@ -778,6 +810,7 @@
   gpr_mu_lock(&resource_user->mu);
   ru_ref_by(resource_user, (gpr_atm)size);
   resource_user->free_pool -= (int64_t)size;
+  resource_user->outstanding_allocations += (int64_t)size;
   if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
     gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
@@ -792,6 +825,7 @@
                          GRPC_ERROR_NONE);
     }
   } else {
+    resource_user->outstanding_allocations -= (int64_t)size;
     GRPC_CLOSURE_SCHED(exec_ctx, optional_on_done, GRPC_ERROR_NONE);
   }
   gpr_mu_unlock(&resource_user->mu);
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 18cf611..1b102b5 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -39,7 +39,7 @@
                              grpc_pollset_set *interested_parties,
                              const grpc_channel_args *channel_args,
                              const grpc_resolved_address *addr,
-                             gpr_timespec deadline);
+                             grpc_millis deadline);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 7d9e953..5611dd9 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -48,7 +48,6 @@
 typedef struct {
   gpr_mu mu;
   grpc_fd *fd;
-  gpr_timespec deadline;
   grpc_timer alarm;
   grpc_closure on_alarm;
   int refs;
@@ -244,7 +243,7 @@
                                     grpc_pollset_set *interested_parties,
                                     const grpc_channel_args *channel_args,
                                     const grpc_resolved_address *addr,
-                                    gpr_timespec deadline) {
+                                    grpc_millis deadline) {
   int fd;
   grpc_dualstack_mode dsmode;
   int err;
@@ -325,9 +324,7 @@
 
   gpr_mu_lock(&ac->mu);
   GRPC_CLOSURE_INIT(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
-  grpc_timer_init(exec_ctx, &ac->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm);
   grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
   gpr_mu_unlock(&ac->mu);
 
@@ -342,7 +339,7 @@
     grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
     grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
     const grpc_resolved_address *addr,
-    gpr_timespec deadline) = tcp_client_connect_impl;
+    grpc_millis deadline) = tcp_client_connect_impl;
 }
 
 void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
@@ -350,7 +347,7 @@
                              grpc_pollset_set *interested_parties,
                              const grpc_channel_args *channel_args,
                              const grpc_resolved_address *addr,
-                             gpr_timespec deadline) {
+                             grpc_millis deadline) {
   grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
                                channel_args, addr, deadline);
 }
diff --git a/src/core/lib/iomgr/tcp_client_uv.cc b/src/core/lib/iomgr/tcp_client_uv.cc
index 8383597..f3e9366 100644
--- a/src/core/lib/iomgr/tcp_client_uv.cc
+++ b/src/core/lib/iomgr/tcp_client_uv.cc
@@ -119,7 +119,7 @@
                                     grpc_pollset_set *interested_parties,
                                     const grpc_channel_args *channel_args,
                                     const grpc_resolved_address *resolved_addr,
-                                    gpr_timespec deadline) {
+                                    grpc_millis deadline) {
   grpc_uv_tcp_connect *connect;
   grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
   (void)channel_args;
@@ -158,9 +158,7 @@
                  uv_tc_on_connect);
   GRPC_CLOSURE_INIT(&connect->on_alarm, uv_tc_on_alarm, connect,
                     grpc_schedule_on_exec_ctx);
-  grpc_timer_init(exec_ctx, &connect->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &connect->alarm, deadline, &connect->on_alarm);
 }
 
 // overridden by api_fuzzer.c
@@ -169,7 +167,7 @@
     grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
     grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
     const grpc_resolved_address *addr,
-    gpr_timespec deadline) = tcp_client_connect_impl;
+    grpc_millis deadline) = tcp_client_connect_impl;
 }
 
 void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
@@ -177,7 +175,7 @@
                              grpc_pollset_set *interested_parties,
                              const grpc_channel_args *channel_args,
                              const grpc_resolved_address *addr,
-                             gpr_timespec deadline) {
+                             grpc_millis deadline) {
   grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
                                channel_args, addr, deadline);
 }
diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc
index 1154965..9adf7ee 100644
--- a/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/src/core/lib/iomgr/tcp_client_windows.cc
@@ -43,7 +43,6 @@
   grpc_closure *on_done;
   gpr_mu mu;
   grpc_winsocket *socket;
-  gpr_timespec deadline;
   grpc_timer alarm;
   grpc_closure on_alarm;
   char *addr_name;
@@ -126,7 +125,7 @@
 static void tcp_client_connect_impl(
     grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_endpoint **endpoint,
     grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
-    const grpc_resolved_address *addr, gpr_timespec deadline) {
+    const grpc_resolved_address *addr, grpc_millis deadline) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
   int status;
@@ -206,8 +205,7 @@
   GRPC_CLOSURE_INIT(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
 
   GRPC_CLOSURE_INIT(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
-  grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm);
   grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
   return;
 
@@ -233,7 +231,7 @@
     grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
     grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
     const grpc_resolved_address *addr,
-    gpr_timespec deadline) = tcp_client_connect_impl;
+    grpc_millis deadline) = tcp_client_connect_impl;
 }
 
 void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
@@ -241,7 +239,7 @@
                              grpc_pollset_set *interested_parties,
                              const grpc_channel_args *channel_args,
                              const grpc_resolved_address *addr,
-                             gpr_timespec deadline) {
+                             grpc_millis deadline) {
   grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
                                channel_args, addr, deadline);
 }
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index 7e27129..7fcaef7 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -135,13 +135,11 @@
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p run", p);
   }
   gpr_mu_lock(p->pollset_mu);
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  gpr_timespec deadline =
-      gpr_time_add(now, gpr_time_from_seconds(10, GPR_TIMESPAN));
+  grpc_millis deadline = grpc_exec_ctx_now(exec_ctx) + 13 * GPR_MS_PER_SEC;
   GRPC_STATS_INC_TCP_BACKUP_POLLER_POLLS(exec_ctx);
-  GRPC_LOG_IF_ERROR("backup_poller:pollset_work",
-                    grpc_pollset_work(exec_ctx, BACKUP_POLLER_POLLSET(p), NULL,
-                                      now, deadline));
+  GRPC_LOG_IF_ERROR(
+      "backup_poller:pollset_work",
+      grpc_pollset_work(exec_ctx, BACKUP_POLLER_POLLSET(p), NULL, deadline));
   gpr_mu_unlock(p->pollset_mu);
   /* last "uncovered" notification is the ref that keeps us polling, if we get
    * there try a cas to release it */
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index 466600d..419e834 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -45,8 +45,7 @@
    application callback is also responsible for maintaining information about
    when to free up any user-level state. */
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_closure *closure,
-                     gpr_timespec now);
+                     grpc_millis deadline, grpc_closure *closure);
 
 /* Initialize *timer without setting it. This can later be passed through
    the regular init or cancel */
@@ -96,8 +95,8 @@
    with high probability at least one thread in the system will see an update
    at any time slice. */
 grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx,
-                                         gpr_timespec now, gpr_timespec *next);
-void grpc_timer_list_init(gpr_timespec now);
+                                         grpc_millis *next);
+void grpc_timer_list_init(grpc_exec_ctx *exec_ctx);
 void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx);
 
 /* Consume a kick issued by grpc_kick_poller */
diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc
index 971d80d..b8e895d 100644
--- a/src/core/lib/iomgr/timer_generic.cc
+++ b/src/core/lib/iomgr/timer_generic.cc
@@ -220,9 +220,6 @@
 
 static struct shared_mutables g_shared_mutables;
 
-static gpr_clock_type g_clock_type;
-static gpr_timespec g_start_time;
-
 static gpr_atm saturating_add(gpr_atm a, gpr_atm b) {
   if (a > GPR_ATM_MAX - b) {
     return GPR_ATM_MAX;
@@ -235,52 +232,19 @@
                                                        gpr_atm *next,
                                                        grpc_error *error);
 
-static gpr_timespec dbl_to_ts(double d) {
-  gpr_timespec ts;
-  ts.tv_sec = (int64_t)d;
-  ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
-  ts.clock_type = GPR_TIMESPAN;
-  return ts;
-}
-
-static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
-  ts = gpr_time_sub(ts, g_start_time);
-  double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
-             (double)ts.tv_nsec / GPR_NS_PER_MS +
-             (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
-  if (x < 0) return 0;
-  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
-  return (gpr_atm)x;
-}
-
-static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
-  ts = gpr_time_sub(ts, g_start_time);
-  double x =
-      GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
-  if (x < 0) return 0;
-  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
-  return (gpr_atm)x;
-}
-
-static gpr_timespec atm_to_timespec(gpr_atm x) {
-  return gpr_time_add(g_start_time, dbl_to_ts((double)x / 1000.0));
-}
-
 static gpr_atm compute_min_deadline(timer_shard *shard) {
   return grpc_timer_heap_is_empty(&shard->heap)
              ? saturating_add(shard->queue_deadline_cap, 1)
              : grpc_timer_heap_top(&shard->heap)->deadline;
 }
 
-void grpc_timer_list_init(gpr_timespec now) {
+void grpc_timer_list_init(grpc_exec_ctx *exec_ctx) {
   uint32_t i;
 
   g_shared_mutables.initialized = true;
   g_shared_mutables.checker_mu = GPR_SPINLOCK_INITIALIZER;
   gpr_mu_init(&g_shared_mutables.mu);
-  g_clock_type = now.clock_type;
-  g_start_time = now;
-  g_shared_mutables.min_timer = timespec_to_atm_round_down(now);
+  g_shared_mutables.min_timer = grpc_exec_ctx_now(exec_ctx);
   gpr_tls_init(&g_last_seen_min_timer);
   gpr_tls_set(&g_last_seen_min_timer, 0);
   grpc_register_tracer(&grpc_timer_trace);
@@ -317,10 +281,6 @@
   g_shared_mutables.initialized = false;
 }
 
-static double ts_to_dbl(gpr_timespec ts) {
-  return (double)ts.tv_sec + 1e-9 * ts.tv_nsec;
-}
-
 /* returns true if the first element in the list */
 static void list_join(grpc_timer *head, grpc_timer *timer) {
   timer->next = head;
@@ -361,24 +321,20 @@
 void grpc_timer_init_unset(grpc_timer *timer) { timer->pending = false; }
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_closure *closure,
-                     gpr_timespec now) {
+                     grpc_millis deadline, grpc_closure *closure) {
   int is_first_timer = 0;
   timer_shard *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)];
-  GPR_ASSERT(deadline.clock_type == g_clock_type);
-  GPR_ASSERT(now.clock_type == g_clock_type);
   timer->closure = closure;
-  gpr_atm deadline_atm = timer->deadline = timespec_to_atm_round_up(deadline);
+  timer->deadline = deadline;
 
 #ifndef NDEBUG
   timer->hash_table_next = NULL;
 #endif
 
   if (GRPC_TRACER_ON(grpc_timer_trace)) {
-    gpr_log(GPR_DEBUG, "TIMER %p: SET %" PRId64 ".%09d [%" PRIdPTR
-                       "] now %" PRId64 ".%09d [%" PRIdPTR "] call %p[%p]",
-            timer, deadline.tv_sec, deadline.tv_nsec, deadline_atm, now.tv_sec,
-            now.tv_nsec, timespec_to_atm_round_down(now), closure, closure->cb);
+    gpr_log(GPR_DEBUG,
+            "TIMER %p: SET %" PRIdPTR " now %" PRIdPTR " call %p[%p]", timer,
+            deadline, grpc_exec_ctx_now(exec_ctx), closure, closure->cb);
   }
 
   if (!g_shared_mutables.initialized) {
@@ -391,7 +347,8 @@
 
   gpr_mu_lock(&shard->mu);
   timer->pending = true;
-  if (gpr_time_cmp(deadline, now) <= 0) {
+  grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+  if (deadline <= now) {
     timer->pending = false;
     GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     gpr_mu_unlock(&shard->mu);
@@ -400,11 +357,11 @@
   }
 
   grpc_time_averaged_stats_add_sample(&shard->stats,
-                                      ts_to_dbl(gpr_time_sub(deadline, now)));
+                                      (double)(deadline - now) / 1000.0);
 
   ADD_TO_HASH_TABLE(timer);
 
-  if (deadline_atm < shard->queue_deadline_cap) {
+  if (deadline < shard->queue_deadline_cap) {
     is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
   } else {
     timer->heap_index = INVALID_HEAP_INDEX;
@@ -435,12 +392,12 @@
       gpr_log(GPR_DEBUG, "  .. old shard min_deadline=%" PRIdPTR,
               shard->min_deadline);
     }
-    if (deadline_atm < shard->min_deadline) {
+    if (deadline < shard->min_deadline) {
       gpr_atm old_min_deadline = g_shard_queue[0]->min_deadline;
-      shard->min_deadline = deadline_atm;
+      shard->min_deadline = deadline;
       note_deadline_change(shard);
-      if (shard->shard_queue_index == 0 && deadline_atm < old_min_deadline) {
-        gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, deadline_atm);
+      if (shard->shard_queue_index == 0 && deadline < old_min_deadline) {
+        gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, deadline);
         grpc_kick_poller();
       }
     }
@@ -544,8 +501,9 @@
     }
     if (timer->deadline > now) return NULL;
     if (GRPC_TRACER_ON(grpc_timer_trace)) {
-      gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late", timer,
-              now - timer->deadline);
+      gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late via %s scheduler",
+              timer, now - timer->deadline,
+              timer->closure->scheduler->vtable->name);
     }
     timer->pending = false;
     grpc_timer_heap_pop(&shard->heap);
@@ -567,6 +525,10 @@
   }
   *new_min_deadline = compute_min_deadline(shard);
   gpr_mu_unlock(&shard->mu);
+  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    gpr_log(GPR_DEBUG, "  .. shard[%d] popped %" PRIdPTR,
+            (int)(shard - g_shards), n);
+  }
   return n;
 }
 
@@ -639,29 +601,27 @@
 }
 
 grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx,
-                                         gpr_timespec now, gpr_timespec *next) {
+                                         grpc_millis *next) {
   // prelude
-  GPR_ASSERT(now.clock_type == g_clock_type);
-  gpr_atm now_atm = timespec_to_atm_round_down(now);
+  grpc_millis now = grpc_exec_ctx_now(exec_ctx);
 
   /* fetch from a thread-local first: this avoids contention on a globally
      mutable cacheline in the common case */
-  gpr_atm min_timer = gpr_tls_get(&g_last_seen_min_timer);
-  if (now_atm < min_timer) {
+  grpc_millis min_timer = gpr_tls_get(&g_last_seen_min_timer);
+  if (now < min_timer) {
     if (next != NULL) {
-      *next =
-          atm_to_timespec(GPR_MIN(timespec_to_atm_round_up(*next), min_timer));
+      *next = GPR_MIN(*next, min_timer);
     }
     if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
       gpr_log(GPR_DEBUG,
-              "TIMER CHECK SKIP: now_atm=%" PRIdPTR " min_timer=%" PRIdPTR,
-              now_atm, min_timer);
+              "TIMER CHECK SKIP: now=%" PRIdPTR " min_timer=%" PRIdPTR, now,
+              min_timer);
     }
     return GRPC_TIMERS_CHECKED_AND_EMPTY;
   }
 
   grpc_error *shutdown_error =
-      gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0
+      now != GRPC_MILLIS_INF_FUTURE
           ? GRPC_ERROR_NONE
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
 
@@ -671,34 +631,24 @@
     if (next == NULL) {
       next_str = gpr_strdup("NULL");
     } else {
-      gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
-                   next->tv_nsec, timespec_to_atm_round_down(*next));
+      gpr_asprintf(&next_str, "%" PRIdPTR, *next);
     }
-    gpr_log(GPR_DEBUG, "TIMER CHECK BEGIN: now=%" PRId64 ".%09d [%" PRIdPTR
-                       "] next=%s tls_min=%" PRIdPTR " glob_min=%" PRIdPTR,
-            now.tv_sec, now.tv_nsec, now_atm, next_str,
-            gpr_tls_get(&g_last_seen_min_timer),
+    gpr_log(GPR_DEBUG, "TIMER CHECK BEGIN: now=%" PRIdPTR
+                       " next=%s tls_min=%" PRIdPTR " glob_min=%" PRIdPTR,
+            now, next_str, gpr_tls_get(&g_last_seen_min_timer),
             gpr_atm_no_barrier_load(&g_shared_mutables.min_timer));
     gpr_free(next_str);
   }
   // actual code
-  grpc_timer_check_result r;
-  gpr_atm next_atm;
-  if (next == NULL) {
-    r = run_some_expired_timers(exec_ctx, now_atm, NULL, shutdown_error);
-  } else {
-    next_atm = timespec_to_atm_round_down(*next);
-    r = run_some_expired_timers(exec_ctx, now_atm, &next_atm, shutdown_error);
-    *next = atm_to_timespec(next_atm);
-  }
+  grpc_timer_check_result r =
+      run_some_expired_timers(exec_ctx, now, next, shutdown_error);
   // tracing
   if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
     char *next_str;
     if (next == NULL) {
       next_str = gpr_strdup("NULL");
     } else {
-      gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
-                   next->tv_nsec, next_atm);
+      gpr_asprintf(&next_str, "%" PRIdPTR, *next);
     }
     gpr_log(GPR_DEBUG, "TIMER CHECK END: r=%d; next=%s", r, next_str);
     gpr_free(next_str);
diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc
index 9b54fab..1248f82 100644
--- a/src/core/lib/iomgr/timer_manager.cc
+++ b/src/core/lib/iomgr/timer_manager.cc
@@ -55,7 +55,7 @@
 static bool g_has_timed_waiter;
 // the deadline of the current timed waiter thread (only relevant if
 // g_has_timed_waiter is true)
-static gpr_timespec g_timed_waiter_deadline;
+static grpc_millis g_timed_waiter_deadline;
 // generation counter to track which thread is waiting for the next timer
 static uint64_t g_timed_waiter_generation;
 
@@ -99,9 +99,8 @@
 
 void grpc_timer_manager_tick() {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  gpr_timespec next = gpr_inf_future(GPR_CLOCK_MONOTONIC);
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  grpc_timer_check(&exec_ctx, now, &next);
+  grpc_millis next = GRPC_MILLIS_INF_FUTURE;
+  grpc_timer_check(&exec_ctx, &next);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -124,6 +123,9 @@
     gpr_mu_unlock(&g_mu);
   }
   // without our lock, flush the exec_ctx
+  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    gpr_log(GPR_DEBUG, "flush exec_ctx");
+  }
   grpc_exec_ctx_flush(exec_ctx);
   gpr_mu_lock(&g_mu);
   // garbage collect any threads hanging out that are dead
@@ -136,8 +138,7 @@
 // wait until 'next' (or forever if there is already a timed waiter in the pool)
 // returns true if the thread should continue executing (false if it should
 // shutdown)
-static bool wait_until(gpr_timespec next) {
-  const gpr_timespec inf_future = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+static bool wait_until(grpc_exec_ctx *exec_ctx, grpc_millis next) {
   gpr_mu_lock(&g_mu);
   // if we're not threaded anymore, leave
   if (!g_threaded) {
@@ -171,30 +172,29 @@
        unless their 'next' is earlier than the current timed-waiter's deadline
        (in which case the thread with earlier 'next' takes over as the new timed
        waiter) */
-    if (gpr_time_cmp(next, inf_future) != 0) {
-      if (!g_has_timed_waiter ||
-          (gpr_time_cmp(next, g_timed_waiter_deadline) < 0)) {
+    if (next != GRPC_MILLIS_INF_FUTURE) {
+      if (!g_has_timed_waiter || (next < g_timed_waiter_deadline)) {
         my_timed_waiter_generation = ++g_timed_waiter_generation;
         g_has_timed_waiter = true;
         g_timed_waiter_deadline = next;
 
         if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
-          gpr_timespec wait_time =
-              gpr_time_sub(next, gpr_now(GPR_CLOCK_MONOTONIC));
-          gpr_log(GPR_DEBUG, "sleep for a %" PRId64 ".%09d seconds",
-                  wait_time.tv_sec, wait_time.tv_nsec);
+          grpc_millis wait_time = next - grpc_exec_ctx_now(exec_ctx);
+          gpr_log(GPR_DEBUG, "sleep for a %" PRIdPTR " milliseconds",
+                  wait_time);
         }
       } else {  // g_timed_waiter == true && next >= g_timed_waiter_deadline
-        next = inf_future;
+        next = GRPC_MILLIS_INF_FUTURE;
       }
     }
 
     if (GRPC_TRACER_ON(grpc_timer_check_trace) &&
-        gpr_time_cmp(next, inf_future) == 0) {
+        next == GRPC_MILLIS_INF_FUTURE) {
       gpr_log(GPR_DEBUG, "sleep until kicked");
     }
 
-    gpr_cv_wait(&g_cv_wait, &g_mu, next);
+    gpr_cv_wait(&g_cv_wait, &g_mu,
+                grpc_millis_to_timespec(next, GPR_CLOCK_REALTIME));
 
     if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
       gpr_log(GPR_DEBUG, "wait ended: was_timed:%d kicked:%d",
@@ -206,7 +206,7 @@
     // there's work to do after checking timers (code above)
     if (my_timed_waiter_generation == g_timed_waiter_generation) {
       g_has_timed_waiter = false;
-      g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+      g_timed_waiter_deadline = GRPC_MILLIS_INF_FUTURE;
     }
   }
 
@@ -222,12 +222,11 @@
 }
 
 static void timer_main_loop(grpc_exec_ctx *exec_ctx) {
-  const gpr_timespec inf_future = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   for (;;) {
-    gpr_timespec next = inf_future;
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+    grpc_millis next = GRPC_MILLIS_INF_FUTURE;
+    grpc_exec_ctx_invalidate_now(exec_ctx);
     // check timer state, updates next to the next time to run a check
-    switch (grpc_timer_check(exec_ctx, now, &next)) {
+    switch (grpc_timer_check(exec_ctx, &next)) {
       case GRPC_TIMERS_FIRED:
         run_some_timers(exec_ctx);
         break;
@@ -244,10 +243,10 @@
         if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
           gpr_log(GPR_DEBUG, "timers not checked: expect another thread to");
         }
-        next = inf_future;
+        next = GRPC_MILLIS_INF_FUTURE;
       /* fall through */
       case GRPC_TIMERS_CHECKED_AND_EMPTY:
-        if (!wait_until(next)) {
+        if (!wait_until(exec_ctx, next)) {
           return;
         }
         break;
@@ -303,7 +302,7 @@
   g_completed_threads = NULL;
 
   g_has_timed_waiter = false;
-  g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  g_timed_waiter_deadline = GRPC_MILLIS_INF_FUTURE;
 
   start_threads();
 }
@@ -350,7 +349,7 @@
   gpr_mu_lock(&g_mu);
   g_kicked = true;
   g_has_timed_waiter = false;
-  g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  g_timed_waiter_deadline = GRPC_MILLIS_INF_FUTURE;
   ++g_timed_waiter_generation;
   gpr_cv_signal(&g_cv_wait);
   gpr_mu_unlock(&g_mu);
diff --git a/src/core/lib/iomgr/timer_uv.cc b/src/core/lib/iomgr/timer_uv.cc
index 53f79b5..ccbbe35 100644
--- a/src/core/lib/iomgr/timer_uv.cc
+++ b/src/core/lib/iomgr/timer_uv.cc
@@ -55,19 +55,18 @@
 }
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_closure *closure,
-                     gpr_timespec now) {
+                     grpc_millis deadline, grpc_closure *closure) {
   uint64_t timeout;
   uv_timer_t *uv_timer;
   GRPC_UV_ASSERT_SAME_THREAD();
   timer->closure = closure;
-  if (gpr_time_cmp(deadline, now) <= 0) {
+  if (deadline <= grpc_exec_ctx_now(exec_ctx)) {
     timer->pending = 0;
     GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     return;
   }
   timer->pending = 1;
-  timeout = (uint64_t)gpr_time_to_millis(gpr_time_sub(deadline, now));
+  timeout = (uint64_t)(deadline - grpc_exec_ctx_now(exec_ctx));
   uv_timer = (uv_timer_t *)gpr_malloc(sizeof(uv_timer_t));
   uv_timer_init(uv_default_loop(), uv_timer);
   uv_timer->data = timer;
@@ -91,11 +90,11 @@
 }
 
 grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx,
-                                         gpr_timespec now, gpr_timespec *next) {
+                                         grpc_millis *next) {
   return GRPC_TIMERS_NOT_CHECKED;
 }
 
-void grpc_timer_list_init(gpr_timespec now) {}
+void grpc_timer_list_init(grpc_exec_ctx *exec_ctx) {}
 void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {}
 
 void grpc_timer_consume_kick(void) {}
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
index 8fe5802..5b2ddce 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
@@ -97,7 +97,7 @@
 
   /* The http call is local. If it takes more than one sec, it is for sure not
      on compute engine. */
-  gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN);
+  grpc_millis max_detection_delay = GPR_MS_PER_SEC;
 
   grpc_pollset *pollset = (grpc_pollset *)gpr_zalloc(grpc_pollset_size());
   grpc_pollset_init(pollset, &g_polling_mu);
@@ -116,7 +116,7 @@
       grpc_resource_quota_create("google_default_credentials");
   grpc_httpcli_get(
       exec_ctx, &context, &detector.pollent, resource_quota, &request,
-      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
+      grpc_exec_ctx_now(exec_ctx) + max_detection_delay,
       GRPC_CLOSURE_CREATE(on_compute_engine_detection_http_response, &detector,
                           grpc_schedule_on_exec_ctx),
       &detector.response);
@@ -133,8 +133,7 @@
             "pollset_work",
             grpc_pollset_work(exec_ctx,
                               grpc_polling_entity_pollset(&detector.pollent),
-                              &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                              gpr_inf_future(GPR_CLOCK_MONOTONIC)))) {
+                              &worker, GRPC_MILLIS_INF_FUTURE))) {
       detector.is_done = 1;
       detector.success = 0;
     }
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc
index aea16de..39e72c1 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc
@@ -384,7 +384,7 @@
 gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN};
 
 /* Max delay defaults to one minute. */
-gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN};
+grpc_millis grpc_jwt_verifier_max_delay = 60 * GPR_MS_PER_SEC;
 
 typedef struct {
   char *email_domain;
@@ -711,7 +711,7 @@
   resource_quota = grpc_resource_quota_create("jwt_verifier");
   grpc_httpcli_get(
       exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
-      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
+      grpc_exec_ctx_now(exec_ctx) + grpc_jwt_verifier_max_delay,
       GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx),
       &ctx->responses[HTTP_RESPONSE_KEYS]);
   grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
@@ -838,10 +838,10 @@
      channel. This would allow us to cancel an authentication query when under
      extreme memory pressure. */
   resource_quota = grpc_resource_quota_create("jwt_verifier");
-  grpc_httpcli_get(
-      exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
-      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
-      http_cb, &ctx->responses[rsp_idx]);
+  grpc_httpcli_get(exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent,
+                   resource_quota, &req,
+                   grpc_exec_ctx_now(exec_ctx) + grpc_jwt_verifier_max_delay,
+                   http_cb, &ctx->responses[rsp_idx]);
   grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   gpr_free(req.host);
   gpr_free(req.http.path);
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h
index 0603811..998365e 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -85,7 +85,7 @@
 
 /* Globals to control the verifier. Not thread-safe. */
 extern gpr_timespec grpc_jwt_verifier_clock_skew;
-extern gpr_timespec grpc_jwt_verifier_max_delay;
+extern grpc_millis grpc_jwt_verifier_max_delay;
 
 /* The verifier can be created with some custom mappings to help with key
    discovery in the case where the issuer is an email address.
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
index 0a801be..f52a424 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
@@ -117,7 +117,7 @@
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
     grpc_exec_ctx *exec_ctx, const grpc_http_response *response,
-    grpc_mdelem *token_md, gpr_timespec *token_lifetime) {
+    grpc_mdelem *token_md, grpc_millis *token_lifetime) {
   char *null_terminated_body = NULL;
   char *new_access_token = NULL;
   grpc_credentials_status status = GRPC_CREDENTIALS_OK;
@@ -183,9 +183,7 @@
     }
     gpr_asprintf(&new_access_token, "%s %s", token_type->value,
                  access_token->value);
-    token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
-    token_lifetime->tv_nsec = 0;
-    token_lifetime->clock_type = GPR_TIMESPAN;
+    *token_lifetime = strtol(expires_in->value, NULL, 10) * GPR_MS_PER_SEC;
     if (!GRPC_MDISNULL(*token_md)) GRPC_MDELEM_UNREF(exec_ctx, *token_md);
     *token_md = grpc_mdelem_from_slices(
         exec_ctx,
@@ -214,7 +212,7 @@
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)r->creds;
   grpc_mdelem access_token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_credentials_status status =
       grpc_oauth2_token_fetcher_credentials_parse_server_response(
           exec_ctx, &r->response, &access_token_md, &token_lifetime);
@@ -222,10 +220,9 @@
   gpr_mu_lock(&c->mu);
   c->token_fetch_pending = false;
   c->access_token_md = GRPC_MDELEM_REF(access_token_md);
-  c->token_expiration =
-      status == GRPC_CREDENTIALS_OK
-          ? gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime)
-          : gpr_inf_past(GPR_CLOCK_REALTIME);
+  c->token_expiration = status == GRPC_CREDENTIALS_OK
+                            ? grpc_exec_ctx_now(exec_ctx) + token_lifetime
+                            : 0;
   grpc_oauth2_pending_get_request_metadata *pending_request =
       c->pending_requests;
   c->pending_requests = NULL;
@@ -260,14 +257,12 @@
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
   // Check if we can use the cached token.
-  gpr_timespec refresh_threshold = gpr_time_from_seconds(
-      GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
+  grpc_millis refresh_threshold =
+      GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC;
   grpc_mdelem cached_access_token_md = GRPC_MDNULL;
   gpr_mu_lock(&c->mu);
   if (!GRPC_MDISNULL(c->access_token_md) &&
-      (gpr_time_cmp(
-           gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)),
-           refresh_threshold) > 0)) {
+      (c->token_expiration + grpc_exec_ctx_now(exec_ctx) > refresh_threshold)) {
     cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md);
   }
   if (!GRPC_MDISNULL(cached_access_token_md)) {
@@ -296,10 +291,10 @@
   gpr_mu_unlock(&c->mu);
   if (start_fetch) {
     grpc_call_credentials_ref(creds);
-    c->fetch_func(
-        exec_ctx, grpc_credentials_metadata_request_create(creds),
-        &c->httpcli_context, &c->pollent, on_oauth2_token_fetcher_http_response,
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), refresh_threshold));
+    c->fetch_func(exec_ctx, grpc_credentials_metadata_request_create(creds),
+                  &c->httpcli_context, &c->pollent,
+                  on_oauth2_token_fetcher_http_response,
+                  grpc_exec_ctx_now(exec_ctx) + refresh_threshold);
   }
   return false;
 }
@@ -340,7 +335,7 @@
   c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
   gpr_ref_init(&c->base.refcount, 1);
   gpr_mu_init(&c->mu);
-  c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
+  c->token_expiration = 0;
   c->fetch_func = fetch_func;
   c->pollent =
       grpc_polling_entity_create_from_pollset_set(grpc_pollset_set_create());
@@ -358,7 +353,7 @@
 static void compute_engine_fetch_oauth2(
     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
     grpc_httpcli_context *httpcli_context, grpc_polling_entity *pollent,
-    grpc_iomgr_cb_func response_cb, gpr_timespec deadline) {
+    grpc_iomgr_cb_func response_cb, grpc_millis deadline) {
   grpc_http_header header = {(char *)"Metadata-Flavor", (char *)"Google"};
   grpc_httpcli_request request;
   memset(&request, 0, sizeof(grpc_httpcli_request));
@@ -410,7 +405,7 @@
 static void refresh_token_fetch_oauth2(
     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
     grpc_httpcli_context *httpcli_context, grpc_polling_entity *pollent,
-    grpc_iomgr_cb_func response_cb, gpr_timespec deadline) {
+    grpc_iomgr_cb_func response_cb, grpc_millis deadline) {
   grpc_google_refresh_token_credentials *c =
       (grpc_google_refresh_token_credentials *)metadata_req->creds;
   grpc_http_header header = {(char *)"Content-Type",
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index c8a9333..4beaec9 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -61,7 +61,7 @@
                                        grpc_httpcli_context *http_context,
                                        grpc_polling_entity *pollent,
                                        grpc_iomgr_cb_func cb,
-                                       gpr_timespec deadline);
+                                       grpc_millis deadline);
 
 typedef struct grpc_oauth2_pending_get_request_metadata {
   grpc_credentials_mdelem_array *md_array;
@@ -74,7 +74,7 @@
   grpc_call_credentials base;
   gpr_mu mu;
   grpc_mdelem access_token_md;
-  gpr_timespec token_expiration;
+  grpc_millis token_expiration;
   bool token_fetch_pending;
   grpc_oauth2_pending_get_request_metadata *pending_requests;
   grpc_httpcli_context httpcli_context;
@@ -104,7 +104,7 @@
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
     grpc_exec_ctx *exec_ctx, const struct grpc_http_response *response,
-    grpc_mdelem *token_md, gpr_timespec *token_lifetime);
+    grpc_mdelem *token_md, grpc_millis *token_lifetime);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/lib/support/block_annotate.h b/src/core/lib/support/block_annotate.h
deleted file mode 100644
index 8e3ef7d..0000000
--- a/src/core/lib/support/block_annotate.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
-#define GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void gpr_thd_start_blocking_region();
-void gpr_thd_end_blocking_region();
-
-#ifdef __cplusplus
-}
-#endif
-
-/* These annotations identify the beginning and end of regions where
-   the code may block for reasons other than synchronization functions.
-   These include poll, epoll, and getaddrinfo. */
-
-#ifdef GRPC_SCHEDULING_MARK_BLOCKING_REGION
-#define GRPC_SCHEDULING_START_BLOCKING_REGION \
-  do {                                        \
-    gpr_thd_start_blocking_region();          \
-  } while (0)
-#define GRPC_SCHEDULING_END_BLOCKING_REGION \
-  do {                                      \
-    gpr_thd_end_blocking_region();          \
-  } while (0)
-#else
-#define GRPC_SCHEDULING_START_BLOCKING_REGION \
-  do {                                        \
-  } while (0)
-#define GRPC_SCHEDULING_END_BLOCKING_REGION \
-  do {                                      \
-  } while (0)
-#endif
-
-#endif /* GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H */
diff --git a/src/core/lib/support/log_android.cc b/src/core/lib/support/log_android.cc
index 6f1cec5..9e8529c 100644
--- a/src/core/lib/support/log_android.cc
+++ b/src/core/lib/support/log_android.cc
@@ -39,8 +39,8 @@
   return ANDROID_LOG_DEFAULT;
 }
 
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...) {
+extern "C" void gpr_log(const char *file, int line, gpr_log_severity severity,
+                        const char *format, ...) {
   char *message = NULL;
   va_list args;
   va_start(args, format);
@@ -50,8 +50,8 @@
   free(message);
 }
 
-void gpr_default_log(gpr_log_func_args *args) {
-  char *final_slash;
+extern "C" void gpr_default_log(gpr_log_func_args *args) {
+  const char *final_slash;
   const char *display_file;
   char *output = NULL;
 
diff --git a/src/core/lib/support/time_posix.cc b/src/core/lib/support/time_posix.cc
index deccb50..3267ea6 100644
--- a/src/core/lib/support/time_posix.cc
+++ b/src/core/lib/support/time_posix.cc
@@ -30,7 +30,6 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include "src/core/lib/support/block_annotate.h"
 
 static struct timespec timespec_from_gpr(gpr_timespec gts) {
   struct timespec rv;
@@ -159,9 +158,7 @@
 
     delta = gpr_time_sub(until, now);
     delta_ts = timespec_from_gpr(delta);
-    GRPC_SCHEDULING_START_BLOCKING_REGION;
     ns_result = nanosleep(&delta_ts, NULL);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
     if (ns_result == 0) {
       break;
     }
diff --git a/src/core/lib/support/time_windows.cc b/src/core/lib/support/time_windows.cc
index dda7566..08c1b22 100644
--- a/src/core/lib/support/time_windows.cc
+++ b/src/core/lib/support/time_windows.cc
@@ -28,7 +28,6 @@
 #include <process.h>
 #include <sys/timeb.h>
 
-#include "src/core/lib/support/block_annotate.h"
 #include "src/core/lib/support/time_precise.h"
 
 static LARGE_INTEGER g_start_time;
@@ -94,9 +93,7 @@
     sleep_millis =
         delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
     GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX));
-    GRPC_SCHEDULING_START_BLOCKING_REGION;
     Sleep((DWORD)sleep_millis);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
   }
 }
 
diff --git a/src/core/lib/surface/alarm.cc b/src/core/lib/surface/alarm.cc
index 4e67543..16a16bf 100644
--- a/src/core/lib/surface/alarm.cc
+++ b/src/core/lib/surface/alarm.cc
@@ -126,8 +126,7 @@
 
   GPR_ASSERT(grpc_cq_begin_op(cq, tag));
   grpc_timer_init(&exec_ctx, &alarm->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+                  grpc_timespec_to_millis_round_up(deadline), &alarm->on_alarm);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 6c97f5c..8216aa0 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -216,7 +216,7 @@
      server, it's trailing metadata */
   grpc_linked_mdelem send_extra_metadata[MAX_SEND_EXTRA_METADATA_COUNT];
   int send_extra_metadata_count;
-  gpr_timespec send_deadline;
+  grpc_millis send_deadline;
 
   grpc_slice_buffer_stream sending_stream;
 
@@ -283,7 +283,7 @@
                          grpc_error *error);
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
                                   grpc_error *error);
-static void get_final_status(grpc_call *call,
+static void get_final_status(grpc_exec_ctx *exec_ctx, grpc_call *call,
                              void (*set_value)(grpc_status_code code,
                                                void *user_data),
                              void *set_value_user_data, grpc_slice *details);
@@ -372,11 +372,10 @@
   }
   for (i = 0; i < 2; i++) {
     for (j = 0; j < 2; j++) {
-      call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+      call->metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE;
     }
   }
-  gpr_timespec send_deadline =
-      gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
+  grpc_millis send_deadline = args->send_deadline;
 
   bool immediately_cancel = false;
 
@@ -394,10 +393,7 @@
     gpr_mu_lock(&pc->child_list_mu);
 
     if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
-      send_deadline = gpr_time_min(
-          gpr_convert_clock_type(send_deadline,
-                                 args->parent->send_deadline.clock_type),
-          args->parent->send_deadline);
+      send_deadline = GPR_MIN(send_deadline, args->parent->send_deadline);
     }
     /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
      * GRPC_PROPAGATE_STATS_CONTEXT */
@@ -551,8 +547,8 @@
     GRPC_CQ_INTERNAL_UNREF(exec_ctx, c->cq, "bind");
   }
 
-  get_final_status(c, set_status_value_directly, &c->final_info.final_status,
-                   NULL);
+  get_final_status(exec_ctx, c, set_status_value_directly,
+                   &c->final_info.final_status, NULL);
   c->final_info.stats.latency =
       gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
 
@@ -738,13 +734,16 @@
  * FINAL STATUS CODE MANIPULATION
  */
 
-static bool get_final_status_from(
-    grpc_call *call, grpc_error *error, bool allow_ok_status,
-    void (*set_value)(grpc_status_code code, void *user_data),
-    void *set_value_user_data, grpc_slice *details) {
+static bool get_final_status_from(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                                  grpc_error *error, bool allow_ok_status,
+                                  void (*set_value)(grpc_status_code code,
+                                                    void *user_data),
+                                  void *set_value_user_data,
+                                  grpc_slice *details) {
   grpc_status_code code;
   grpc_slice slice = grpc_empty_slice();
-  grpc_error_get_status(error, call->send_deadline, &code, &slice, NULL);
+  grpc_error_get_status(exec_ctx, error, call->send_deadline, &code, &slice,
+                        NULL);
   if (code == GRPC_STATUS_OK && !allow_ok_status) {
     return false;
   }
@@ -756,7 +755,7 @@
   return true;
 }
 
-static void get_final_status(grpc_call *call,
+static void get_final_status(grpc_exec_ctx *exec_ctx, grpc_call *call,
                              void (*set_value)(grpc_status_code code,
                                                void *user_data),
                              void *set_value_user_data, grpc_slice *details) {
@@ -781,8 +780,9 @@
     for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
       if (status[i].is_set &&
           grpc_error_has_clear_grpc_status(status[i].error)) {
-        if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
-                                  set_value, set_value_user_data, details)) {
+        if (get_final_status_from(exec_ctx, call, status[i].error,
+                                  allow_ok_status != 0, set_value,
+                                  set_value_user_data, details)) {
           return;
         }
       }
@@ -790,8 +790,9 @@
     /* If no clearly defined status exists, search for 'anything' */
     for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
       if (status[i].is_set) {
-        if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
-                                  set_value, set_value_user_data, details)) {
+        if (get_final_status_from(exec_ctx, call, status[i].error,
+                                  allow_ok_status != 0, set_value,
+                                  set_value_user_data, details)) {
           return;
         }
       }
@@ -1330,17 +1331,22 @@
     }
 
     if (call->is_client) {
-      get_final_status(call, set_status_value_directly,
+      get_final_status(exec_ctx, call, set_status_value_directly,
                        call->final_op.client.status,
                        call->final_op.client.status_details);
     } else {
-      get_final_status(call, set_cancelled_value,
+      get_final_status(exec_ctx, call, set_cancelled_value,
                        call->final_op.server.cancelled, NULL);
     }
 
     GRPC_ERROR_UNREF(error);
     error = GRPC_ERROR_NONE;
   }
+  if (error != GRPC_ERROR_NONE && bctl->op.recv_message &&
+      *call->receiving_buffer != NULL) {
+    grpc_byte_buffer_destroy(*call->receiving_buffer);
+    *call->receiving_buffer = NULL;
+  }
 
   if (bctl->completion_data.notify_tag.is_closure) {
     /* unrefs bctl->error */
@@ -1611,11 +1617,8 @@
     validate_filtered_metadata(exec_ctx, bctl);
     GPR_TIMER_END("validate_filtered_metadata", 0);
 
-    if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
-            0 &&
-        !call->is_client) {
-      call->send_deadline =
-          gpr_convert_clock_type(md->deadline, GPR_CLOCK_MONOTONIC);
+    if (md->deadline != GRPC_MILLIS_INF_FUTURE && !call->is_client) {
+      call->send_deadline = md->deadline;
     }
   }
 
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index c680139..27c2f52 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -49,7 +49,7 @@
   grpc_mdelem *add_initial_metadata;
   size_t add_initial_metadata_count;
 
-  gpr_timespec send_deadline;
+  grpc_millis send_deadline;
 } grpc_call_create_args;
 
 /* Create a new call based on \a args.
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index 59fced7..860dcc8 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -262,7 +262,7 @@
     grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
     uint32_t propagation_mask, grpc_completion_queue *cq,
     grpc_pollset_set *pollset_set_alternative, grpc_mdelem path_mdelem,
-    grpc_mdelem authority_mdelem, gpr_timespec deadline) {
+    grpc_mdelem authority_mdelem, grpc_millis deadline) {
   grpc_mdelem send_metadata[2];
   size_t num_metadata = 0;
 
@@ -308,7 +308,7 @@
       host != NULL ? grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_AUTHORITY,
                                              grpc_slice_ref_internal(*host))
                    : GRPC_MDNULL,
-      deadline);
+      grpc_timespec_to_millis_round_up(deadline));
   grpc_exec_ctx_finish(&exec_ctx);
   return call;
 }
@@ -316,7 +316,7 @@
 grpc_call *grpc_channel_create_pollset_set_call(
     grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
     uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
-    const grpc_slice *host, gpr_timespec deadline, void *reserved) {
+    const grpc_slice *host, grpc_millis deadline, void *reserved) {
   GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
       exec_ctx, channel, parent_call, propagation_mask, NULL, pollset_set,
@@ -372,7 +372,8 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_call *call = grpc_channel_create_call_internal(
       &exec_ctx, channel, parent_call, propagation_mask, completion_queue, NULL,
-      GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority), deadline);
+      GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority),
+      grpc_timespec_to_millis_round_up(deadline));
   grpc_exec_ctx_finish(&exec_ctx);
   return call;
 }
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 427422b..4d1c7e3 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -47,7 +47,7 @@
 grpc_call *grpc_channel_create_pollset_set_call(
     grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
     uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
-    const grpc_slice *host, gpr_timespec deadline, void *reserved);
+    const grpc_slice *host, grpc_millis deadline, void *reserved);
 
 /** Get a (borrowed) pointer to this channels underlying channel stack */
 grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index 453646b..36b4b83 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -61,8 +61,7 @@
   grpc_error *(*kick)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                       grpc_pollset_worker *specific_worker);
   grpc_error *(*work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                      grpc_pollset_worker **worker, gpr_timespec now,
-                      gpr_timespec deadline);
+                      grpc_pollset_worker **worker, grpc_millis deadline);
   void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                    grpc_closure *closure);
   void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset);
@@ -100,8 +99,7 @@
 static grpc_error *non_polling_poller_work(grpc_exec_ctx *exec_ctx,
                                            grpc_pollset *pollset,
                                            grpc_pollset_worker **worker,
-                                           gpr_timespec now,
-                                           gpr_timespec deadline) {
+                                           grpc_millis deadline) {
   non_polling_poller *npp = (non_polling_poller *)pollset;
   if (npp->shutdown) return GRPC_ERROR_NONE;
   non_polling_worker w;
@@ -115,7 +113,10 @@
     w.next->prev = w.prev->next = &w;
   }
   w.kicked = false;
-  while (!npp->shutdown && !w.kicked && !gpr_cv_wait(&w.cv, &npp->mu, deadline))
+  gpr_timespec deadline_ts =
+      grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME);
+  while (!npp->shutdown && !w.kicked &&
+         !gpr_cv_wait(&w.cv, &npp->mu, deadline_ts))
     ;
   if (&w == npp->root) {
     npp->root = w.next;
@@ -743,7 +744,7 @@
 typedef struct {
   gpr_atm last_seen_things_queued_ever;
   grpc_completion_queue *cq;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   grpc_cq_completion *stolen_completion;
   void *tag; /* for pluck */
   bool first_loop;
@@ -772,8 +773,7 @@
       return true;
     }
   }
-  return !a->first_loop &&
-         gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
+  return !a->first_loop && a->deadline < grpc_exec_ctx_now(exec_ctx);
 }
 
 #ifndef NDEBUG
@@ -802,7 +802,6 @@
 static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
                           void *reserved) {
   grpc_event ret;
-  gpr_timespec now;
   cq_next_data *cqd = (cq_next_data *)DATA_FROM_CQ(cq);
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@@ -819,23 +818,20 @@
 
   dump_pending_tags(cq);
 
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-
   GRPC_CQ_INTERNAL_REF(cq, "next");
 
+  grpc_millis deadline_millis = grpc_timespec_to_millis_round_up(deadline);
   cq_is_finished_arg is_finished_arg = {
-
       gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       cq,
-      deadline,
+      deadline_millis,
       NULL,
       NULL,
       true};
   grpc_exec_ctx exec_ctx =
       GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg);
-
   for (;;) {
-    gpr_timespec iteration_deadline = deadline;
+    grpc_millis iteration_deadline = deadline_millis;
 
     if (is_finished_arg.stolen_completion != NULL) {
       grpc_cq_completion *c = is_finished_arg.stolen_completion;
@@ -862,7 +858,7 @@
          attempt at popping. Not doing this can potentially deadlock this
          thread forever (if the deadline is infinity) */
       if (cq_event_queue_num_items(&cqd->queue) > 0) {
-        iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
+        iteration_deadline = 0;
       }
     }
 
@@ -883,8 +879,8 @@
       break;
     }
 
-    now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
+    if (!is_finished_arg.first_loop &&
+        grpc_exec_ctx_now(&exec_ctx) >= deadline_millis) {
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
       dump_pending_tags(cq);
@@ -895,7 +891,7 @@
     gpr_mu_lock(cq->mu);
     cq->num_polls++;
     grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq),
-                                              NULL, now, iteration_deadline);
+                                              NULL, iteration_deadline);
     gpr_mu_unlock(cq->mu);
 
     if (err != GRPC_ERROR_NONE) {
@@ -1032,8 +1028,7 @@
     }
     gpr_mu_unlock(cq->mu);
   }
-  return !a->first_loop &&
-         gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
+  return !a->first_loop && a->deadline < grpc_exec_ctx_now(exec_ctx);
 }
 
 static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
@@ -1042,7 +1037,6 @@
   grpc_cq_completion *c;
   grpc_cq_completion *prev;
   grpc_pollset_worker *worker = NULL;
-  gpr_timespec now;
   cq_pluck_data *cqd = (cq_pluck_data *)DATA_FROM_CQ(cq);
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
@@ -1061,14 +1055,13 @@
 
   dump_pending_tags(cq);
 
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-
   GRPC_CQ_INTERNAL_REF(cq, "pluck");
   gpr_mu_lock(cq->mu);
+  grpc_millis deadline_millis = grpc_timespec_to_millis_round_up(deadline);
   cq_is_finished_arg is_finished_arg = {
       gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       cq,
-      deadline,
+      deadline_millis,
       NULL,
       tag,
       true};
@@ -1120,8 +1113,8 @@
       dump_pending_tags(cq);
       break;
     }
-    now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
+    if (!is_finished_arg.first_loop &&
+        grpc_exec_ctx_now(&exec_ctx) >= deadline_millis) {
       del_plucker(cq, tag, &worker);
       gpr_mu_unlock(cq->mu);
       memset(&ret, 0, sizeof(ret));
@@ -1129,10 +1122,9 @@
       dump_pending_tags(cq);
       break;
     }
-
     cq->num_polls++;
     grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq),
-                                              &worker, now, deadline);
+                                              &worker, deadline_millis);
     if (err != GRPC_ERROR_NONE) {
       del_plucker(cq, tag, &worker);
       gpr_mu_unlock(cq->mu);
diff --git a/src/core/lib/surface/lame_client.cc b/src/core/lib/surface/lame_client.cc
index 6286f91..88e26cb 100644
--- a/src/core/lib/surface/lame_client.cc
+++ b/src/core/lib/surface/lame_client.cc
@@ -74,7 +74,7 @@
   mdb->list.head = &calld->status;
   mdb->list.tail = &calld->details;
   mdb->list.count = 2;
-  mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  mdb->deadline = GRPC_MILLIS_INF_FUTURE;
 }
 
 static void lame_start_transport_stream_op_batch(
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index 1d0fd47..dd09cb9 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -137,7 +137,7 @@
   bool host_set;
   grpc_slice path;
   grpc_slice host;
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   grpc_completion_queue *cq_new;
 
@@ -492,11 +492,13 @@
       GPR_ASSERT(calld->path_set);
       rc->data.batch.details->host = grpc_slice_ref_internal(calld->host);
       rc->data.batch.details->method = grpc_slice_ref_internal(calld->path);
-      rc->data.batch.details->deadline = calld->deadline;
+      rc->data.batch.details->deadline =
+          grpc_millis_to_timespec(calld->deadline, GPR_CLOCK_MONOTONIC);
       rc->data.batch.details->flags = calld->recv_initial_metadata_flags;
       break;
     case REGISTERED_CALL:
-      *rc->data.registered.deadline = calld->deadline;
+      *rc->data.registered.deadline =
+          grpc_millis_to_timespec(calld->deadline, GPR_CLOCK_MONOTONIC);
       if (rc->data.registered.optional_payload) {
         *rc->data.registered.optional_payload = calld->payload;
         calld->payload = NULL;
@@ -739,7 +741,7 @@
                                             grpc_error *error) {
   grpc_call_element *elem = (grpc_call_element *)ptr;
   call_data *calld = (call_data *)elem->call_data;
-  gpr_timespec op_deadline;
+  grpc_millis op_deadline;
 
   if (error == GRPC_ERROR_NONE) {
     GPR_ASSERT(calld->recv_initial_metadata->idx.named.path != NULL);
@@ -759,7 +761,7 @@
     GRPC_ERROR_REF(error);
   }
   op_deadline = calld->recv_initial_metadata->deadline;
-  if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
+  if (op_deadline != GRPC_MILLIS_INF_FUTURE) {
     calld->deadline = op_deadline;
   }
   if (calld->host_set && calld->path_set) {
@@ -833,7 +835,7 @@
   memset(&args, 0, sizeof(args));
   args.channel = chand->channel;
   args.server_transport_data = transport_server_data;
-  args.send_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  args.send_deadline = GRPC_MILLIS_INF_FUTURE;
   grpc_call *call;
   grpc_error *error = grpc_call_create(exec_ctx, &args, &call);
   grpc_call_element *elem =
@@ -881,7 +883,7 @@
   call_data *calld = (call_data *)elem->call_data;
   channel_data *chand = (channel_data *)elem->channel_data;
   memset(calld, 0, sizeof(call_data));
-  calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  calld->deadline = GRPC_MILLIS_INF_FUTURE;
   calld->call = grpc_call_from_top_element(elem);
   gpr_mu_init(&calld->mu_state);
 
diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc
index e7fa0ee..6ed427c 100644
--- a/src/core/lib/transport/bdp_estimator.cc
+++ b/src/core/lib/transport/bdp_estimator.cc
@@ -30,8 +30,12 @@
 void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) {
   estimator->estimate = 65536;
   estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
+  estimator->ping_start_time = gpr_time_0(GPR_CLOCK_MONOTONIC);
+  estimator->next_ping_scheduled = 0;
   estimator->name = name;
   estimator->bw_est = 0;
+  estimator->inter_ping_delay = 100.0;  // start at 100ms
+  estimator->stable_estimate_count = 0;
 }
 
 bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator,
@@ -51,10 +55,11 @@
   estimator->accumulator += num_bytes;
 }
 
-bool grpc_bdp_estimator_need_ping(const grpc_bdp_estimator *estimator) {
+bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
+                                  const grpc_bdp_estimator *estimator) {
   switch (estimator->ping_state) {
     case GRPC_BDP_PING_UNSCHEDULED:
-      return true;
+      return grpc_exec_ctx_now(exec_ctx) >= estimator->next_ping_scheduled;
     case GRPC_BDP_PING_SCHEDULED:
       return false;
     case GRPC_BDP_PING_STARTED:
@@ -84,11 +89,13 @@
   estimator->ping_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
 }
 
-void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator) {
-  gpr_timespec dt_ts =
-      gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), estimator->ping_start_time);
+void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
+                                      grpc_bdp_estimator *estimator) {
+  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+  gpr_timespec dt_ts = gpr_time_sub(now, estimator->ping_start_time);
   double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec;
   double bw = dt > 0 ? ((double)estimator->accumulator / dt) : 0;
+  int start_inter_ping_delay = estimator->inter_ping_delay;
   if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
     gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64
                        " dt=%lf bw=%lfMbs bw_est=%lfMbs",
@@ -105,7 +112,26 @@
       gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64,
               estimator->name, estimator->estimate);
     }
+    estimator->inter_ping_delay /= 2;  // if the ping estimate changes,
+                                       // exponentially get faster at probing
+  } else if (estimator->inter_ping_delay < 10000) {
+    estimator->stable_estimate_count++;
+    if (estimator->stable_estimate_count >= 2) {
+      estimator->inter_ping_delay +=
+          100 +
+          (int)(rand() * 100.0 / RAND_MAX);  // if the ping estimate is steady,
+                                             // slowly ramp down the probe time
+    }
+  }
+  if (start_inter_ping_delay != estimator->inter_ping_delay) {
+    estimator->stable_estimate_count = 0;
+    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+      gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", estimator->name,
+              estimator->inter_ping_delay);
+    }
   }
   estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
   estimator->accumulator = 0;
+  estimator->next_ping_scheduled =
+      grpc_exec_ctx_now(exec_ctx) + estimator->inter_ping_delay;
 }
diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h
index 21c27ec..480d523 100644
--- a/src/core/lib/transport/bdp_estimator.h
+++ b/src/core/lib/transport/bdp_estimator.h
@@ -23,6 +23,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 
 #define GRPC_BDP_SAMPLES 16
 #define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3
@@ -43,7 +44,12 @@
   grpc_bdp_estimator_ping_state ping_state;
   int64_t accumulator;
   int64_t estimate;
+  // when was the current ping started?
   gpr_timespec ping_start_time;
+  // when should the next ping start?
+  grpc_millis next_ping_scheduled;
+  int inter_ping_delay;
+  int stable_estimate_count;
   double bw_est;
   const char *name;
 } grpc_bdp_estimator;
@@ -59,7 +65,8 @@
 void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
                                            int64_t num_bytes);
 // Returns true if the user should schedule a ping
-bool grpc_bdp_estimator_need_ping(const grpc_bdp_estimator *estimator);
+bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
+                                  const grpc_bdp_estimator *estimator);
 // Schedule a ping: call in response to receiving a true from
 // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
 // transport (but not necessarily started)
@@ -68,7 +75,8 @@
 // the ping is on the wire
 void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator);
 // Completes a previously started ping
-void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator);
+void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
+                                      grpc_bdp_estimator *estimator);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc
index 5e3920b..2e3b61b 100644
--- a/src/core/lib/transport/error_utils.cc
+++ b/src/core/lib/transport/error_utils.cc
@@ -39,8 +39,9 @@
   return NULL;
 }
 
-void grpc_error_get_status(grpc_error *error, gpr_timespec deadline,
-                           grpc_status_code *code, grpc_slice *slice,
+void grpc_error_get_status(grpc_exec_ctx *exec_ctx, grpc_error *error,
+                           grpc_millis deadline, grpc_status_code *code,
+                           grpc_slice *slice,
                            grpc_http2_error_code *http_error) {
   // Start with the parent error and recurse through the tree of children
   // until we find the first one that has a status code.
@@ -63,8 +64,8 @@
     status = (grpc_status_code)integer;
   } else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR,
                                 &integer)) {
-    status = grpc_http2_error_to_grpc_status((grpc_http2_error_code)integer,
-                                             deadline);
+    status = grpc_http2_error_to_grpc_status(
+        exec_ctx, (grpc_http2_error_code)integer, deadline);
   }
   if (code != NULL) *code = status;
 
diff --git a/src/core/lib/transport/error_utils.h b/src/core/lib/transport/error_utils.h
index 18ff548..2c97f9f 100644
--- a/src/core/lib/transport/error_utils.h
+++ b/src/core/lib/transport/error_utils.h
@@ -20,6 +20,7 @@
 #define GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H
 
 #include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
 
 #ifdef __cplusplus
@@ -32,8 +33,9 @@
 /// All attributes are pulled from the same child error. If any of the
 /// attributes (code, msg, http_status) are unneeded, they can be passed as
 /// NULL.
-void grpc_error_get_status(grpc_error *error, gpr_timespec deadline,
-                           grpc_status_code *code, grpc_slice *slice,
+void grpc_error_get_status(grpc_exec_ctx *exec_ctx, grpc_error *error,
+                           grpc_millis deadline, grpc_status_code *code,
+                           grpc_slice *slice,
                            grpc_http2_error_code *http_status);
 
 /// A utility function to check whether there is a clear status code that
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index 54388bd..2df9c91 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -74,7 +74,7 @@
 
 void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
   memset(batch, 0, sizeof(*batch));
-  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  batch->deadline = GRPC_MILLIS_INF_FUTURE;
 }
 
 void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx,
@@ -270,9 +270,7 @@
 }
 
 bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
-  return batch->list.head == NULL &&
-         gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type),
-                      batch->deadline) == 0;
+  return batch->list.head == NULL && batch->deadline == GRPC_MILLIS_INF_FUTURE;
 }
 
 size_t grpc_metadata_batch_size(grpc_metadata_batch *batch) {
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 63f30a7..a2b4b92 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -51,9 +51,9 @@
   grpc_mdelem_list list;
   grpc_metadata_batch_callouts idx;
   /** Used to calculate grpc-timeout at the point of sending,
-      or gpr_inf_future if this batch does not need to send a
+      or GRPC_MILLIS_INF_FUTURE if this batch does not need to send a
       grpc-timeout */
-  gpr_timespec deadline;
+  grpc_millis deadline;
 } grpc_metadata_batch;
 
 void grpc_metadata_batch_init(grpc_metadata_batch *batch);
diff --git a/src/core/lib/transport/status_conversion.cc b/src/core/lib/transport/status_conversion.cc
index a40d333..891c442 100644
--- a/src/core/lib/transport/status_conversion.cc
+++ b/src/core/lib/transport/status_conversion.cc
@@ -37,8 +37,9 @@
   }
 }
 
-grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
-                                                 gpr_timespec deadline) {
+grpc_status_code grpc_http2_error_to_grpc_status(grpc_exec_ctx *exec_ctx,
+                                                 grpc_http2_error_code error,
+                                                 grpc_millis deadline) {
   switch (error) {
     case GRPC_HTTP2_NO_ERROR:
       /* should never be received */
@@ -46,7 +47,7 @@
     case GRPC_HTTP2_CANCEL:
       /* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been
        * exceeded */
-      return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0
+      return grpc_exec_ctx_now(exec_ctx) > deadline
                  ? GRPC_STATUS_DEADLINE_EXCEEDED
                  : GRPC_STATUS_CANCELLED;
     case GRPC_HTTP2_ENHANCE_YOUR_CALM:
diff --git a/src/core/lib/transport/status_conversion.h b/src/core/lib/transport/status_conversion.h
index b257998..fd58a82 100644
--- a/src/core/lib/transport/status_conversion.h
+++ b/src/core/lib/transport/status_conversion.h
@@ -20,6 +20,7 @@
 #define GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H
 
 #include <grpc/grpc.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
 
 #ifdef __cplusplus
@@ -28,8 +29,9 @@
 
 /* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
 grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status);
-grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
-                                                 gpr_timespec deadline);
+grpc_status_code grpc_http2_error_to_grpc_status(grpc_exec_ctx *exec_ctx,
+                                                 grpc_http2_error_code error,
+                                                 grpc_millis deadline);
 
 /* Conversion of HTTP status codes (:status) to grpc status codes */
 grpc_status_code grpc_http2_status_to_grpc_status(int status);
diff --git a/src/core/lib/transport/timeout_encoding.cc b/src/core/lib/transport/timeout_encoding.cc
index 02f179d..23a9ef3 100644
--- a/src/core/lib/transport/timeout_encoding.cc
+++ b/src/core/lib/transport/timeout_encoding.cc
@@ -59,60 +59,27 @@
   }
 }
 
-static void enc_nanos(char *buffer, int64_t x) {
+static void enc_millis(char *buffer, int64_t x) {
   x = round_up_to_three_sig_figs(x);
-  if (x < 100000) {
-    if (x % 1000 == 0) {
-      enc_ext(buffer, x / 1000, 'u');
-    } else {
-      enc_ext(buffer, x, 'n');
-    }
-  } else if (x < 100000000) {
-    if (x % 1000000 == 0) {
-      enc_ext(buffer, x / 1000000, 'm');
-    } else {
-      enc_ext(buffer, x / 1000, 'u');
-    }
-  } else if (x < 1000000000) {
-    enc_ext(buffer, x / 1000000, 'm');
+  if (x < GPR_MS_PER_SEC) {
+    enc_ext(buffer, x, 'm');
   } else {
-    /* note that this is only ever called with times of less than one second,
-       so if we reach here the time must have been rounded up to a whole second
-       (and no more) */
-    memcpy(buffer, "1S", 3);
+    if (x % GPR_MS_PER_SEC == 0) {
+      enc_seconds(buffer, x / GPR_MS_PER_SEC);
+    } else {
+      enc_ext(buffer, x, 'm');
+    }
   }
 }
 
-static void enc_micros(char *buffer, int64_t x) {
-  x = round_up_to_three_sig_figs(x);
-  if (x < 100000) {
-    if (x % 1000 == 0) {
-      enc_ext(buffer, x / 1000, 'm');
-    } else {
-      enc_ext(buffer, x, 'u');
-    }
-  } else if (x < 100000000) {
-    if (x % 1000000 == 0) {
-      enc_ext(buffer, x / 1000000, 'S');
-    } else {
-      enc_ext(buffer, x / 1000, 'm');
-    }
-  } else {
-    enc_ext(buffer, x / 1000000, 'S');
-  }
-}
-
-void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer) {
-  if (timeout.tv_sec < 0) {
+void grpc_http2_encode_timeout(grpc_millis timeout, char *buffer) {
+  if (timeout <= 0) {
     enc_tiny(buffer);
-  } else if (timeout.tv_sec == 0) {
-    enc_nanos(buffer, timeout.tv_nsec);
-  } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
-    enc_micros(buffer,
-               (int64_t)(timeout.tv_sec * 1000000) +
-                   (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
+  } else if (timeout < 1000 * GPR_MS_PER_SEC) {
+    enc_millis(buffer, timeout);
   } else {
-    enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
+    enc_seconds(buffer,
+                timeout / GPR_MS_PER_SEC + (timeout % GPR_MS_PER_SEC != 0));
   }
 }
 
@@ -121,8 +88,8 @@
   return p == end;
 }
 
-int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout) {
-  int32_t x = 0;
+int grpc_http2_decode_timeout(grpc_slice text, grpc_millis *timeout) {
+  grpc_millis x = 0;
   const uint8_t *p = GRPC_SLICE_START_PTR(text);
   const uint8_t *end = GRPC_SLICE_END_PTR(text);
   int have_digit = 0;
@@ -136,7 +103,7 @@
     /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
     if (x >= (100 * 1000 * 1000)) {
       if (x != (100 * 1000 * 1000) || digit != 0) {
-        *timeout = gpr_inf_future(GPR_TIMESPAN);
+        *timeout = GRPC_MILLIS_INF_FUTURE;
         return 1;
       }
     }
@@ -150,22 +117,22 @@
   /* decode unit specifier */
   switch (*p) {
     case 'n':
-      *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
+      *timeout = x / GPR_NS_PER_MS + (x % GPR_NS_PER_MS != 0);
       break;
     case 'u':
-      *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
+      *timeout = x / GPR_US_PER_MS + (x % GPR_US_PER_MS != 0);
       break;
     case 'm':
-      *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
+      *timeout = x;
       break;
     case 'S':
-      *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
+      *timeout = x * GPR_MS_PER_SEC;
       break;
     case 'M':
-      *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
+      *timeout = x * 60 * GPR_MS_PER_SEC;
       break;
     case 'H':
-      *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
+      *timeout = x * 60 * 60 * GPR_MS_PER_SEC;
       break;
     default:
       return 0;
diff --git a/src/core/lib/transport/timeout_encoding.h b/src/core/lib/transport/timeout_encoding.h
index 1f4e206..25cb663 100644
--- a/src/core/lib/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -22,6 +22,7 @@
 #include <grpc/slice.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/support/string.h"
 
 #define GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
@@ -32,8 +33,8 @@
 
 /* Encode/decode timeouts to the GRPC over HTTP/2 format;
    encoding may round up arbitrarily */
-void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout);
+void grpc_http2_encode_timeout(grpc_millis timeout, char *buffer);
+int grpc_http2_decode_timeout(grpc_slice text, grpc_millis *timeout);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/lib/transport/transport_op_string.cc b/src/core/lib/transport/transport_op_string.cc
index 87fdf72..cc11b0c 100644
--- a/src/core/lib/transport/transport_op_string.cc
+++ b/src/core/lib/transport/transport_op_string.cc
@@ -51,10 +51,9 @@
     if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", "));
     put_metadata(b, m->md);
   }
-  if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) {
+  if (md.deadline != GRPC_MILLIS_INF_FUTURE) {
     char *tmp;
-    gpr_asprintf(&tmp, " deadline=%" PRId64 ".%09d", md.deadline.tv_sec,
-                 md.deadline.tv_nsec);
+    gpr_asprintf(&tmp, " deadline=%" PRIdPTR, md.deadline);
     gpr_strvec_add(b, tmp);
   }
 }
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
index 37798ec..c61afc1 100644
--- a/src/objective-c/BoringSSL.podspec
+++ b/src/objective-c/BoringSSL.podspec
@@ -31,7 +31,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'BoringSSL'
-  version = '9.0'
+  version = '9.1'
   s.version  = version
   s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
   # Adapted from the homepage:
@@ -67,9 +67,10 @@
   # "The name and email addresses of the library maintainers, not the Podspec maintainer."
   s.authors  = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite'
 
+  major_version = version[0] + '.0'
   s.source = {
     :git => 'https://boringssl.googlesource.com/boringssl',
-    :tag => "version_for_cocoapods_#{version}",
+    :tag => "version_for_cocoapods_#{major_version}",
   }
 
   name = 'openssl'
@@ -186,6 +187,7 @@
     cat > include/openssl/BoringSSL.modulemap <<EOF
       framework module openssl {
         umbrella header "umbrella.h"
+        textual header "arm_arch.h"
         export *
         module * { export * }
       }
diff --git a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
index 1796c6d..ad83481 100644
--- a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
@@ -47,7 +47,7 @@
 
   s.pod_target_xcconfig = {
     # This is needed by all pods that depend on Protobuf:
-    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO=1',
     # This is needed by all pods that depend on gRPC-RxLibrary:
     'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
   }
diff --git a/src/php/tests/qps/client.php b/src/php/tests/qps/client.php
index a785d83..0890405 100644
--- a/src/php/tests/qps/client.php
+++ b/src/php/tests/qps/client.php
@@ -37,6 +37,7 @@
  */
 
 require dirname(__FILE__).'/vendor/autoload.php';
+require dirname(__FILE__).'/histogram.php';
 
 /**
  * Assertion function that always exits with an error code if the assertion is
@@ -63,19 +64,19 @@
 }
 
 /* Start the actual client */
-
-function qps_client_main($proxy_address) {
-    echo "Initiating php client\n";
+function qps_client_main($proxy_address, $server_ind) {
+    echo "[php-client] Initiating php client\n";
 
     $proxystubopts = [];
     $proxystubopts['credentials'] = Grpc\ChannelCredentials::createInsecure();
     $proxystub = new Grpc\Testing\ProxyClientServiceClient($proxy_address, $proxystubopts);
     list($config, $status) = $proxystub->GetConfig(new Grpc\Testing\Void())->wait();
     hardAssertIfStatusOk($status);
-    hardAssert($config->getClientChannels() == 1, "Only 1 channel supported");
     hardAssert($config->getOutstandingRpcsPerChannel() == 1, "Only 1 outstanding RPC supported");
 
-    echo "Got configuration from proxy, target is " . $config->getServerTargets()[0] . "\n";
+    echo "[php-client] Got configuration from proxy, target is '$server_ind'th server" . $config->getServerTargets()[$server_ind] . "\n";
+    $histres = $config->getHistogramParams()->getResolution();
+    $histmax = $config->getHistogramParams()->getMaxPossible();
 
     $stubopts = [];
     if ($config->getSecurityParams()) {
@@ -93,10 +94,10 @@
     } else {
         $stubopts['credentials'] = Grpc\ChannelCredentials::createInsecure();
     }
-    echo "Initiating php benchmarking client\n";
+    echo "[php-client] Initiating php benchmarking client\n";
 
     $stub = new Grpc\Testing\BenchmarkServiceClient(
-        $config->getServerTargets()[0], $stubopts);
+        $config->getServerTargets()[$server_ind], $stubopts);
     $req = new Grpc\Testing\SimpleRequest();
 
     $req->setResponseType(Grpc\Testing\PayloadType::COMPRESSABLE);
@@ -115,8 +116,11 @@
     } else {
         $poisson = false;
     }
-    $metric = new Grpc\Testing\ProxyStat;
-    $telemetry = $proxystub->ReportTime();
+    $histogram = new Histogram($histres, $histmax);
+    $histogram->clean();
+    $count = 0;
+    $histogram_result = new Grpc\Testing\HistogramData;
+    $telehist = $proxystub->ReportHist();
     if ($config->getRpcType() == Grpc\Testing\RpcType::UNARY) {
         while (1) {
             if ($poisson) {
@@ -126,8 +130,20 @@
             $startreq = microtime(true);
             list($resp,$status) = $stub->UnaryCall($req)->wait();
             hardAssertIfStatusOk($status);
-            $metric->setLatency(microtime(true)-$startreq);
-            $telemetry->write($metric);
+            $histogram->add((microtime(true)-$startreq)*1e9);
+            $count += 1;
+            if ($count == 2000) {
+              $contents = $histogram->contents();
+              $histogram_result->setBucket($contents);
+              $histogram_result->setMinSeen($histogram->minimum());
+              $histogram_result->setMaxSeen($histogram->maximum());
+              $histogram_result->setSum($histogram->sum());
+              $histogram_result->setSumOfSquares($histogram->sum_of_squares());
+              $histogram_result->setCount($histogram->count());
+              $telehist->write($histogram_result);
+              $histogram->clean();
+              $count = 0;
+            }
         }
     } else {
         $stream = $stub->StreamingCall();
@@ -139,8 +155,20 @@
             $startreq = microtime(true);
             $stream->write($req);
             $resp = $stream->read();
-            $metric->setLatency(microtime(true)-$startreq);
-            $telemetry->write($metric);
+            $histogram->add((microtime(true)-$startreq)*1e9);
+            $count += 1;
+            if ($count == 2000) {
+              $contents = $histogram->contents();
+              $histogram_result->setBucket($contents);
+              $histogram_result->setMinSeen($histogram->minimum());
+              $histogram_result->setMaxSeen($histogram->maximum());
+              $histogram_result->setSum($histogram->sum());
+              $histogram_result->setSumOfSquares($histogram->sum_of_squares());
+              $histogram_result->setCount($histogram->count());
+              $telehist->write($histogram_result);
+              $histogram->clean();
+              $count = 0;
+          }
         }
     }
 }
@@ -148,4 +176,4 @@
 ini_set('display_startup_errors', 1);
 ini_set('display_errors', 1);
 error_reporting(-1);
-qps_client_main($argv[1]);
+qps_client_main($argv[1], $argv[2]);
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Core/Stats.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Core/Stats.php
new file mode 100644
index 0000000..f9c710c
--- /dev/null
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Core/Stats.php
@@ -0,0 +1,33 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: src/proto/grpc/core/stats.proto
+
+namespace GPBMetadata\Src\Proto\Grpc\Core;
+
+class Stats
+{
+    public static $is_initialized = false;
+
+    public static function initOnce() {
+        $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+        if (static::$is_initialized == true) {
+          return;
+        }
+        $pool->internalAddGeneratedFile(hex2bin(
+            "0a97020a1f7372632f70726f746f2f677270632f636f72652f7374617473" .
+            "2e70726f746f1209677270632e636f726522260a064275636b6574120d0a" .
+            "057374617274180120012801120d0a05636f756e74180220012804222f0a" .
+            "09486973746f6772616d12220a076275636b65747318012003280b32112e" .
+            "677270632e636f72652e4275636b6574225b0a064d6574726963120c0a04" .
+            "6e616d65180120012809120f0a05636f756e74180a20012804480012290a" .
+            "09686973746f6772616d180b2001280b32142e677270632e636f72652e48" .
+            "6973746f6772616d480042070a0576616c7565222b0a0553746174731222" .
+            "0a076d65747269637318012003280b32112e677270632e636f72652e4d65" .
+            "74726963620670726f746f33"
+        ));
+
+        static::$is_initialized = true;
+    }
+}
+
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php
index efca18a..9b3a752 100644
--- a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Control.php
@@ -17,108 +17,119 @@
         \GPBMetadata\Src\Proto\Grpc\Testing\Payloads::initOnce();
         \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
         $pool->internalAddGeneratedFile(hex2bin(
-            "0add170a247372632f70726f746f2f677270632f74657374696e672f636f" .
-            "6e74726f6c2e70726f746f120c677270632e74657374696e671a25737263" .
-            "2f70726f746f2f677270632f74657374696e672f7061796c6f6164732e70" .
-            "726f746f1a227372632f70726f746f2f677270632f74657374696e672f73" .
-            "746174732e70726f746f22250a0d506f6973736f6e506172616d7312140a" .
-            "0c6f6666657265645f6c6f616418012001280122120a10436c6f7365644c" .
-            "6f6f70506172616d73227b0a0a4c6f6164506172616d7312350a0b636c6f" .
-            "7365645f6c6f6f7018012001280b321e2e677270632e74657374696e672e" .
-            "436c6f7365644c6f6f70506172616d734800122e0a07706f6973736f6e18" .
-            "022001280b321b2e677270632e74657374696e672e506f6973736f6e5061" .
-            "72616d73480042060a046c6f616422430a0e536563757269747950617261" .
-            "6d7312130a0b7573655f746573745f6361180120012808121c0a14736572" .
-            "7665725f686f73745f6f76657272696465180220012809224d0a0a436861" .
-            "6e6e656c417267120c0a046e616d6518012001280912130a097374725f76" .
-            "616c7565180220012809480012130a09696e745f76616c75651803200128" .
-            "05480042070a0576616c756522a0040a0c436c69656e74436f6e66696712" .
-            "160a0e7365727665725f74617267657473180120032809122d0a0b636c69" .
-            "656e745f7479706518022001280e32182e677270632e74657374696e672e" .
-            "436c69656e745479706512350a0f73656375726974795f706172616d7318" .
-            "032001280b321c2e677270632e74657374696e672e536563757269747950" .
-            "6172616d7312240a1c6f75747374616e64696e675f727063735f7065725f" .
-            "6368616e6e656c18042001280512170a0f636c69656e745f6368616e6e65" .
-            "6c73180520012805121c0a146173796e635f636c69656e745f7468726561" .
-            "647318072001280512270a087270635f7479706518082001280e32152e67" .
-            "7270632e74657374696e672e52706354797065122d0a0b6c6f61645f7061" .
-            "72616d73180a2001280b32182e677270632e74657374696e672e4c6f6164" .
-            "506172616d7312330a0e7061796c6f61645f636f6e666967180b2001280b" .
-            "321b2e677270632e74657374696e672e5061796c6f6164436f6e66696712" .
-            "370a10686973746f6772616d5f706172616d73180c2001280b321d2e6772" .
-            "70632e74657374696e672e486973746f6772616d506172616d7312110a09" .
-            "636f72655f6c697374180d2003280512120a0a636f72655f6c696d697418" .
-            "0e2001280512180a106f746865725f636c69656e745f617069180f200128" .
-            "09122e0a0c6368616e6e656c5f6172677318102003280b32182e67727063" .
-            "2e74657374696e672e4368616e6e656c41726722380a0c436c69656e7453" .
-            "746174757312280a05737461747318012001280b32192e677270632e7465" .
-            "7374696e672e436c69656e74537461747322150a044d61726b120d0a0572" .
-            "6573657418012001280822680a0a436c69656e7441726773122b0a057365" .
-            "74757018012001280b321a2e677270632e74657374696e672e436c69656e" .
-            "74436f6e666967480012220a046d61726b18022001280b32122e67727063" .
-            "2e74657374696e672e4d61726b480042090a076172677479706522b4020a" .
-            "0c536572766572436f6e666967122d0a0b7365727665725f747970651801" .
-            "2001280e32182e677270632e74657374696e672e53657276657254797065" .
-            "12350a0f73656375726974795f706172616d7318022001280b321c2e6772" .
-            "70632e74657374696e672e5365637572697479506172616d73120c0a0470" .
-            "6f7274180420012805121c0a146173796e635f7365727665725f74687265" .
-            "61647318072001280512120a0a636f72655f6c696d697418082001280512" .
-            "330a0e7061796c6f61645f636f6e66696718092001280b321b2e67727063" .
-            "2e74657374696e672e5061796c6f6164436f6e66696712110a09636f7265" .
-            "5f6c697374180a2003280512180a106f746865725f7365727665725f6170" .
-            "69180b20012809121c0a137265736f757263655f71756f74615f73697a65" .
-            "18e9072001280522680a0a53657276657241726773122b0a057365747570" .
-            "18012001280b321a2e677270632e74657374696e672e536572766572436f" .
-            "6e666967480012220a046d61726b18022001280b32122e677270632e7465" .
-            "7374696e672e4d61726b480042090a076172677479706522550a0c536572" .
-            "76657253746174757312280a05737461747318012001280b32192e677270" .
-            "632e74657374696e672e5365727665725374617473120c0a04706f727418" .
-            "0220012805120d0a05636f726573180320012805220d0a0b436f72655265" .
-            "7175657374221d0a0c436f7265526573706f6e7365120d0a05636f726573" .
-            "18012001280522060a04566f696422fd010a085363656e6172696f120c0a" .
-            "046e616d6518012001280912310a0d636c69656e745f636f6e6669671802" .
-            "2001280b321a2e677270632e74657374696e672e436c69656e74436f6e66" .
-            "696712130a0b6e756d5f636c69656e747318032001280512310a0d736572" .
-            "7665725f636f6e66696718042001280b321a2e677270632e74657374696e" .
-            "672e536572766572436f6e66696712130a0b6e756d5f7365727665727318" .
-            "052001280512160a0e7761726d75705f7365636f6e647318062001280512" .
-            "190a1162656e63686d61726b5f7365636f6e647318072001280512200a18" .
-            "737061776e5f6c6f63616c5f776f726b65725f636f756e74180820012805" .
-            "22360a095363656e6172696f7312290a097363656e6172696f7318012003" .
-            "280b32162e677270632e74657374696e672e5363656e6172696f22f8020a" .
-            "155363656e6172696f526573756c7453756d6d617279120b0a0371707318" .
-            "0120012801121b0a137170735f7065725f7365727665725f636f72651802" .
-            "20012801121a0a127365727665725f73797374656d5f74696d6518032001" .
-            "280112180a107365727665725f757365725f74696d65180420012801121a" .
-            "0a12636c69656e745f73797374656d5f74696d6518052001280112180a10" .
-            "636c69656e745f757365725f74696d6518062001280112120a0a6c617465" .
-            "6e63795f353018072001280112120a0a6c6174656e63795f393018082001" .
-            "280112120a0a6c6174656e63795f393518092001280112120a0a6c617465" .
-            "6e63795f3939180a2001280112130a0b6c6174656e63795f393939180b20" .
-            "01280112180a107365727665725f6370755f7573616765180c2001280112" .
-            "260a1e7375636365737366756c5f72657175657374735f7065725f736563" .
-            "6f6e64180d2001280112220a1a6661696c65645f72657175657374735f70" .
-            "65725f7365636f6e64180e200128012283030a0e5363656e6172696f5265" .
-            "73756c7412280a087363656e6172696f18012001280b32162e677270632e" .
-            "74657374696e672e5363656e6172696f122e0a096c6174656e6369657318" .
-            "022001280b321b2e677270632e74657374696e672e486973746f6772616d" .
-            "44617461122f0a0c636c69656e745f737461747318032003280b32192e67" .
-            "7270632e74657374696e672e436c69656e745374617473122f0a0c736572" .
-            "7665725f737461747318042003280b32192e677270632e74657374696e67" .
-            "2e536572766572537461747312140a0c7365727665725f636f7265731805" .
-            "2003280512340a0773756d6d61727918062001280b32232e677270632e74" .
-            "657374696e672e5363656e6172696f526573756c7453756d6d6172791216" .
-            "0a0e636c69656e745f7375636365737318072003280812160a0e73657276" .
-            "65725f7375636365737318082003280812390a0f726571756573745f7265" .
-            "73756c747318092003280b32202e677270632e74657374696e672e526571" .
-            "75657374526573756c74436f756e742a410a0a436c69656e745479706512" .
-            "0f0a0b53594e435f434c49454e54100012100a0c4153594e435f434c4945" .
-            "4e54100112100a0c4f544845525f434c49454e5410022a5b0a0a53657276" .
-            "657254797065120f0a0b53594e435f534552564552100012100a0c415359" .
-            "4e435f534552564552100112180a144153594e435f47454e455249435f53" .
-            "4552564552100212100a0c4f544845525f53455256455210032a230a0752" .
-            "70635479706512090a05554e4152591000120d0a0953545245414d494e47" .
-            "1001620670726f746f33"
+            "0aa21a0a247372632f70726f746f2f677270632f74657374696e672f636f" .
+            "6e74726f6c2e70726f746f120c677270632e74657374696e671a22737263" .
+            "2f70726f746f2f677270632f74657374696e672f73746174732e70726f74" .
+            "6f22250a0d506f6973736f6e506172616d7312140a0c6f6666657265645f" .
+            "6c6f616418012001280122120a10436c6f7365644c6f6f70506172616d73" .
+            "227b0a0a4c6f6164506172616d7312350a0b636c6f7365645f6c6f6f7018" .
+            "012001280b321e2e677270632e74657374696e672e436c6f7365644c6f6f" .
+            "70506172616d734800122e0a07706f6973736f6e18022001280b321b2e67" .
+            "7270632e74657374696e672e506f6973736f6e506172616d73480042060a" .
+            "046c6f616422560a0e5365637572697479506172616d7312130a0b757365" .
+            "5f746573745f6361180120012808121c0a147365727665725f686f73745f" .
+            "6f7665727269646518022001280912110a09637265645f74797065180320" .
+            "012809224d0a0a4368616e6e656c417267120c0a046e616d651801200128" .
+            "0912130a097374725f76616c7565180220012809480012130a09696e745f" .
+            "76616c7565180320012805480042070a0576616c756522d5040a0c436c69" .
+            "656e74436f6e66696712160a0e7365727665725f74617267657473180120" .
+            "032809122d0a0b636c69656e745f7479706518022001280e32182e677270" .
+            "632e74657374696e672e436c69656e745479706512350a0f736563757269" .
+            "74795f706172616d7318032001280b321c2e677270632e74657374696e67" .
+            "2e5365637572697479506172616d7312240a1c6f75747374616e64696e67" .
+            "5f727063735f7065725f6368616e6e656c18042001280512170a0f636c69" .
+            "656e745f6368616e6e656c73180520012805121c0a146173796e635f636c" .
+            "69656e745f7468726561647318072001280512270a087270635f74797065" .
+            "18082001280e32152e677270632e74657374696e672e5270635479706512" .
+            "2d0a0b6c6f61645f706172616d73180a2001280b32182e677270632e7465" .
+            "7374696e672e4c6f6164506172616d7312330a0e7061796c6f61645f636f" .
+            "6e666967180b2001280b321b2e677270632e74657374696e672e5061796c" .
+            "6f6164436f6e66696712370a10686973746f6772616d5f706172616d7318" .
+            "0c2001280b321d2e677270632e74657374696e672e486973746f6772616d" .
+            "506172616d7312110a09636f72655f6c697374180d2003280512120a0a63" .
+            "6f72655f6c696d6974180e2001280512180a106f746865725f636c69656e" .
+            "745f617069180f20012809122e0a0c6368616e6e656c5f61726773181020" .
+            "03280b32182e677270632e74657374696e672e4368616e6e656c41726712" .
+            "160a0e746872656164735f7065725f6371181120012805121b0a136d6573" .
+            "73616765735f7065725f73747265616d18122001280522380a0c436c6965" .
+            "6e7453746174757312280a05737461747318012001280b32192e67727063" .
+            "2e74657374696e672e436c69656e74537461747322150a044d61726b120d" .
+            "0a05726573657418012001280822680a0a436c69656e7441726773122b0a" .
+            "05736574757018012001280b321a2e677270632e74657374696e672e436c" .
+            "69656e74436f6e666967480012220a046d61726b18022001280b32122e67" .
+            "7270632e74657374696e672e4d61726b480042090a076172677479706522" .
+            "fd020a0c536572766572436f6e666967122d0a0b7365727665725f747970" .
+            "6518012001280e32182e677270632e74657374696e672e53657276657254" .
+            "79706512350a0f73656375726974795f706172616d7318022001280b321c" .
+            "2e677270632e74657374696e672e5365637572697479506172616d73120c" .
+            "0a04706f7274180420012805121c0a146173796e635f7365727665725f74" .
+            "68726561647318072001280512120a0a636f72655f6c696d697418082001" .
+            "280512330a0e7061796c6f61645f636f6e66696718092001280b321b2e67" .
+            "7270632e74657374696e672e5061796c6f6164436f6e66696712110a0963" .
+            "6f72655f6c697374180a2003280512180a106f746865725f736572766572" .
+            "5f617069180b2001280912160a0e746872656164735f7065725f6371180c" .
+            "20012805121c0a137265736f757263655f71756f74615f73697a6518e907" .
+            "20012805122f0a0c6368616e6e656c5f6172677318ea072003280b32182e" .
+            "677270632e74657374696e672e4368616e6e656c41726722680a0a536572" .
+            "76657241726773122b0a05736574757018012001280b321a2e677270632e" .
+            "74657374696e672e536572766572436f6e666967480012220a046d61726b" .
+            "18022001280b32122e677270632e74657374696e672e4d61726b48004209" .
+            "0a076172677479706522550a0c53657276657253746174757312280a0573" .
+            "7461747318012001280b32192e677270632e74657374696e672e53657276" .
+            "65725374617473120c0a04706f7274180220012805120d0a05636f726573" .
+            "180320012805220d0a0b436f726552657175657374221d0a0c436f726552" .
+            "6573706f6e7365120d0a05636f72657318012001280522060a04566f6964" .
+            "22fd010a085363656e6172696f120c0a046e616d6518012001280912310a" .
+            "0d636c69656e745f636f6e66696718022001280b321a2e677270632e7465" .
+            "7374696e672e436c69656e74436f6e66696712130a0b6e756d5f636c6965" .
+            "6e747318032001280512310a0d7365727665725f636f6e66696718042001" .
+            "280b321a2e677270632e74657374696e672e536572766572436f6e666967" .
+            "12130a0b6e756d5f7365727665727318052001280512160a0e7761726d75" .
+            "705f7365636f6e647318062001280512190a1162656e63686d61726b5f73" .
+            "65636f6e647318072001280512200a18737061776e5f6c6f63616c5f776f" .
+            "726b65725f636f756e7418082001280522360a095363656e6172696f7312" .
+            "290a097363656e6172696f7318012003280b32162e677270632e74657374" .
+            "696e672e5363656e6172696f2284040a155363656e6172696f526573756c" .
+            "7453756d6d617279120b0a03717073180120012801121b0a137170735f70" .
+            "65725f7365727665725f636f7265180220012801121a0a12736572766572" .
+            "5f73797374656d5f74696d6518032001280112180a107365727665725f75" .
+            "7365725f74696d65180420012801121a0a12636c69656e745f7379737465" .
+            "6d5f74696d6518052001280112180a10636c69656e745f757365725f7469" .
+            "6d6518062001280112120a0a6c6174656e63795f35301807200128011212" .
+            "0a0a6c6174656e63795f393018082001280112120a0a6c6174656e63795f" .
+            "393518092001280112120a0a6c6174656e63795f3939180a200128011213" .
+            "0a0b6c6174656e63795f393939180b2001280112180a107365727665725f" .
+            "6370755f7573616765180c2001280112260a1e7375636365737366756c5f" .
+            "72657175657374735f7065725f7365636f6e64180d2001280112220a1a66" .
+            "61696c65645f72657175657374735f7065725f7365636f6e64180e200128" .
+            "0112200a18636c69656e745f706f6c6c735f7065725f7265717565737418" .
+            "0f2001280112200a187365727665725f706f6c6c735f7065725f72657175" .
+            "65737418102001280112220a1a7365727665725f717565726965735f7065" .
+            "725f6370755f73656318112001280112220a1a636c69656e745f71756572" .
+            "6965735f7065725f6370755f7365631812200128012283030a0e5363656e" .
+            "6172696f526573756c7412280a087363656e6172696f18012001280b3216" .
+            "2e677270632e74657374696e672e5363656e6172696f122e0a096c617465" .
+            "6e6369657318022001280b321b2e677270632e74657374696e672e486973" .
+            "746f6772616d44617461122f0a0c636c69656e745f737461747318032003" .
+            "280b32192e677270632e74657374696e672e436c69656e74537461747312" .
+            "2f0a0c7365727665725f737461747318042003280b32192e677270632e74" .
+            "657374696e672e536572766572537461747312140a0c7365727665725f63" .
+            "6f72657318052003280512340a0773756d6d61727918062001280b32232e" .
+            "677270632e74657374696e672e5363656e6172696f526573756c7453756d" .
+            "6d61727912160a0e636c69656e745f737563636573731807200328081216" .
+            "0a0e7365727665725f7375636365737318082003280812390a0f72657175" .
+            "6573745f726573756c747318092003280b32202e677270632e7465737469" .
+            "6e672e52657175657374526573756c74436f756e742a410a0a436c69656e" .
+            "7454797065120f0a0b53594e435f434c49454e54100012100a0c4153594e" .
+            "435f434c49454e54100112100a0c4f544845525f434c49454e5410022a5b" .
+            "0a0a53657276657254797065120f0a0b53594e435f534552564552100012" .
+            "100a0c4153594e435f534552564552100112180a144153594e435f47454e" .
+            "455249435f534552564552100212100a0c4f544845525f53455256455210" .
+            "032a720a075270635479706512090a05554e4152591000120d0a09535452" .
+            "45414d494e47100112190a1553545245414d494e475f46524f4d5f434c49" .
+            "454e54100212190a1553545245414d494e475f46524f4d5f534552564552" .
+            "100312170a1353545245414d494e475f424f54485f574159531004620670" .
+            "726f746f33"
         ));
 
         static::$is_initialized = true;
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php
index e35944e..e07f736 100644
--- a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/ProxyService.php
@@ -15,17 +15,20 @@
           return;
         }
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+        \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
         $pool->internalAddGeneratedFile(hex2bin(
-            "0a97020a2a7372632f70726f746f2f677270632f74657374696e672f7072" .
+            "0ad6020a2a7372632f70726f746f2f677270632f74657374696e672f7072" .
             "6f78792d736572766963652e70726f746f120c677270632e74657374696e" .
-            "671a247372632f70726f746f2f677270632f74657374696e672f636f6e74" .
-            "726f6c2e70726f746f221c0a0950726f787953746174120f0a076c617465" .
-            "6e6379180120012801328e010a1250726f7879436c69656e745365727669" .
-            "6365123b0a09476574436f6e66696712122e677270632e74657374696e67" .
-            "2e566f69641a1a2e677270632e74657374696e672e436c69656e74436f6e" .
-            "666967123b0a0a5265706f727454696d6512172e677270632e7465737469" .
-            "6e672e50726f7879537461741a122e677270632e74657374696e672e566f" .
-            "69642801620670726f746f33"
+            "671a227372632f70726f746f2f677270632f74657374696e672f73746174" .
+            "732e70726f746f221c0a0950726f787953746174120f0a076c6174656e63" .
+            "7918012001280132cf010a1250726f7879436c69656e7453657276696365" .
+            "123b0a09476574436f6e66696712122e677270632e74657374696e672e56" .
+            "6f69641a1a2e677270632e74657374696e672e436c69656e74436f6e6669" .
+            "67123b0a0a5265706f727454696d6512172e677270632e74657374696e67" .
+            "2e50726f7879537461741a122e677270632e74657374696e672e566f6964" .
+            "2801123f0a0a5265706f727448697374121b2e677270632e74657374696e" .
+            "672e486973746f6772616d446174611a122e677270632e74657374696e67" .
+            "2e566f69642801620670726f746f33"
         ));
 
         static::$is_initialized = true;
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php
index 7a9439a..e402918 100644
--- a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Services.php
@@ -16,27 +16,40 @@
         }
         \GPBMetadata\Src\Proto\Grpc\Testing\Messages::initOnce();
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
+        \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
         $pool->internalAddGeneratedFile(hex2bin(
-            "0ad1040a257372632f70726f746f2f677270632f74657374696e672f7365" .
-            "7276696365732e70726f746f120c677270632e74657374696e671a257372" .
-            "632f70726f746f2f677270632f74657374696e672f6d657373616765732e" .
-            "70726f746f1a247372632f70726f746f2f677270632f74657374696e672f" .
-            "636f6e74726f6c2e70726f746f32aa010a1042656e63686d61726b536572" .
-            "7669636512460a09556e61727943616c6c121b2e677270632e7465737469" .
-            "6e672e53696d706c65526571756573741a1c2e677270632e74657374696e" .
-            "672e53696d706c65526573706f6e7365124e0a0d53747265616d696e6743" .
-            "616c6c121b2e677270632e74657374696e672e53696d706c655265717565" .
-            "73741a1c2e677270632e74657374696e672e53696d706c65526573706f6e" .
-            "7365280130013297020a0d576f726b65725365727669636512450a095275" .
-            "6e53657276657212182e677270632e74657374696e672e53657276657241" .
-            "7267731a1a2e677270632e74657374696e672e5365727665725374617475" .
-            "732801300112450a0952756e436c69656e7412182e677270632e74657374" .
-            "696e672e436c69656e74417267731a1a2e677270632e74657374696e672e" .
-            "436c69656e745374617475732801300112420a09436f7265436f756e7412" .
-            "192e677270632e74657374696e672e436f7265526571756573741a1a2e67" .
-            "7270632e74657374696e672e436f7265526573706f6e736512340a0a5175" .
-            "6974576f726b657212122e677270632e74657374696e672e566f69641a12" .
-            "2e677270632e74657374696e672e566f6964620670726f746f33"
+            "0aaa070a257372632f70726f746f2f677270632f74657374696e672f7365" .
+            "7276696365732e70726f746f120c677270632e74657374696e671a247372" .
+            "632f70726f746f2f677270632f74657374696e672f636f6e74726f6c2e70" .
+            "726f746f1a227372632f70726f746f2f677270632f74657374696e672f73" .
+            "746174732e70726f746f32a6030a1042656e63686d61726b536572766963" .
+            "6512460a09556e61727943616c6c121b2e677270632e74657374696e672e" .
+            "53696d706c65526571756573741a1c2e677270632e74657374696e672e53" .
+            "696d706c65526573706f6e7365124e0a0d53747265616d696e6743616c6c" .
+            "121b2e677270632e74657374696e672e53696d706c65526571756573741a" .
+            "1c2e677270632e74657374696e672e53696d706c65526573706f6e736528" .
+            "01300112520a1353747265616d696e6746726f6d436c69656e74121b2e67" .
+            "7270632e74657374696e672e53696d706c65526571756573741a1c2e6772" .
+            "70632e74657374696e672e53696d706c65526573706f6e7365280112520a" .
+            "1353747265616d696e6746726f6d536572766572121b2e677270632e7465" .
+            "7374696e672e53696d706c65526571756573741a1c2e677270632e746573" .
+            "74696e672e53696d706c65526573706f6e7365300112520a115374726561" .
+            "6d696e67426f746857617973121b2e677270632e74657374696e672e5369" .
+            "6d706c65526571756573741a1c2e677270632e74657374696e672e53696d" .
+            "706c65526573706f6e7365280130013297020a0d576f726b657253657276" .
+            "69636512450a0952756e53657276657212182e677270632e74657374696e" .
+            "672e536572766572417267731a1a2e677270632e74657374696e672e5365" .
+            "727665725374617475732801300112450a0952756e436c69656e7412182e" .
+            "677270632e74657374696e672e436c69656e74417267731a1a2e67727063" .
+            "2e74657374696e672e436c69656e745374617475732801300112420a0943" .
+            "6f7265436f756e7412192e677270632e74657374696e672e436f72655265" .
+            "71756573741a1a2e677270632e74657374696e672e436f7265526573706f" .
+            "6e736512340a0a51756974576f726b657212122e677270632e7465737469" .
+            "6e672e566f69641a122e677270632e74657374696e672e566f6964325e0a" .
+            "185265706f72745170735363656e6172696f5365727669636512420a0e52" .
+            "65706f72745363656e6172696f121c2e677270632e74657374696e672e53" .
+            "63656e6172696f526573756c741a122e677270632e74657374696e672e56" .
+            "6f6964620670726f746f33"
         ));
 
         static::$is_initialized = true;
diff --git a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php
index 99c0000..3d23b75 100644
--- a/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php
+++ b/src/php/tests/qps/generated_code/GPBMetadata/Src/Proto/Grpc/Testing/Stats.php
@@ -14,28 +14,33 @@
         if (static::$is_initialized == true) {
           return;
         }
+        \GPBMetadata\Src\Proto\Grpc\Core\Stats::initOnce();
         $pool->internalAddGeneratedFile(hex2bin(
-            "0adf040a227372632f70726f746f2f677270632f74657374696e672f7374" .
-            "6174732e70726f746f120c677270632e74657374696e67227a0a0b536572" .
-            "766572537461747312140a0c74696d655f656c6170736564180120012801" .
-            "12110a0974696d655f7573657218022001280112130a0b74696d655f7379" .
-            "7374656d18032001280112160a0e746f74616c5f6370755f74696d651804" .
-            "2001280412150a0d69646c655f6370755f74696d65180520012804223b0a" .
-            "0f486973746f6772616d506172616d7312120a0a7265736f6c7574696f6e" .
-            "18012001280112140a0c6d61785f706f737369626c651802200128012277" .
-            "0a0d486973746f6772616d44617461120e0a066275636b65741801200328" .
-            "0d12100a086d696e5f7365656e18022001280112100a086d61785f736565" .
-            "6e180320012801120b0a0373756d18042001280112160a0e73756d5f6f66" .
-            "5f73717561726573180520012801120d0a05636f756e7418062001280122" .
-            "380a1252657175657374526573756c74436f756e7412130a0b7374617475" .
-            "735f636f6465180120012805120d0a05636f756e7418022001280322b601" .
-            "0a0b436c69656e745374617473122e0a096c6174656e6369657318012001" .
-            "280b321b2e677270632e74657374696e672e486973746f6772616d446174" .
-            "6112140a0c74696d655f656c617073656418022001280112110a0974696d" .
-            "655f7573657218032001280112130a0b74696d655f73797374656d180420" .
-            "01280112390a0f726571756573745f726573756c747318052003280b3220" .
-            "2e677270632e74657374696e672e52657175657374526573756c74436f75" .
-            "6e74620670726f746f33"
+            "0ada050a227372632f70726f746f2f677270632f74657374696e672f7374" .
+            "6174732e70726f746f120c677270632e74657374696e6722b7010a0b5365" .
+            "72766572537461747312140a0c74696d655f656c61707365641801200128" .
+            "0112110a0974696d655f7573657218022001280112130a0b74696d655f73" .
+            "797374656d18032001280112160a0e746f74616c5f6370755f74696d6518" .
+            "042001280412150a0d69646c655f6370755f74696d651805200128041215" .
+            "0a0d63715f706f6c6c5f636f756e7418062001280412240a0a636f72655f" .
+            "737461747318072001280b32102e677270632e636f72652e537461747322" .
+            "3b0a0f486973746f6772616d506172616d7312120a0a7265736f6c757469" .
+            "6f6e18012001280112140a0c6d61785f706f737369626c65180220012801" .
+            "22770a0d486973746f6772616d44617461120e0a066275636b6574180120" .
+            "03280d12100a086d696e5f7365656e18022001280112100a086d61785f73" .
+            "65656e180320012801120b0a0373756d18042001280112160a0e73756d5f" .
+            "6f665f73717561726573180520012801120d0a05636f756e741806200128" .
+            "0122380a1252657175657374526573756c74436f756e7412130a0b737461" .
+            "7475735f636f6465180120012805120d0a05636f756e7418022001280322" .
+            "f3010a0b436c69656e745374617473122e0a096c6174656e636965731801" .
+            "2001280b321b2e677270632e74657374696e672e486973746f6772616d44" .
+            "61746112140a0c74696d655f656c617073656418022001280112110a0974" .
+            "696d655f7573657218032001280112130a0b74696d655f73797374656d18" .
+            "042001280112390a0f726571756573745f726573756c747318052003280b" .
+            "32202e677270632e74657374696e672e52657175657374526573756c7443" .
+            "6f756e7412150a0d63715f706f6c6c5f636f756e7418062001280412240a" .
+            "0a636f72655f737461747318072001280b32102e677270632e636f72652e" .
+            "5374617473620670726f746f33"
         ));
 
         static::$is_initialized = true;
diff --git a/src/php/tests/qps/generated_code/Grpc/Core/Bucket.php b/src/php/tests/qps/generated_code/Grpc/Core/Bucket.php
new file mode 100644
index 0000000..897d627
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Core/Bucket.php
@@ -0,0 +1,75 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: src/proto/grpc/core/stats.proto
+
+namespace Grpc\Core;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>grpc.core.Bucket</code>
+ */
+class Bucket extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>double start = 1;</code>
+     */
+    private $start = 0.0;
+    /**
+     * Generated from protobuf field <code>uint64 count = 2;</code>
+     */
+    private $count = 0;
+
+    public function __construct() {
+        \GPBMetadata\Src\Proto\Grpc\Core\Stats::initOnce();
+        parent::__construct();
+    }
+
+    /**
+     * Generated from protobuf field <code>double start = 1;</code>
+     * @return float
+     */
+    public function getStart()
+    {
+        return $this->start;
+    }
+
+    /**
+     * Generated from protobuf field <code>double start = 1;</code>
+     * @param float $var
+     * @return $this
+     */
+    public function setStart($var)
+    {
+        GPBUtil::checkDouble($var);
+        $this->start = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>uint64 count = 2;</code>
+     * @return int|string
+     */
+    public function getCount()
+    {
+        return $this->count;
+    }
+
+    /**
+     * Generated from protobuf field <code>uint64 count = 2;</code>
+     * @param int|string $var
+     * @return $this
+     */
+    public function setCount($var)
+    {
+        GPBUtil::checkUint64($var);
+        $this->count = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Core/Histogram.php b/src/php/tests/qps/generated_code/Grpc/Core/Histogram.php
new file mode 100644
index 0000000..1902be8
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Core/Histogram.php
@@ -0,0 +1,49 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: src/proto/grpc/core/stats.proto
+
+namespace Grpc\Core;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>grpc.core.Histogram</code>
+ */
+class Histogram extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Bucket buckets = 1;</code>
+     */
+    private $buckets;
+
+    public function __construct() {
+        \GPBMetadata\Src\Proto\Grpc\Core\Stats::initOnce();
+        parent::__construct();
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Bucket buckets = 1;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
+     */
+    public function getBuckets()
+    {
+        return $this->buckets;
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Bucket buckets = 1;</code>
+     * @param \Grpc\Core\Bucket[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
+     */
+    public function setBuckets($var)
+    {
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Core\Bucket::class);
+        $this->buckets = $arr;
+
+        return $this;
+    }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Core/Metric.php b/src/php/tests/qps/generated_code/Grpc/Core/Metric.php
new file mode 100644
index 0000000..c3581b7
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Core/Metric.php
@@ -0,0 +1,102 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: src/proto/grpc/core/stats.proto
+
+namespace Grpc\Core;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>grpc.core.Metric</code>
+ */
+class Metric extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     */
+    private $name = '';
+    protected $value;
+
+    public function __construct() {
+        \GPBMetadata\Src\Proto\Grpc\Core\Stats::initOnce();
+        parent::__construct();
+    }
+
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>uint64 count = 10;</code>
+     * @return int|string
+     */
+    public function getCount()
+    {
+        return $this->readOneof(10);
+    }
+
+    /**
+     * Generated from protobuf field <code>uint64 count = 10;</code>
+     * @param int|string $var
+     * @return $this
+     */
+    public function setCount($var)
+    {
+        GPBUtil::checkUint64($var);
+        $this->writeOneof(10, $var);
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>.grpc.core.Histogram histogram = 11;</code>
+     * @return \Grpc\Core\Histogram
+     */
+    public function getHistogram()
+    {
+        return $this->readOneof(11);
+    }
+
+    /**
+     * Generated from protobuf field <code>.grpc.core.Histogram histogram = 11;</code>
+     * @param \Grpc\Core\Histogram $var
+     * @return $this
+     */
+    public function setHistogram($var)
+    {
+        GPBUtil::checkMessage($var, \Grpc\Core\Histogram::class);
+        $this->writeOneof(11, $var);
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->whichOneof("value");
+    }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Core/Stats.php b/src/php/tests/qps/generated_code/Grpc/Core/Stats.php
new file mode 100644
index 0000000..e6f3fb0
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Core/Stats.php
@@ -0,0 +1,49 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: src/proto/grpc/core/stats.proto
+
+namespace Grpc\Core;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>grpc.core.Stats</code>
+ */
+class Stats extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Metric metrics = 1;</code>
+     */
+    private $metrics;
+
+    public function __construct() {
+        \GPBMetadata\Src\Proto\Grpc\Core\Stats::initOnce();
+        parent::__construct();
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Metric metrics = 1;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
+     */
+    public function getMetrics()
+    {
+        return $this->metrics;
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.core.Metric metrics = 1;</code>
+     * @param \Grpc\Core\Metric[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
+     */
+    public function setMetrics($var)
+    {
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Core\Metric::class);
+        $this->metrics = $arr;
+
+        return $this;
+    }
+
+}
+
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php
index ddf750a..fa3e147 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/BenchmarkServiceClient.php
@@ -18,17 +18,19 @@
 //
 // An integration test service that covers all the method signature permutations
 // of unary/streaming requests/responses.
-namespace Grpc\Testing {
+namespace Grpc\Testing;
 
-  class BenchmarkServiceClient extends \Grpc\BaseStub {
+/**
+ */
+class BenchmarkServiceClient extends \Grpc\BaseStub {
 
     /**
      * @param string $hostname hostname
      * @param array $opts channel options
-     * @param Grpc\Channel $channel (optional) re-use channel object
+     * @param \Grpc\Channel $channel (optional) re-use channel object
      */
     public function __construct($hostname, $opts, $channel = null) {
-      parent::__construct($hostname, $opts, $channel);
+        parent::__construct($hostname, $opts, $channel);
     }
 
     /**
@@ -40,24 +42,62 @@
      */
     public function UnaryCall(\Grpc\Testing\SimpleRequest $argument,
       $metadata = [], $options = []) {
-      return $this->_simpleRequest('/grpc.testing.BenchmarkService/UnaryCall',
-      $argument,
-      ['\Grpc\Testing\SimpleResponse', 'decode'],
-      $metadata, $options);
+        return $this->_simpleRequest('/grpc.testing.BenchmarkService/UnaryCall',
+        $argument,
+        ['\Grpc\Testing\SimpleResponse', 'decode'],
+        $metadata, $options);
     }
 
     /**
-     * One request followed by one response.
-     * The server returns the client payload as-is.
+     * Repeated sequence of one request followed by one response.
+     * Should be called streaming ping-pong
+     * The server returns the client payload as-is on each response
      * @param array $metadata metadata
      * @param array $options call options
      */
     public function StreamingCall($metadata = [], $options = []) {
-      return $this->_bidiRequest('/grpc.testing.BenchmarkService/StreamingCall',
-      ['\Grpc\Testing\SimpleResponse','decode'],
-      $metadata, $options);
+        return $this->_bidiRequest('/grpc.testing.BenchmarkService/StreamingCall',
+        ['\Grpc\Testing\SimpleResponse','decode'],
+        $metadata, $options);
     }
 
-  }
+    /**
+     * Single-sided unbounded streaming from client to server
+     * The server returns the client payload as-is once the client does WritesDone
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function StreamingFromClient($metadata = [], $options = []) {
+        return $this->_clientStreamRequest('/grpc.testing.BenchmarkService/StreamingFromClient',
+        ['\Grpc\Testing\SimpleResponse','decode'],
+        $metadata, $options);
+    }
+
+    /**
+     * Single-sided unbounded streaming from server to client
+     * The server repeatedly returns the client payload as-is
+     * @param \Grpc\Testing\SimpleRequest $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function StreamingFromServer(\Grpc\Testing\SimpleRequest $argument,
+      $metadata = [], $options = []) {
+        return $this->_serverStreamRequest('/grpc.testing.BenchmarkService/StreamingFromServer',
+        $argument,
+        ['\Grpc\Testing\SimpleResponse', 'decode'],
+        $metadata, $options);
+    }
+
+    /**
+     * Two-sided unbounded streaming between server to client
+     * Both sides send the content of their own choice to the other
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function StreamingBothWays($metadata = [], $options = []) {
+        return $this->_bidiRequest('/grpc.testing.BenchmarkService/StreamingBothWays',
+        ['\Grpc\Testing\SimpleResponse','decode'],
+        $metadata, $options);
+    }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php b/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php
index f0497ac..7eb364b 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/BoolValue.php
@@ -9,22 +9,18 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * TODO(dgq): Go back to using well-known types once
  * https://github.com/grpc/grpc/issues/6980 has been fixed.
  * import "google/protobuf/wrappers.proto";
- * </pre>
  *
- * Protobuf type <code>grpc.testing.BoolValue</code>
+ * Generated from protobuf message <code>grpc.testing.BoolValue</code>
  */
 class BoolValue extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * The bool value.
-     * </pre>
      *
-     * <code>bool value = 1;</code>
+     * Generated from protobuf field <code>bool value = 1;</code>
      */
     private $value = false;
 
@@ -34,11 +30,10 @@
     }
 
     /**
-     * <pre>
      * The bool value.
-     * </pre>
      *
-     * <code>bool value = 1;</code>
+     * Generated from protobuf field <code>bool value = 1;</code>
+     * @return bool
      */
     public function getValue()
     {
@@ -46,16 +41,18 @@
     }
 
     /**
-     * <pre>
      * The bool value.
-     * </pre>
      *
-     * <code>bool value = 1;</code>
+     * Generated from protobuf field <code>bool value = 1;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setValue($var)
     {
         GPBUtil::checkBool($var);
         $this->value = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php
index 0057d38..0511026 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ByteBufferParams.php
@@ -9,16 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ByteBufferParams</code>
+ * Generated from protobuf message <code>grpc.testing.ByteBufferParams</code>
  */
 class ByteBufferParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
      */
     private $req_size = 0;
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
      */
     private $resp_size = 0;
 
@@ -28,7 +28,8 @@
     }
 
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
+     * @return int
      */
     public function getReqSize()
     {
@@ -36,16 +37,21 @@
     }
 
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setReqSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->req_size = $var;
+
+        return $this;
     }
 
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
+     * @return int
      */
     public function getRespSize()
     {
@@ -53,12 +59,16 @@
     }
 
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setRespSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->resp_size = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php b/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php
index d2fe3ae..5c5fb86 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ChannelArg.php
@@ -9,12 +9,12 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ChannelArg</code>
+ * Generated from protobuf message <code>grpc.testing.ChannelArg</code>
  */
 class ChannelArg extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
      */
     private $name = '';
     protected $value;
@@ -25,7 +25,8 @@
     }
 
     /**
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @return string
      */
     public function getName()
     {
@@ -33,16 +34,21 @@
     }
 
     /**
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @param string $var
+     * @return $this
      */
     public function setName($var)
     {
         GPBUtil::checkString($var, True);
         $this->name = $var;
+
+        return $this;
     }
 
     /**
-     * <code>string str_value = 2;</code>
+     * Generated from protobuf field <code>string str_value = 2;</code>
+     * @return string
      */
     public function getStrValue()
     {
@@ -50,16 +56,21 @@
     }
 
     /**
-     * <code>string str_value = 2;</code>
+     * Generated from protobuf field <code>string str_value = 2;</code>
+     * @param string $var
+     * @return $this
      */
     public function setStrValue($var)
     {
         GPBUtil::checkString($var, True);
         $this->writeOneof(2, $var);
+
+        return $this;
     }
 
     /**
-     * <code>int32 int_value = 3;</code>
+     * Generated from protobuf field <code>int32 int_value = 3;</code>
+     * @return int
      */
     public function getIntValue()
     {
@@ -67,14 +78,21 @@
     }
 
     /**
-     * <code>int32 int_value = 3;</code>
+     * Generated from protobuf field <code>int32 int_value = 3;</code>
+     * @param int $var
+     * @return $this
      */
     public function setIntValue($var)
     {
         GPBUtil::checkInt32($var);
         $this->writeOneof(3, $var);
+
+        return $this;
     }
 
+    /**
+     * @return string
+     */
     public function getValue()
     {
         return $this->whichOneof("value");
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php
index c878c5a..ee3fd46 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientArgs.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ClientArgs</code>
+ * Generated from protobuf message <code>grpc.testing.ClientArgs</code>
  */
 class ClientArgs extends \Google\Protobuf\Internal\Message
 {
@@ -21,7 +21,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ClientConfig setup = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientConfig setup = 1;</code>
+     * @return \Grpc\Testing\ClientConfig
      */
     public function getSetup()
     {
@@ -29,16 +30,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ClientConfig setup = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientConfig setup = 1;</code>
+     * @param \Grpc\Testing\ClientConfig $var
+     * @return $this
      */
-    public function setSetup(&$var)
+    public function setSetup($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ClientConfig::class);
         $this->writeOneof(1, $var);
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.Mark mark = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.Mark mark = 2;</code>
+     * @return \Grpc\Testing\Mark
      */
     public function getMark()
     {
@@ -46,14 +52,21 @@
     }
 
     /**
-     * <code>.grpc.testing.Mark mark = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.Mark mark = 2;</code>
+     * @param \Grpc\Testing\Mark $var
+     * @return $this
      */
-    public function setMark(&$var)
+    public function setMark($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Mark::class);
         $this->writeOneof(2, $var);
+
+        return $this;
     }
 
+    /**
+     * @return string
+     */
     public function getArgtype()
     {
         return $this->whichOneof("argtype");
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php
index 52d6a75..f7bc215 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientConfig.php
@@ -9,96 +9,94 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ClientConfig</code>
+ * Generated from protobuf message <code>grpc.testing.ClientConfig</code>
  */
 class ClientConfig extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * List of targets to connect to. At least one target needs to be specified.
-     * </pre>
      *
-     * <code>repeated string server_targets = 1;</code>
+     * Generated from protobuf field <code>repeated string server_targets = 1;</code>
      */
     private $server_targets;
     /**
-     * <code>.grpc.testing.ClientType client_type = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientType client_type = 2;</code>
      */
     private $client_type = 0;
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 3;</code>
      */
     private $security_params = null;
     /**
-     * <pre>
      * How many concurrent RPCs to start for each channel.
      * For synchronous client, use a separate thread for each outstanding RPC.
-     * </pre>
      *
-     * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+     * Generated from protobuf field <code>int32 outstanding_rpcs_per_channel = 4;</code>
      */
     private $outstanding_rpcs_per_channel = 0;
     /**
-     * <pre>
      * Number of independent client channels to create.
      * i-th channel will connect to server_target[i % server_targets.size()]
-     * </pre>
      *
-     * <code>int32 client_channels = 5;</code>
+     * Generated from protobuf field <code>int32 client_channels = 5;</code>
      */
     private $client_channels = 0;
     /**
-     * <pre>
      * Only for async client. Number of threads to use to start/manage RPCs.
-     * </pre>
      *
-     * <code>int32 async_client_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_client_threads = 7;</code>
      */
     private $async_client_threads = 0;
     /**
-     * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.RpcType rpc_type = 8;</code>
      */
     private $rpc_type = 0;
     /**
-     * <pre>
      * The requested load for the entire client (aggregated over all the threads).
-     * </pre>
      *
-     * <code>.grpc.testing.LoadParams load_params = 10;</code>
+     * Generated from protobuf field <code>.grpc.testing.LoadParams load_params = 10;</code>
      */
     private $load_params = null;
     /**
-     * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
      */
     private $payload_config = null;
     /**
-     * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
      */
     private $histogram_params = null;
     /**
-     * <pre>
      * Specify the cores we should run the client on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 13;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 13;</code>
      */
     private $core_list;
     /**
-     * <code>int32 core_limit = 14;</code>
+     * Generated from protobuf field <code>int32 core_limit = 14;</code>
      */
     private $core_limit = 0;
     /**
-     * <pre>
      * If we use an OTHER_CLIENT client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_client_api = 15;</code>
+     * Generated from protobuf field <code>string other_client_api = 15;</code>
      */
     private $other_client_api = '';
     /**
-     * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
      */
     private $channel_args;
+    /**
+     * Number of threads that share each completion queue
+     *
+     * Generated from protobuf field <code>int32 threads_per_cq = 17;</code>
+     */
+    private $threads_per_cq = 0;
+    /**
+     * Number of messages on a stream before it gets finished/restarted
+     *
+     * Generated from protobuf field <code>int32 messages_per_stream = 18;</code>
+     */
+    private $messages_per_stream = 0;
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
@@ -106,11 +104,10 @@
     }
 
     /**
-     * <pre>
      * List of targets to connect to. At least one target needs to be specified.
-     * </pre>
      *
-     * <code>repeated string server_targets = 1;</code>
+     * Generated from protobuf field <code>repeated string server_targets = 1;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getServerTargets()
     {
@@ -118,20 +115,23 @@
     }
 
     /**
-     * <pre>
      * List of targets to connect to. At least one target needs to be specified.
-     * </pre>
      *
-     * <code>repeated string server_targets = 1;</code>
+     * Generated from protobuf field <code>repeated string server_targets = 1;</code>
+     * @param string[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setServerTargets(&$var)
+    public function setServerTargets($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING);
-        $this->server_targets = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING);
+        $this->server_targets = $arr;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.ClientType client_type = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientType client_type = 2;</code>
+     * @return int
      */
     public function getClientType()
     {
@@ -139,16 +139,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ClientType client_type = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientType client_type = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setClientType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\ClientType::class);
         $this->client_type = $var;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 3;</code>
+     * @return \Grpc\Testing\SecurityParams
      */
     public function getSecurityParams()
     {
@@ -156,21 +161,24 @@
     }
 
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 3;</code>
+     * @param \Grpc\Testing\SecurityParams $var
+     * @return $this
      */
-    public function setSecurityParams(&$var)
+    public function setSecurityParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\SecurityParams::class);
         $this->security_params = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * How many concurrent RPCs to start for each channel.
      * For synchronous client, use a separate thread for each outstanding RPC.
-     * </pre>
      *
-     * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+     * Generated from protobuf field <code>int32 outstanding_rpcs_per_channel = 4;</code>
+     * @return int
      */
     public function getOutstandingRpcsPerChannel()
     {
@@ -178,26 +186,27 @@
     }
 
     /**
-     * <pre>
      * How many concurrent RPCs to start for each channel.
      * For synchronous client, use a separate thread for each outstanding RPC.
-     * </pre>
      *
-     * <code>int32 outstanding_rpcs_per_channel = 4;</code>
+     * Generated from protobuf field <code>int32 outstanding_rpcs_per_channel = 4;</code>
+     * @param int $var
+     * @return $this
      */
     public function setOutstandingRpcsPerChannel($var)
     {
         GPBUtil::checkInt32($var);
         $this->outstanding_rpcs_per_channel = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of independent client channels to create.
      * i-th channel will connect to server_target[i % server_targets.size()]
-     * </pre>
      *
-     * <code>int32 client_channels = 5;</code>
+     * Generated from protobuf field <code>int32 client_channels = 5;</code>
+     * @return int
      */
     public function getClientChannels()
     {
@@ -205,25 +214,26 @@
     }
 
     /**
-     * <pre>
      * Number of independent client channels to create.
      * i-th channel will connect to server_target[i % server_targets.size()]
-     * </pre>
      *
-     * <code>int32 client_channels = 5;</code>
+     * Generated from protobuf field <code>int32 client_channels = 5;</code>
+     * @param int $var
+     * @return $this
      */
     public function setClientChannels($var)
     {
         GPBUtil::checkInt32($var);
         $this->client_channels = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Only for async client. Number of threads to use to start/manage RPCs.
-     * </pre>
      *
-     * <code>int32 async_client_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_client_threads = 7;</code>
+     * @return int
      */
     public function getAsyncClientThreads()
     {
@@ -231,20 +241,23 @@
     }
 
     /**
-     * <pre>
      * Only for async client. Number of threads to use to start/manage RPCs.
-     * </pre>
      *
-     * <code>int32 async_client_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_client_threads = 7;</code>
+     * @param int $var
+     * @return $this
      */
     public function setAsyncClientThreads($var)
     {
         GPBUtil::checkInt32($var);
         $this->async_client_threads = $var;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.RpcType rpc_type = 8;</code>
+     * @return int
      */
     public function getRpcType()
     {
@@ -252,20 +265,23 @@
     }
 
     /**
-     * <code>.grpc.testing.RpcType rpc_type = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.RpcType rpc_type = 8;</code>
+     * @param int $var
+     * @return $this
      */
     public function setRpcType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\RpcType::class);
         $this->rpc_type = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * The requested load for the entire client (aggregated over all the threads).
-     * </pre>
      *
-     * <code>.grpc.testing.LoadParams load_params = 10;</code>
+     * Generated from protobuf field <code>.grpc.testing.LoadParams load_params = 10;</code>
+     * @return \Grpc\Testing\LoadParams
      */
     public function getLoadParams()
     {
@@ -273,20 +289,23 @@
     }
 
     /**
-     * <pre>
      * The requested load for the entire client (aggregated over all the threads).
-     * </pre>
      *
-     * <code>.grpc.testing.LoadParams load_params = 10;</code>
+     * Generated from protobuf field <code>.grpc.testing.LoadParams load_params = 10;</code>
+     * @param \Grpc\Testing\LoadParams $var
+     * @return $this
      */
-    public function setLoadParams(&$var)
+    public function setLoadParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\LoadParams::class);
         $this->load_params = $var;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+     * @return \Grpc\Testing\PayloadConfig
      */
     public function getPayloadConfig()
     {
@@ -294,16 +313,21 @@
     }
 
     /**
-     * <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 11;</code>
+     * @param \Grpc\Testing\PayloadConfig $var
+     * @return $this
      */
-    public function setPayloadConfig(&$var)
+    public function setPayloadConfig($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\PayloadConfig::class);
         $this->payload_config = $var;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+     * @return \Grpc\Testing\HistogramParams
      */
     public function getHistogramParams()
     {
@@ -311,20 +335,23 @@
     }
 
     /**
-     * <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramParams histogram_params = 12;</code>
+     * @param \Grpc\Testing\HistogramParams $var
+     * @return $this
      */
-    public function setHistogramParams(&$var)
+    public function setHistogramParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\HistogramParams::class);
         $this->histogram_params = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Specify the cores we should run the client on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 13;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 13;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getCoreList()
     {
@@ -332,20 +359,23 @@
     }
 
     /**
-     * <pre>
      * Specify the cores we should run the client on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 13;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 13;</code>
+     * @param int[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setCoreList(&$var)
+    public function setCoreList($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
-        $this->core_list = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+        $this->core_list = $arr;
+
+        return $this;
     }
 
     /**
-     * <code>int32 core_limit = 14;</code>
+     * Generated from protobuf field <code>int32 core_limit = 14;</code>
+     * @return int
      */
     public function getCoreLimit()
     {
@@ -353,20 +383,23 @@
     }
 
     /**
-     * <code>int32 core_limit = 14;</code>
+     * Generated from protobuf field <code>int32 core_limit = 14;</code>
+     * @param int $var
+     * @return $this
      */
     public function setCoreLimit($var)
     {
         GPBUtil::checkInt32($var);
         $this->core_limit = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * If we use an OTHER_CLIENT client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_client_api = 15;</code>
+     * Generated from protobuf field <code>string other_client_api = 15;</code>
+     * @return string
      */
     public function getOtherClientApi()
     {
@@ -374,20 +407,23 @@
     }
 
     /**
-     * <pre>
      * If we use an OTHER_CLIENT client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_client_api = 15;</code>
+     * Generated from protobuf field <code>string other_client_api = 15;</code>
+     * @param string $var
+     * @return $this
      */
     public function setOtherClientApi($var)
     {
         GPBUtil::checkString($var, True);
         $this->other_client_api = $var;
+
+        return $this;
     }
 
     /**
-     * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getChannelArgs()
     {
@@ -395,12 +431,68 @@
     }
 
     /**
-     * <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 16;</code>
+     * @param \Grpc\Testing\ChannelArg[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setChannelArgs(&$var)
+    public function setChannelArgs($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ChannelArg::class);
-        $this->channel_args = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ChannelArg::class);
+        $this->channel_args = $arr;
+
+        return $this;
+    }
+
+    /**
+     * Number of threads that share each completion queue
+     *
+     * Generated from protobuf field <code>int32 threads_per_cq = 17;</code>
+     * @return int
+     */
+    public function getThreadsPerCq()
+    {
+        return $this->threads_per_cq;
+    }
+
+    /**
+     * Number of threads that share each completion queue
+     *
+     * Generated from protobuf field <code>int32 threads_per_cq = 17;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setThreadsPerCq($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->threads_per_cq = $var;
+
+        return $this;
+    }
+
+    /**
+     * Number of messages on a stream before it gets finished/restarted
+     *
+     * Generated from protobuf field <code>int32 messages_per_stream = 18;</code>
+     * @return int
+     */
+    public function getMessagesPerStream()
+    {
+        return $this->messages_per_stream;
+    }
+
+    /**
+     * Number of messages on a stream before it gets finished/restarted
+     *
+     * Generated from protobuf field <code>int32 messages_per_stream = 18;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setMessagesPerStream($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->messages_per_stream = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php
index 8b9a0c3..f2a7621 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStats.php
@@ -9,42 +9,48 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ClientStats</code>
+ * Generated from protobuf message <code>grpc.testing.ClientStats</code>
  */
 class ClientStats extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Latency histogram. Data points are in nanoseconds.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 1;</code>
      */
     private $latencies = null;
     /**
-     * <pre>
      * See ServerStats for details.
-     * </pre>
      *
-     * <code>double time_elapsed = 2;</code>
+     * Generated from protobuf field <code>double time_elapsed = 2;</code>
      */
     private $time_elapsed = 0.0;
     /**
-     * <code>double time_user = 3;</code>
+     * Generated from protobuf field <code>double time_user = 3;</code>
      */
     private $time_user = 0.0;
     /**
-     * <code>double time_system = 4;</code>
+     * Generated from protobuf field <code>double time_system = 4;</code>
      */
     private $time_system = 0.0;
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
      */
     private $request_results;
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     */
+    private $cq_poll_count = 0;
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     */
+    private $core_stats = null;
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
@@ -52,11 +58,10 @@
     }
 
     /**
-     * <pre>
      * Latency histogram. Data points are in nanoseconds.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 1;</code>
+     * @return \Grpc\Testing\HistogramData
      */
     public function getLatencies()
     {
@@ -64,24 +69,25 @@
     }
 
     /**
-     * <pre>
      * Latency histogram. Data points are in nanoseconds.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 1;</code>
+     * @param \Grpc\Testing\HistogramData $var
+     * @return $this
      */
-    public function setLatencies(&$var)
+    public function setLatencies($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\HistogramData::class);
         $this->latencies = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * See ServerStats for details.
-     * </pre>
      *
-     * <code>double time_elapsed = 2;</code>
+     * Generated from protobuf field <code>double time_elapsed = 2;</code>
+     * @return float
      */
     public function getTimeElapsed()
     {
@@ -89,20 +95,23 @@
     }
 
     /**
-     * <pre>
      * See ServerStats for details.
-     * </pre>
      *
-     * <code>double time_elapsed = 2;</code>
+     * Generated from protobuf field <code>double time_elapsed = 2;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeElapsed($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_elapsed = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double time_user = 3;</code>
+     * Generated from protobuf field <code>double time_user = 3;</code>
+     * @return float
      */
     public function getTimeUser()
     {
@@ -110,16 +119,21 @@
     }
 
     /**
-     * <code>double time_user = 3;</code>
+     * Generated from protobuf field <code>double time_user = 3;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeUser($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_user = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double time_system = 4;</code>
+     * Generated from protobuf field <code>double time_system = 4;</code>
+     * @return float
      */
     public function getTimeSystem()
     {
@@ -127,20 +141,23 @@
     }
 
     /**
-     * <code>double time_system = 4;</code>
+     * Generated from protobuf field <code>double time_system = 4;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeSystem($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_system = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getRequestResults()
     {
@@ -148,16 +165,70 @@
     }
 
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 5;</code>
+     * @param \Grpc\Testing\RequestResultCount[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setRequestResults(&$var)
+    public function setRequestResults($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
-        $this->request_results = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
+        $this->request_results = $arr;
+
+        return $this;
+    }
+
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     * @return int|string
+     */
+    public function getCqPollCount()
+    {
+        return $this->cq_poll_count;
+    }
+
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     * @param int|string $var
+     * @return $this
+     */
+    public function setCqPollCount($var)
+    {
+        GPBUtil::checkUint64($var);
+        $this->cq_poll_count = $var;
+
+        return $this;
+    }
+
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     * @return \Grpc\Core\Stats
+     */
+    public function getCoreStats()
+    {
+        return $this->core_stats;
+    }
+
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     * @param \Grpc\Core\Stats $var
+     * @return $this
+     */
+    public function setCoreStats($var)
+    {
+        GPBUtil::checkMessage($var, \Grpc\Core\Stats::class);
+        $this->core_stats = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php
index a59f87a..3ea40c4 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientStatus.php
@@ -9,12 +9,12 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ClientStatus</code>
+ * Generated from protobuf message <code>grpc.testing.ClientStatus</code>
  */
 class ClientStatus extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>.grpc.testing.ClientStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientStats stats = 1;</code>
      */
     private $stats = null;
 
@@ -24,7 +24,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ClientStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientStats stats = 1;</code>
+     * @return \Grpc\Testing\ClientStats
      */
     public function getStats()
     {
@@ -32,12 +33,16 @@
     }
 
     /**
-     * <code>.grpc.testing.ClientStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientStats stats = 1;</code>
+     * @param \Grpc\Testing\ClientStats $var
+     * @return $this
      */
-    public function setStats(&$var)
+    public function setStats($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ClientStats::class);
         $this->stats = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php
index 4f59da9..d1df4f1 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClientType.php
@@ -5,29 +5,25 @@
 namespace Grpc\Testing;
 
 /**
- * Protobuf enum <code>grpc.testing.ClientType</code>
+ * Protobuf enum <code>Grpc\Testing\ClientType</code>
  */
 class ClientType
 {
     /**
-     * <pre>
      * Many languages support a basic distinction between using
      * sync or async client, and this allows the specification
-     * </pre>
      *
-     * <code>SYNC_CLIENT = 0;</code>
+     * Generated from protobuf enum <code>SYNC_CLIENT = 0;</code>
      */
     const SYNC_CLIENT = 0;
     /**
-     * <code>ASYNC_CLIENT = 1;</code>
+     * Generated from protobuf enum <code>ASYNC_CLIENT = 1;</code>
      */
     const ASYNC_CLIENT = 1;
     /**
-     * <pre>
      * used for some language-specific variants
-     * </pre>
      *
-     * <code>OTHER_CLIENT = 2;</code>
+     * Generated from protobuf enum <code>OTHER_CLIENT = 2;</code>
      */
     const OTHER_CLIENT = 2;
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php
index 53f2948..2772836 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ClosedLoopParams.php
@@ -9,12 +9,10 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Once an RPC finishes, immediately start a new one.
  * No configuration parameters needed.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ClosedLoopParams</code>
+ * Generated from protobuf message <code>grpc.testing.ClosedLoopParams</code>
  */
 class ClosedLoopParams extends \Google\Protobuf\Internal\Message
 {
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php
index 6d990f1..b9013cd 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ComplexProtoParams.php
@@ -9,12 +9,10 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * TODO (vpai): Fill this in once the details of complex, representative
  *              protos are decided
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ComplexProtoParams</code>
+ * Generated from protobuf message <code>grpc.testing.ComplexProtoParams</code>
  */
 class ComplexProtoParams extends \Google\Protobuf\Internal\Message
 {
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php
index 2e078b3..7772572 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/CoreRequest.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.CoreRequest</code>
+ * Generated from protobuf message <code>grpc.testing.CoreRequest</code>
  */
 class CoreRequest extends \Google\Protobuf\Internal\Message
 {
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php
index 85cb341..e0b40ee 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/CoreResponse.php
@@ -9,16 +9,14 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.CoreResponse</code>
+ * Generated from protobuf message <code>grpc.testing.CoreResponse</code>
  */
 class CoreResponse extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Number of cores available on the server
-     * </pre>
      *
-     * <code>int32 cores = 1;</code>
+     * Generated from protobuf field <code>int32 cores = 1;</code>
      */
     private $cores = 0;
 
@@ -28,11 +26,10 @@
     }
 
     /**
-     * <pre>
      * Number of cores available on the server
-     * </pre>
      *
-     * <code>int32 cores = 1;</code>
+     * Generated from protobuf field <code>int32 cores = 1;</code>
+     * @return int
      */
     public function getCores()
     {
@@ -40,16 +37,18 @@
     }
 
     /**
-     * <pre>
      * Number of cores available on the server
-     * </pre>
      *
-     * <code>int32 cores = 1;</code>
+     * Generated from protobuf field <code>int32 cores = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setCores($var)
     {
         GPBUtil::checkInt32($var);
         $this->cores = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php
index 27340fb..6a6623a 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/EchoStatus.php
@@ -9,21 +9,19 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * A protobuf representation for grpc status. This is used by test
  * clients to specify a status that the server should attempt to return.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.EchoStatus</code>
+ * Generated from protobuf message <code>grpc.testing.EchoStatus</code>
  */
 class EchoStatus extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>int32 code = 1;</code>
+     * Generated from protobuf field <code>int32 code = 1;</code>
      */
     private $code = 0;
     /**
-     * <code>string message = 2;</code>
+     * Generated from protobuf field <code>string message = 2;</code>
      */
     private $message = '';
 
@@ -33,7 +31,8 @@
     }
 
     /**
-     * <code>int32 code = 1;</code>
+     * Generated from protobuf field <code>int32 code = 1;</code>
+     * @return int
      */
     public function getCode()
     {
@@ -41,16 +40,21 @@
     }
 
     /**
-     * <code>int32 code = 1;</code>
+     * Generated from protobuf field <code>int32 code = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setCode($var)
     {
         GPBUtil::checkInt32($var);
         $this->code = $var;
+
+        return $this;
     }
 
     /**
-     * <code>string message = 2;</code>
+     * Generated from protobuf field <code>string message = 2;</code>
+     * @return string
      */
     public function getMessage()
     {
@@ -58,12 +62,16 @@
     }
 
     /**
-     * <code>string message = 2;</code>
+     * Generated from protobuf field <code>string message = 2;</code>
+     * @param string $var
+     * @return $this
      */
     public function setMessage($var)
     {
         GPBUtil::checkString($var, True);
         $this->message = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php
index 056da6e..136eac7 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramData.php
@@ -9,36 +9,34 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Histogram data based on grpc/support/histogram.c
- * </pre>
  *
- * Protobuf type <code>grpc.testing.HistogramData</code>
+ * Generated from protobuf message <code>grpc.testing.HistogramData</code>
  */
 class HistogramData extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>repeated uint32 bucket = 1;</code>
+     * Generated from protobuf field <code>repeated uint32 bucket = 1;</code>
      */
     private $bucket;
     /**
-     * <code>double min_seen = 2;</code>
+     * Generated from protobuf field <code>double min_seen = 2;</code>
      */
     private $min_seen = 0.0;
     /**
-     * <code>double max_seen = 3;</code>
+     * Generated from protobuf field <code>double max_seen = 3;</code>
      */
     private $max_seen = 0.0;
     /**
-     * <code>double sum = 4;</code>
+     * Generated from protobuf field <code>double sum = 4;</code>
      */
     private $sum = 0.0;
     /**
-     * <code>double sum_of_squares = 5;</code>
+     * Generated from protobuf field <code>double sum_of_squares = 5;</code>
      */
     private $sum_of_squares = 0.0;
     /**
-     * <code>double count = 6;</code>
+     * Generated from protobuf field <code>double count = 6;</code>
      */
     private $count = 0.0;
 
@@ -48,7 +46,8 @@
     }
 
     /**
-     * <code>repeated uint32 bucket = 1;</code>
+     * Generated from protobuf field <code>repeated uint32 bucket = 1;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getBucket()
     {
@@ -56,16 +55,21 @@
     }
 
     /**
-     * <code>repeated uint32 bucket = 1;</code>
+     * Generated from protobuf field <code>repeated uint32 bucket = 1;</code>
+     * @param int[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setBucket(&$var)
+    public function setBucket($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::UINT32);
-        $this->bucket = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::UINT32);
+        $this->bucket = $arr;
+
+        return $this;
     }
 
     /**
-     * <code>double min_seen = 2;</code>
+     * Generated from protobuf field <code>double min_seen = 2;</code>
+     * @return float
      */
     public function getMinSeen()
     {
@@ -73,16 +77,21 @@
     }
 
     /**
-     * <code>double min_seen = 2;</code>
+     * Generated from protobuf field <code>double min_seen = 2;</code>
+     * @param float $var
+     * @return $this
      */
     public function setMinSeen($var)
     {
         GPBUtil::checkDouble($var);
         $this->min_seen = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double max_seen = 3;</code>
+     * Generated from protobuf field <code>double max_seen = 3;</code>
+     * @return float
      */
     public function getMaxSeen()
     {
@@ -90,16 +99,21 @@
     }
 
     /**
-     * <code>double max_seen = 3;</code>
+     * Generated from protobuf field <code>double max_seen = 3;</code>
+     * @param float $var
+     * @return $this
      */
     public function setMaxSeen($var)
     {
         GPBUtil::checkDouble($var);
         $this->max_seen = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double sum = 4;</code>
+     * Generated from protobuf field <code>double sum = 4;</code>
+     * @return float
      */
     public function getSum()
     {
@@ -107,16 +121,21 @@
     }
 
     /**
-     * <code>double sum = 4;</code>
+     * Generated from protobuf field <code>double sum = 4;</code>
+     * @param float $var
+     * @return $this
      */
     public function setSum($var)
     {
         GPBUtil::checkDouble($var);
         $this->sum = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double sum_of_squares = 5;</code>
+     * Generated from protobuf field <code>double sum_of_squares = 5;</code>
+     * @return float
      */
     public function getSumOfSquares()
     {
@@ -124,16 +143,21 @@
     }
 
     /**
-     * <code>double sum_of_squares = 5;</code>
+     * Generated from protobuf field <code>double sum_of_squares = 5;</code>
+     * @param float $var
+     * @return $this
      */
     public function setSumOfSquares($var)
     {
         GPBUtil::checkDouble($var);
         $this->sum_of_squares = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double count = 6;</code>
+     * Generated from protobuf field <code>double count = 6;</code>
+     * @return float
      */
     public function getCount()
     {
@@ -141,12 +165,16 @@
     }
 
     /**
-     * <code>double count = 6;</code>
+     * Generated from protobuf field <code>double count = 6;</code>
+     * @param float $var
+     * @return $this
      */
     public function setCount($var)
     {
         GPBUtil::checkDouble($var);
         $this->count = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php
index 836c94b..1a1b484 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/HistogramParams.php
@@ -9,28 +9,22 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Histogram params based on grpc/support/histogram.c
- * </pre>
  *
- * Protobuf type <code>grpc.testing.HistogramParams</code>
+ * Generated from protobuf message <code>grpc.testing.HistogramParams</code>
  */
 class HistogramParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * first bucket is [0, 1 + resolution)
-     * </pre>
      *
-     * <code>double resolution = 1;</code>
+     * Generated from protobuf field <code>double resolution = 1;</code>
      */
     private $resolution = 0.0;
     /**
-     * <pre>
      * use enough buckets to allow this value
-     * </pre>
      *
-     * <code>double max_possible = 2;</code>
+     * Generated from protobuf field <code>double max_possible = 2;</code>
      */
     private $max_possible = 0.0;
 
@@ -40,11 +34,10 @@
     }
 
     /**
-     * <pre>
      * first bucket is [0, 1 + resolution)
-     * </pre>
      *
-     * <code>double resolution = 1;</code>
+     * Generated from protobuf field <code>double resolution = 1;</code>
+     * @return float
      */
     public function getResolution()
     {
@@ -52,24 +45,25 @@
     }
 
     /**
-     * <pre>
      * first bucket is [0, 1 + resolution)
-     * </pre>
      *
-     * <code>double resolution = 1;</code>
+     * Generated from protobuf field <code>double resolution = 1;</code>
+     * @param float $var
+     * @return $this
      */
     public function setResolution($var)
     {
         GPBUtil::checkDouble($var);
         $this->resolution = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * use enough buckets to allow this value
-     * </pre>
      *
-     * <code>double max_possible = 2;</code>
+     * Generated from protobuf field <code>double max_possible = 2;</code>
+     * @return float
      */
     public function getMaxPossible()
     {
@@ -77,16 +71,18 @@
     }
 
     /**
-     * <pre>
      * use enough buckets to allow this value
-     * </pre>
      *
-     * <code>double max_possible = 2;</code>
+     * Generated from protobuf field <code>double max_possible = 2;</code>
+     * @param float $var
+     * @return $this
      */
     public function setMaxPossible($var)
     {
         GPBUtil::checkDouble($var);
         $this->max_possible = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php
index 1f32e49..04c345f 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/LoadParams.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.LoadParams</code>
+ * Generated from protobuf message <code>grpc.testing.LoadParams</code>
  */
 class LoadParams extends \Google\Protobuf\Internal\Message
 {
@@ -21,7 +21,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+     * @return \Grpc\Testing\ClosedLoopParams
      */
     public function getClosedLoop()
     {
@@ -29,16 +30,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClosedLoopParams closed_loop = 1;</code>
+     * @param \Grpc\Testing\ClosedLoopParams $var
+     * @return $this
      */
-    public function setClosedLoop(&$var)
+    public function setClosedLoop($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ClosedLoopParams::class);
         $this->writeOneof(1, $var);
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.PoissonParams poisson = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.PoissonParams poisson = 2;</code>
+     * @return \Grpc\Testing\PoissonParams
      */
     public function getPoisson()
     {
@@ -46,14 +52,21 @@
     }
 
     /**
-     * <code>.grpc.testing.PoissonParams poisson = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.PoissonParams poisson = 2;</code>
+     * @param \Grpc\Testing\PoissonParams $var
+     * @return $this
      */
-    public function setPoisson(&$var)
+    public function setPoisson($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\PoissonParams::class);
         $this->writeOneof(2, $var);
+
+        return $this;
     }
 
+    /**
+     * @return string
+     */
     public function getLoad()
     {
         return $this->whichOneof("load");
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php b/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php
index ce006ef..be058d5 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Mark.php
@@ -9,20 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Request current stats
- * </pre>
  *
- * Protobuf type <code>grpc.testing.Mark</code>
+ * Generated from protobuf message <code>grpc.testing.Mark</code>
  */
 class Mark extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * if true, the stats will be reset after taking their snapshot.
-     * </pre>
      *
-     * <code>bool reset = 1;</code>
+     * Generated from protobuf field <code>bool reset = 1;</code>
      */
     private $reset = false;
 
@@ -32,11 +28,10 @@
     }
 
     /**
-     * <pre>
      * if true, the stats will be reset after taking their snapshot.
-     * </pre>
      *
-     * <code>bool reset = 1;</code>
+     * Generated from protobuf field <code>bool reset = 1;</code>
+     * @return bool
      */
     public function getReset()
     {
@@ -44,16 +39,18 @@
     }
 
     /**
-     * <pre>
      * if true, the stats will be reset after taking their snapshot.
-     * </pre>
      *
-     * <code>bool reset = 1;</code>
+     * Generated from protobuf field <code>bool reset = 1;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setReset($var)
     {
         GPBUtil::checkBool($var);
         $this->reset = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php b/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php
index d17c271..ad97890 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Payload.php
@@ -9,29 +9,23 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * A block of data, to simply increase gRPC message size.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.Payload</code>
+ * Generated from protobuf message <code>grpc.testing.Payload</code>
  */
 class Payload extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * The type of data in body.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType type = 1;</code>
      */
     private $type = 0;
     /**
-     * <pre>
      * Primary contents of payload.
-     * </pre>
      *
-     * <code>bytes body = 2;</code>
+     * Generated from protobuf field <code>bytes body = 2;</code>
      */
     private $body = '';
 
@@ -41,12 +35,11 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * The type of data in body.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType type = 1;</code>
+     * @return int
      */
     public function getType()
     {
@@ -54,25 +47,26 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * The type of data in body.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType type = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
         $this->type = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Primary contents of payload.
-     * </pre>
      *
-     * <code>bytes body = 2;</code>
+     * Generated from protobuf field <code>bytes body = 2;</code>
+     * @return string
      */
     public function getBody()
     {
@@ -80,16 +74,18 @@
     }
 
     /**
-     * <pre>
      * Primary contents of payload.
-     * </pre>
      *
-     * <code>bytes body = 2;</code>
+     * Generated from protobuf field <code>bytes body = 2;</code>
+     * @param string $var
+     * @return $this
      */
     public function setBody($var)
     {
         GPBUtil::checkString($var, False);
         $this->body = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php
index a2fe710..748f52d 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadConfig.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.PayloadConfig</code>
+ * Generated from protobuf message <code>grpc.testing.PayloadConfig</code>
  */
 class PayloadConfig extends \Google\Protobuf\Internal\Message
 {
@@ -21,7 +21,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+     * @return \Grpc\Testing\ByteBufferParams
      */
     public function getBytebufParams()
     {
@@ -29,16 +30,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ByteBufferParams bytebuf_params = 1;</code>
+     * @param \Grpc\Testing\ByteBufferParams $var
+     * @return $this
      */
-    public function setBytebufParams(&$var)
+    public function setBytebufParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ByteBufferParams::class);
         $this->writeOneof(1, $var);
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+     * @return \Grpc\Testing\SimpleProtoParams
      */
     public function getSimpleParams()
     {
@@ -46,16 +52,21 @@
     }
 
     /**
-     * <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.SimpleProtoParams simple_params = 2;</code>
+     * @param \Grpc\Testing\SimpleProtoParams $var
+     * @return $this
      */
-    public function setSimpleParams(&$var)
+    public function setSimpleParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\SimpleProtoParams::class);
         $this->writeOneof(2, $var);
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+     * @return \Grpc\Testing\ComplexProtoParams
      */
     public function getComplexParams()
     {
@@ -63,14 +74,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.ComplexProtoParams complex_params = 3;</code>
+     * @param \Grpc\Testing\ComplexProtoParams $var
+     * @return $this
      */
-    public function setComplexParams(&$var)
+    public function setComplexParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ComplexProtoParams::class);
         $this->writeOneof(3, $var);
+
+        return $this;
     }
 
+    /**
+     * @return string
+     */
     public function getPayload()
     {
         return $this->whichOneof("payload");
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php
index 189ef03..d8df1af 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PayloadType.php
@@ -5,21 +5,17 @@
 namespace Grpc\Testing;
 
 /**
- * <pre>
  * DEPRECATED, don't use. To be removed shortly.
  * The type of payload that should be returned.
- * </pre>
  *
- * Protobuf enum <code>grpc.testing.PayloadType</code>
+ * Protobuf enum <code>Grpc\Testing\PayloadType</code>
  */
 class PayloadType
 {
     /**
-     * <pre>
      * Compressable text format.
-     * </pre>
      *
-     * <code>COMPRESSABLE = 0;</code>
+     * Generated from protobuf enum <code>COMPRESSABLE = 0;</code>
      */
     const COMPRESSABLE = 0;
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php
index d64edd4..6a4047f 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/PoissonParams.php
@@ -9,21 +9,17 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Parameters of poisson process distribution, which is a good representation
  * of activity coming in from independent identical stationary sources.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.PoissonParams</code>
+ * Generated from protobuf message <code>grpc.testing.PoissonParams</code>
  */
 class PoissonParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
-     * </pre>
      *
-     * <code>double offered_load = 1;</code>
+     * Generated from protobuf field <code>double offered_load = 1;</code>
      */
     private $offered_load = 0.0;
 
@@ -33,11 +29,10 @@
     }
 
     /**
-     * <pre>
      * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
-     * </pre>
      *
-     * <code>double offered_load = 1;</code>
+     * Generated from protobuf field <code>double offered_load = 1;</code>
+     * @return float
      */
     public function getOfferedLoad()
     {
@@ -45,16 +40,18 @@
     }
 
     /**
-     * <pre>
      * The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
-     * </pre>
      *
-     * <code>double offered_load = 1;</code>
+     * Generated from protobuf field <code>double offered_load = 1;</code>
+     * @param float $var
+     * @return $this
      */
     public function setOfferedLoad($var)
     {
         GPBUtil::checkDouble($var);
         $this->offered_load = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php
index a6da2e7..5510b57 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyClientServiceClient.php
@@ -16,17 +16,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-namespace Grpc\Testing {
+namespace Grpc\Testing;
 
-  class ProxyClientServiceClient extends \Grpc\BaseStub {
+/**
+ */
+class ProxyClientServiceClient extends \Grpc\BaseStub {
 
     /**
      * @param string $hostname hostname
      * @param array $opts channel options
-     * @param Grpc\Channel $channel (optional) re-use channel object
+     * @param \Grpc\Channel $channel (optional) re-use channel object
      */
     public function __construct($hostname, $opts, $channel = null) {
-      parent::__construct($hostname, $opts, $channel);
+        parent::__construct($hostname, $opts, $channel);
     }
 
     /**
@@ -36,10 +38,10 @@
      */
     public function GetConfig(\Grpc\Testing\Void $argument,
       $metadata = [], $options = []) {
-      return $this->_simpleRequest('/grpc.testing.ProxyClientService/GetConfig',
-      $argument,
-      ['\Grpc\Testing\ClientConfig', 'decode'],
-      $metadata, $options);
+        return $this->_simpleRequest('/grpc.testing.ProxyClientService/GetConfig',
+        $argument,
+        ['\Grpc\Testing\ClientConfig', 'decode'],
+        $metadata, $options);
     }
 
     /**
@@ -47,11 +49,19 @@
      * @param array $options call options
      */
     public function ReportTime($metadata = [], $options = []) {
-      return $this->_clientStreamRequest('/grpc.testing.ProxyClientService/ReportTime',
-      ['\Grpc\Testing\Void','decode'],
-      $metadata, $options);
+        return $this->_clientStreamRequest('/grpc.testing.ProxyClientService/ReportTime',
+        ['\Grpc\Testing\Void','decode'],
+        $metadata, $options);
     }
 
-  }
+    /**
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function ReportHist($metadata = [], $options = []) {
+        return $this->_clientStreamRequest('/grpc.testing.ProxyClientService/ReportHist',
+        ['\Grpc\Testing\Void','decode'],
+        $metadata, $options);
+    }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php
index ed43be9..6fab611 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ProxyStat.php
@@ -9,12 +9,12 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ProxyStat</code>
+ * Generated from protobuf message <code>grpc.testing.ProxyStat</code>
  */
 class ProxyStat extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>double latency = 1;</code>
+     * Generated from protobuf field <code>double latency = 1;</code>
      */
     private $latency = 0.0;
 
@@ -24,7 +24,8 @@
     }
 
     /**
-     * <code>double latency = 1;</code>
+     * Generated from protobuf field <code>double latency = 1;</code>
+     * @return float
      */
     public function getLatency()
     {
@@ -32,12 +33,16 @@
     }
 
     /**
-     * <code>double latency = 1;</code>
+     * Generated from protobuf field <code>double latency = 1;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php
index dfaaa60..cd72870 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectInfo.php
@@ -9,22 +9,20 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * For reconnect interop test only.
  * Server tells client whether its reconnects are following the spec and the
  * reconnect backoffs it saw.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ReconnectInfo</code>
+ * Generated from protobuf message <code>grpc.testing.ReconnectInfo</code>
  */
 class ReconnectInfo extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>bool passed = 1;</code>
+     * Generated from protobuf field <code>bool passed = 1;</code>
      */
     private $passed = false;
     /**
-     * <code>repeated int32 backoff_ms = 2;</code>
+     * Generated from protobuf field <code>repeated int32 backoff_ms = 2;</code>
      */
     private $backoff_ms;
 
@@ -34,7 +32,8 @@
     }
 
     /**
-     * <code>bool passed = 1;</code>
+     * Generated from protobuf field <code>bool passed = 1;</code>
+     * @return bool
      */
     public function getPassed()
     {
@@ -42,16 +41,21 @@
     }
 
     /**
-     * <code>bool passed = 1;</code>
+     * Generated from protobuf field <code>bool passed = 1;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setPassed($var)
     {
         GPBUtil::checkBool($var);
         $this->passed = $var;
+
+        return $this;
     }
 
     /**
-     * <code>repeated int32 backoff_ms = 2;</code>
+     * Generated from protobuf field <code>repeated int32 backoff_ms = 2;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getBackoffMs()
     {
@@ -59,12 +63,16 @@
     }
 
     /**
-     * <code>repeated int32 backoff_ms = 2;</code>
+     * Generated from protobuf field <code>repeated int32 backoff_ms = 2;</code>
+     * @param int[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setBackoffMs(&$var)
+    public function setBackoffMs($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
-        $this->backoff_ms = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+        $this->backoff_ms = $arr;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php
index 9715855..f91dc41 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ReconnectParams.php
@@ -9,17 +9,15 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * For reconnect interop test only.
  * Client tells server what reconnection parameters it used.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ReconnectParams</code>
+ * Generated from protobuf message <code>grpc.testing.ReconnectParams</code>
  */
 class ReconnectParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>int32 max_reconnect_backoff_ms = 1;</code>
+     * Generated from protobuf field <code>int32 max_reconnect_backoff_ms = 1;</code>
      */
     private $max_reconnect_backoff_ms = 0;
 
@@ -29,7 +27,8 @@
     }
 
     /**
-     * <code>int32 max_reconnect_backoff_ms = 1;</code>
+     * Generated from protobuf field <code>int32 max_reconnect_backoff_ms = 1;</code>
+     * @return int
      */
     public function getMaxReconnectBackoffMs()
     {
@@ -37,12 +36,16 @@
     }
 
     /**
-     * <code>int32 max_reconnect_backoff_ms = 1;</code>
+     * Generated from protobuf field <code>int32 max_reconnect_backoff_ms = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setMaxReconnectBackoffMs($var)
     {
         GPBUtil::checkInt32($var);
         $this->max_reconnect_backoff_ms = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ReportQpsScenarioServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/ReportQpsScenarioServiceClient.php
new file mode 100644
index 0000000..72d44ff
--- /dev/null
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ReportQpsScenarioServiceClient.php
@@ -0,0 +1,50 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+namespace Grpc\Testing;
+
+/**
+ */
+class ReportQpsScenarioServiceClient extends \Grpc\BaseStub {
+
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param \Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+        parent::__construct($hostname, $opts, $channel);
+    }
+
+    /**
+     * Report results of a QPS test benchmark scenario.
+     * @param \Grpc\Testing\ScenarioResult $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function ReportScenario(\Grpc\Testing\ScenarioResult $argument,
+      $metadata = [], $options = []) {
+        return $this->_simpleRequest('/grpc.testing.ReportQpsScenarioService/ReportScenario',
+        $argument,
+        ['\Grpc\Testing\Void', 'decode'],
+        $metadata, $options);
+    }
+
+}
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php b/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php
index 1be42b2..75fa6ca 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/RequestResultCount.php
@@ -9,16 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.RequestResultCount</code>
+ * Generated from protobuf message <code>grpc.testing.RequestResultCount</code>
  */
 class RequestResultCount extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>int32 status_code = 1;</code>
+     * Generated from protobuf field <code>int32 status_code = 1;</code>
      */
     private $status_code = 0;
     /**
-     * <code>int64 count = 2;</code>
+     * Generated from protobuf field <code>int64 count = 2;</code>
      */
     private $count = 0;
 
@@ -28,7 +28,8 @@
     }
 
     /**
-     * <code>int32 status_code = 1;</code>
+     * Generated from protobuf field <code>int32 status_code = 1;</code>
+     * @return int
      */
     public function getStatusCode()
     {
@@ -36,16 +37,21 @@
     }
 
     /**
-     * <code>int32 status_code = 1;</code>
+     * Generated from protobuf field <code>int32 status_code = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setStatusCode($var)
     {
         GPBUtil::checkInt32($var);
         $this->status_code = $var;
+
+        return $this;
     }
 
     /**
-     * <code>int64 count = 2;</code>
+     * Generated from protobuf field <code>int64 count = 2;</code>
+     * @return int|string
      */
     public function getCount()
     {
@@ -53,12 +59,16 @@
     }
 
     /**
-     * <code>int64 count = 2;</code>
+     * Generated from protobuf field <code>int64 count = 2;</code>
+     * @param int|string $var
+     * @return $this
      */
     public function setCount($var)
     {
         GPBUtil::checkInt64($var);
         $this->count = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php b/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php
index b7a8e5e..b2f0a82 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ResponseParameters.php
@@ -9,40 +9,32 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Configuration for a particular response.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ResponseParameters</code>
+ * Generated from protobuf message <code>grpc.testing.ResponseParameters</code>
  */
 class ResponseParameters extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Desired payload sizes in responses from the server.
-     * </pre>
      *
-     * <code>int32 size = 1;</code>
+     * Generated from protobuf field <code>int32 size = 1;</code>
      */
     private $size = 0;
     /**
-     * <pre>
      * Desired interval between consecutive responses in the response stream in
      * microseconds.
-     * </pre>
      *
-     * <code>int32 interval_us = 2;</code>
+     * Generated from protobuf field <code>int32 interval_us = 2;</code>
      */
     private $interval_us = 0;
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue compressed = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue compressed = 3;</code>
      */
     private $compressed = null;
 
@@ -52,11 +44,10 @@
     }
 
     /**
-     * <pre>
      * Desired payload sizes in responses from the server.
-     * </pre>
      *
-     * <code>int32 size = 1;</code>
+     * Generated from protobuf field <code>int32 size = 1;</code>
+     * @return int
      */
     public function getSize()
     {
@@ -64,25 +55,26 @@
     }
 
     /**
-     * <pre>
      * Desired payload sizes in responses from the server.
-     * </pre>
      *
-     * <code>int32 size = 1;</code>
+     * Generated from protobuf field <code>int32 size = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->size = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Desired interval between consecutive responses in the response stream in
      * microseconds.
-     * </pre>
      *
-     * <code>int32 interval_us = 2;</code>
+     * Generated from protobuf field <code>int32 interval_us = 2;</code>
+     * @return int
      */
     public function getIntervalUs()
     {
@@ -90,28 +82,29 @@
     }
 
     /**
-     * <pre>
      * Desired interval between consecutive responses in the response stream in
      * microseconds.
-     * </pre>
      *
-     * <code>int32 interval_us = 2;</code>
+     * Generated from protobuf field <code>int32 interval_us = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setIntervalUs($var)
     {
         GPBUtil::checkInt32($var);
         $this->interval_us = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue compressed = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue compressed = 3;</code>
+     * @return \Grpc\Testing\BoolValue
      */
     public function getCompressed()
     {
@@ -119,19 +112,21 @@
     }
 
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue compressed = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue compressed = 3;</code>
+     * @param \Grpc\Testing\BoolValue $var
+     * @return $this
      */
-    public function setCompressed(&$var)
+    public function setCompressed($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
         $this->compressed = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php b/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php
index 2e664ff..73a6649 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/RpcType.php
@@ -5,17 +5,29 @@
 namespace Grpc\Testing;
 
 /**
- * Protobuf enum <code>grpc.testing.RpcType</code>
+ * Protobuf enum <code>Grpc\Testing\RpcType</code>
  */
 class RpcType
 {
     /**
-     * <code>UNARY = 0;</code>
+     * Generated from protobuf enum <code>UNARY = 0;</code>
      */
     const UNARY = 0;
     /**
-     * <code>STREAMING = 1;</code>
+     * Generated from protobuf enum <code>STREAMING = 1;</code>
      */
     const STREAMING = 1;
+    /**
+     * Generated from protobuf enum <code>STREAMING_FROM_CLIENT = 2;</code>
+     */
+    const STREAMING_FROM_CLIENT = 2;
+    /**
+     * Generated from protobuf enum <code>STREAMING_FROM_SERVER = 3;</code>
+     */
+    const STREAMING_FROM_SERVER = 3;
+    /**
+     * Generated from protobuf enum <code>STREAMING_BOTH_WAYS = 4;</code>
+     */
+    const STREAMING_BOTH_WAYS = 4;
 }
 
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php b/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php
index 136ed29..9ec284b 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Scenario.php
@@ -9,76 +9,58 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * A single performance scenario: input to qps_json_driver
- * </pre>
  *
- * Protobuf type <code>grpc.testing.Scenario</code>
+ * Generated from protobuf message <code>grpc.testing.Scenario</code>
  */
 class Scenario extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Human readable name for this scenario
-     * </pre>
      *
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
      */
     private $name = '';
     /**
-     * <pre>
      * Client configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientConfig client_config = 2;</code>
      */
     private $client_config = null;
     /**
-     * <pre>
      * Number of clients to start for the test
-     * </pre>
      *
-     * <code>int32 num_clients = 3;</code>
+     * Generated from protobuf field <code>int32 num_clients = 3;</code>
      */
     private $num_clients = 0;
     /**
-     * <pre>
      * Server configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerConfig server_config = 4;</code>
      */
     private $server_config = null;
     /**
-     * <pre>
      * Number of servers to start for the test
-     * </pre>
      *
-     * <code>int32 num_servers = 5;</code>
+     * Generated from protobuf field <code>int32 num_servers = 5;</code>
      */
     private $num_servers = 0;
     /**
-     * <pre>
      * Warmup period, in seconds
-     * </pre>
      *
-     * <code>int32 warmup_seconds = 6;</code>
+     * Generated from protobuf field <code>int32 warmup_seconds = 6;</code>
      */
     private $warmup_seconds = 0;
     /**
-     * <pre>
      * Benchmark time, in seconds
-     * </pre>
      *
-     * <code>int32 benchmark_seconds = 7;</code>
+     * Generated from protobuf field <code>int32 benchmark_seconds = 7;</code>
      */
     private $benchmark_seconds = 0;
     /**
-     * <pre>
      * Number of workers to spawn locally (usually zero)
-     * </pre>
      *
-     * <code>int32 spawn_local_worker_count = 8;</code>
+     * Generated from protobuf field <code>int32 spawn_local_worker_count = 8;</code>
      */
     private $spawn_local_worker_count = 0;
 
@@ -88,11 +70,10 @@
     }
 
     /**
-     * <pre>
      * Human readable name for this scenario
-     * </pre>
      *
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @return string
      */
     public function getName()
     {
@@ -100,24 +81,25 @@
     }
 
     /**
-     * <pre>
      * Human readable name for this scenario
-     * </pre>
      *
-     * <code>string name = 1;</code>
+     * Generated from protobuf field <code>string name = 1;</code>
+     * @param string $var
+     * @return $this
      */
     public function setName($var)
     {
         GPBUtil::checkString($var, True);
         $this->name = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Client configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientConfig client_config = 2;</code>
+     * @return \Grpc\Testing\ClientConfig
      */
     public function getClientConfig()
     {
@@ -125,24 +107,25 @@
     }
 
     /**
-     * <pre>
      * Client configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ClientConfig client_config = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.ClientConfig client_config = 2;</code>
+     * @param \Grpc\Testing\ClientConfig $var
+     * @return $this
      */
-    public function setClientConfig(&$var)
+    public function setClientConfig($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ClientConfig::class);
         $this->client_config = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of clients to start for the test
-     * </pre>
      *
-     * <code>int32 num_clients = 3;</code>
+     * Generated from protobuf field <code>int32 num_clients = 3;</code>
+     * @return int
      */
     public function getNumClients()
     {
@@ -150,24 +133,25 @@
     }
 
     /**
-     * <pre>
      * Number of clients to start for the test
-     * </pre>
      *
-     * <code>int32 num_clients = 3;</code>
+     * Generated from protobuf field <code>int32 num_clients = 3;</code>
+     * @param int $var
+     * @return $this
      */
     public function setNumClients($var)
     {
         GPBUtil::checkInt32($var);
         $this->num_clients = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Server configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerConfig server_config = 4;</code>
+     * @return \Grpc\Testing\ServerConfig
      */
     public function getServerConfig()
     {
@@ -175,24 +159,25 @@
     }
 
     /**
-     * <pre>
      * Server configuration
-     * </pre>
      *
-     * <code>.grpc.testing.ServerConfig server_config = 4;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerConfig server_config = 4;</code>
+     * @param \Grpc\Testing\ServerConfig $var
+     * @return $this
      */
-    public function setServerConfig(&$var)
+    public function setServerConfig($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ServerConfig::class);
         $this->server_config = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of servers to start for the test
-     * </pre>
      *
-     * <code>int32 num_servers = 5;</code>
+     * Generated from protobuf field <code>int32 num_servers = 5;</code>
+     * @return int
      */
     public function getNumServers()
     {
@@ -200,24 +185,25 @@
     }
 
     /**
-     * <pre>
      * Number of servers to start for the test
-     * </pre>
      *
-     * <code>int32 num_servers = 5;</code>
+     * Generated from protobuf field <code>int32 num_servers = 5;</code>
+     * @param int $var
+     * @return $this
      */
     public function setNumServers($var)
     {
         GPBUtil::checkInt32($var);
         $this->num_servers = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Warmup period, in seconds
-     * </pre>
      *
-     * <code>int32 warmup_seconds = 6;</code>
+     * Generated from protobuf field <code>int32 warmup_seconds = 6;</code>
+     * @return int
      */
     public function getWarmupSeconds()
     {
@@ -225,24 +211,25 @@
     }
 
     /**
-     * <pre>
      * Warmup period, in seconds
-     * </pre>
      *
-     * <code>int32 warmup_seconds = 6;</code>
+     * Generated from protobuf field <code>int32 warmup_seconds = 6;</code>
+     * @param int $var
+     * @return $this
      */
     public function setWarmupSeconds($var)
     {
         GPBUtil::checkInt32($var);
         $this->warmup_seconds = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Benchmark time, in seconds
-     * </pre>
      *
-     * <code>int32 benchmark_seconds = 7;</code>
+     * Generated from protobuf field <code>int32 benchmark_seconds = 7;</code>
+     * @return int
      */
     public function getBenchmarkSeconds()
     {
@@ -250,24 +237,25 @@
     }
 
     /**
-     * <pre>
      * Benchmark time, in seconds
-     * </pre>
      *
-     * <code>int32 benchmark_seconds = 7;</code>
+     * Generated from protobuf field <code>int32 benchmark_seconds = 7;</code>
+     * @param int $var
+     * @return $this
      */
     public function setBenchmarkSeconds($var)
     {
         GPBUtil::checkInt32($var);
         $this->benchmark_seconds = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of workers to spawn locally (usually zero)
-     * </pre>
      *
-     * <code>int32 spawn_local_worker_count = 8;</code>
+     * Generated from protobuf field <code>int32 spawn_local_worker_count = 8;</code>
+     * @return int
      */
     public function getSpawnLocalWorkerCount()
     {
@@ -275,16 +263,18 @@
     }
 
     /**
-     * <pre>
      * Number of workers to spawn locally (usually zero)
-     * </pre>
      *
-     * <code>int32 spawn_local_worker_count = 8;</code>
+     * Generated from protobuf field <code>int32 spawn_local_worker_count = 8;</code>
+     * @param int $var
+     * @return $this
      */
     public function setSpawnLocalWorkerCount($var)
     {
         GPBUtil::checkInt32($var);
         $this->spawn_local_worker_count = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php
index 809cd96..31d9a39 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResult.php
@@ -9,80 +9,62 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Results of a single benchmark scenario.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ScenarioResult</code>
+ * Generated from protobuf message <code>grpc.testing.ScenarioResult</code>
  */
 class ScenarioResult extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Inputs used to run the scenario.
-     * </pre>
      *
-     * <code>.grpc.testing.Scenario scenario = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Scenario scenario = 1;</code>
      */
     private $scenario = null;
     /**
-     * <pre>
      * Histograms from all clients merged into one histogram.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 2;</code>
      */
     private $latencies = null;
     /**
-     * <pre>
      * Client stats for each client
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
      */
     private $client_stats;
     /**
-     * <pre>
      * Server stats for each server
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
      */
     private $server_stats;
     /**
-     * <pre>
      * Number of cores available to each server
-     * </pre>
      *
-     * <code>repeated int32 server_cores = 5;</code>
+     * Generated from protobuf field <code>repeated int32 server_cores = 5;</code>
      */
     private $server_cores;
     /**
-     * <pre>
      * An after-the-fact computed summary
-     * </pre>
      *
-     * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
      */
     private $summary = null;
     /**
-     * <pre>
      * Information on success or failure of each worker
-     * </pre>
      *
-     * <code>repeated bool client_success = 7;</code>
+     * Generated from protobuf field <code>repeated bool client_success = 7;</code>
      */
     private $client_success;
     /**
-     * <code>repeated bool server_success = 8;</code>
+     * Generated from protobuf field <code>repeated bool server_success = 8;</code>
      */
     private $server_success;
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
      */
     private $request_results;
 
@@ -92,11 +74,10 @@
     }
 
     /**
-     * <pre>
      * Inputs used to run the scenario.
-     * </pre>
      *
-     * <code>.grpc.testing.Scenario scenario = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Scenario scenario = 1;</code>
+     * @return \Grpc\Testing\Scenario
      */
     public function getScenario()
     {
@@ -104,24 +85,25 @@
     }
 
     /**
-     * <pre>
      * Inputs used to run the scenario.
-     * </pre>
      *
-     * <code>.grpc.testing.Scenario scenario = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Scenario scenario = 1;</code>
+     * @param \Grpc\Testing\Scenario $var
+     * @return $this
      */
-    public function setScenario(&$var)
+    public function setScenario($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Scenario::class);
         $this->scenario = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Histograms from all clients merged into one histogram.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 2;</code>
+     * @return \Grpc\Testing\HistogramData
      */
     public function getLatencies()
     {
@@ -129,24 +111,25 @@
     }
 
     /**
-     * <pre>
      * Histograms from all clients merged into one histogram.
-     * </pre>
      *
-     * <code>.grpc.testing.HistogramData latencies = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.HistogramData latencies = 2;</code>
+     * @param \Grpc\Testing\HistogramData $var
+     * @return $this
      */
-    public function setLatencies(&$var)
+    public function setLatencies($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\HistogramData::class);
         $this->latencies = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Client stats for each client
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getClientStats()
     {
@@ -154,24 +137,25 @@
     }
 
     /**
-     * <pre>
      * Client stats for each client
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ClientStats client_stats = 3;</code>
+     * @param \Grpc\Testing\ClientStats[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setClientStats(&$var)
+    public function setClientStats($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ClientStats::class);
-        $this->client_stats = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ClientStats::class);
+        $this->client_stats = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Server stats for each server
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getServerStats()
     {
@@ -179,24 +163,25 @@
     }
 
     /**
-     * <pre>
      * Server stats for each server
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ServerStats server_stats = 4;</code>
+     * @param \Grpc\Testing\ServerStats[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setServerStats(&$var)
+    public function setServerStats($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ServerStats::class);
-        $this->server_stats = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ServerStats::class);
+        $this->server_stats = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of cores available to each server
-     * </pre>
      *
-     * <code>repeated int32 server_cores = 5;</code>
+     * Generated from protobuf field <code>repeated int32 server_cores = 5;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getServerCores()
     {
@@ -204,24 +189,25 @@
     }
 
     /**
-     * <pre>
      * Number of cores available to each server
-     * </pre>
      *
-     * <code>repeated int32 server_cores = 5;</code>
+     * Generated from protobuf field <code>repeated int32 server_cores = 5;</code>
+     * @param int[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setServerCores(&$var)
+    public function setServerCores($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
-        $this->server_cores = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+        $this->server_cores = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * An after-the-fact computed summary
-     * </pre>
      *
-     * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+     * @return \Grpc\Testing\ScenarioResultSummary
      */
     public function getSummary()
     {
@@ -229,24 +215,25 @@
     }
 
     /**
-     * <pre>
      * An after-the-fact computed summary
-     * </pre>
      *
-     * <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.ScenarioResultSummary summary = 6;</code>
+     * @param \Grpc\Testing\ScenarioResultSummary $var
+     * @return $this
      */
-    public function setSummary(&$var)
+    public function setSummary($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ScenarioResultSummary::class);
         $this->summary = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Information on success or failure of each worker
-     * </pre>
      *
-     * <code>repeated bool client_success = 7;</code>
+     * Generated from protobuf field <code>repeated bool client_success = 7;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getClientSuccess()
     {
@@ -254,20 +241,23 @@
     }
 
     /**
-     * <pre>
      * Information on success or failure of each worker
-     * </pre>
      *
-     * <code>repeated bool client_success = 7;</code>
+     * Generated from protobuf field <code>repeated bool client_success = 7;</code>
+     * @param bool[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setClientSuccess(&$var)
+    public function setClientSuccess($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
-        $this->client_success = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
+        $this->client_success = $arr;
+
+        return $this;
     }
 
     /**
-     * <code>repeated bool server_success = 8;</code>
+     * Generated from protobuf field <code>repeated bool server_success = 8;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getServerSuccess()
     {
@@ -275,20 +265,23 @@
     }
 
     /**
-     * <code>repeated bool server_success = 8;</code>
+     * Generated from protobuf field <code>repeated bool server_success = 8;</code>
+     * @param bool[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setServerSuccess(&$var)
+    public function setServerSuccess($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
-        $this->server_success = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BOOL);
+        $this->server_success = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getRequestResults()
     {
@@ -296,16 +289,18 @@
     }
 
     /**
-     * <pre>
      * Number of failed requests (one row per status code seen)
-     * </pre>
      *
-     * <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.RequestResultCount request_results = 9;</code>
+     * @param \Grpc\Testing\RequestResultCount[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setRequestResults(&$var)
+    public function setRequestResults($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
-        $this->request_results = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\RequestResultCount::class);
+        $this->request_results = $arr;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php
index 7520cff..f7f1c98 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ScenarioResultSummary.php
@@ -9,107 +9,107 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Basic summary that can be computed from ClientStats and ServerStats
  * once the scenario has finished.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.ScenarioResultSummary</code>
+ * Generated from protobuf message <code>grpc.testing.ScenarioResultSummary</code>
  */
 class ScenarioResultSummary extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Total number of operations per second over all clients.
-     * </pre>
      *
-     * <code>double qps = 1;</code>
+     * Generated from protobuf field <code>double qps = 1;</code>
      */
     private $qps = 0.0;
     /**
-     * <pre>
      * QPS per one server core.
-     * </pre>
      *
-     * <code>double qps_per_server_core = 2;</code>
+     * Generated from protobuf field <code>double qps_per_server_core = 2;</code>
      */
     private $qps_per_server_core = 0.0;
     /**
-     * <pre>
-     * server load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on system_time (0.85 => 85%)
      *
-     * <code>double server_system_time = 3;</code>
+     * Generated from protobuf field <code>double server_system_time = 3;</code>
      */
     private $server_system_time = 0.0;
     /**
-     * <pre>
-     * server load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on user_time (0.85 => 85%)
      *
-     * <code>double server_user_time = 4;</code>
+     * Generated from protobuf field <code>double server_user_time = 4;</code>
      */
     private $server_user_time = 0.0;
     /**
-     * <pre>
-     * client load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on system_time (0.85 => 85%)
      *
-     * <code>double client_system_time = 5;</code>
+     * Generated from protobuf field <code>double client_system_time = 5;</code>
      */
     private $client_system_time = 0.0;
     /**
-     * <pre>
-     * client load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on user_time (0.85 => 85%)
      *
-     * <code>double client_user_time = 6;</code>
+     * Generated from protobuf field <code>double client_user_time = 6;</code>
      */
     private $client_user_time = 0.0;
     /**
-     * <pre>
      * X% latency percentiles (in nanoseconds)
-     * </pre>
      *
-     * <code>double latency_50 = 7;</code>
+     * Generated from protobuf field <code>double latency_50 = 7;</code>
      */
     private $latency_50 = 0.0;
     /**
-     * <code>double latency_90 = 8;</code>
+     * Generated from protobuf field <code>double latency_90 = 8;</code>
      */
     private $latency_90 = 0.0;
     /**
-     * <code>double latency_95 = 9;</code>
+     * Generated from protobuf field <code>double latency_95 = 9;</code>
      */
     private $latency_95 = 0.0;
     /**
-     * <code>double latency_99 = 10;</code>
+     * Generated from protobuf field <code>double latency_99 = 10;</code>
      */
     private $latency_99 = 0.0;
     /**
-     * <code>double latency_999 = 11;</code>
+     * Generated from protobuf field <code>double latency_999 = 11;</code>
      */
     private $latency_999 = 0.0;
     /**
-     * <pre>
      * server cpu usage percentage
-     * </pre>
      *
-     * <code>double server_cpu_usage = 12;</code>
+     * Generated from protobuf field <code>double server_cpu_usage = 12;</code>
      */
     private $server_cpu_usage = 0.0;
     /**
-     * <pre>
      * Number of requests that succeeded/failed
-     * </pre>
      *
-     * <code>double successful_requests_per_second = 13;</code>
+     * Generated from protobuf field <code>double successful_requests_per_second = 13;</code>
      */
     private $successful_requests_per_second = 0.0;
     /**
-     * <code>double failed_requests_per_second = 14;</code>
+     * Generated from protobuf field <code>double failed_requests_per_second = 14;</code>
      */
     private $failed_requests_per_second = 0.0;
+    /**
+     * Number of polls called inside completion queue per request
+     *
+     * Generated from protobuf field <code>double client_polls_per_request = 15;</code>
+     */
+    private $client_polls_per_request = 0.0;
+    /**
+     * Generated from protobuf field <code>double server_polls_per_request = 16;</code>
+     */
+    private $server_polls_per_request = 0.0;
+    /**
+     * Queries per CPU-sec over all servers or clients
+     *
+     * Generated from protobuf field <code>double server_queries_per_cpu_sec = 17;</code>
+     */
+    private $server_queries_per_cpu_sec = 0.0;
+    /**
+     * Generated from protobuf field <code>double client_queries_per_cpu_sec = 18;</code>
+     */
+    private $client_queries_per_cpu_sec = 0.0;
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
@@ -117,11 +117,10 @@
     }
 
     /**
-     * <pre>
      * Total number of operations per second over all clients.
-     * </pre>
      *
-     * <code>double qps = 1;</code>
+     * Generated from protobuf field <code>double qps = 1;</code>
+     * @return float
      */
     public function getQps()
     {
@@ -129,24 +128,25 @@
     }
 
     /**
-     * <pre>
      * Total number of operations per second over all clients.
-     * </pre>
      *
-     * <code>double qps = 1;</code>
+     * Generated from protobuf field <code>double qps = 1;</code>
+     * @param float $var
+     * @return $this
      */
     public function setQps($var)
     {
         GPBUtil::checkDouble($var);
         $this->qps = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * QPS per one server core.
-     * </pre>
      *
-     * <code>double qps_per_server_core = 2;</code>
+     * Generated from protobuf field <code>double qps_per_server_core = 2;</code>
+     * @return float
      */
     public function getQpsPerServerCore()
     {
@@ -154,24 +154,25 @@
     }
 
     /**
-     * <pre>
      * QPS per one server core.
-     * </pre>
      *
-     * <code>double qps_per_server_core = 2;</code>
+     * Generated from protobuf field <code>double qps_per_server_core = 2;</code>
+     * @param float $var
+     * @return $this
      */
     public function setQpsPerServerCore($var)
     {
         GPBUtil::checkDouble($var);
         $this->qps_per_server_core = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
-     * server load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on system_time (0.85 => 85%)
      *
-     * <code>double server_system_time = 3;</code>
+     * Generated from protobuf field <code>double server_system_time = 3;</code>
+     * @return float
      */
     public function getServerSystemTime()
     {
@@ -179,24 +180,25 @@
     }
 
     /**
-     * <pre>
-     * server load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on system_time (0.85 => 85%)
      *
-     * <code>double server_system_time = 3;</code>
+     * Generated from protobuf field <code>double server_system_time = 3;</code>
+     * @param float $var
+     * @return $this
      */
     public function setServerSystemTime($var)
     {
         GPBUtil::checkDouble($var);
         $this->server_system_time = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
-     * server load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on user_time (0.85 => 85%)
      *
-     * <code>double server_user_time = 4;</code>
+     * Generated from protobuf field <code>double server_user_time = 4;</code>
+     * @return float
      */
     public function getServerUserTime()
     {
@@ -204,24 +206,25 @@
     }
 
     /**
-     * <pre>
-     * server load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * server load based on user_time (0.85 => 85%)
      *
-     * <code>double server_user_time = 4;</code>
+     * Generated from protobuf field <code>double server_user_time = 4;</code>
+     * @param float $var
+     * @return $this
      */
     public function setServerUserTime($var)
     {
         GPBUtil::checkDouble($var);
         $this->server_user_time = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
-     * client load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on system_time (0.85 => 85%)
      *
-     * <code>double client_system_time = 5;</code>
+     * Generated from protobuf field <code>double client_system_time = 5;</code>
+     * @return float
      */
     public function getClientSystemTime()
     {
@@ -229,24 +232,25 @@
     }
 
     /**
-     * <pre>
-     * client load based on system_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on system_time (0.85 => 85%)
      *
-     * <code>double client_system_time = 5;</code>
+     * Generated from protobuf field <code>double client_system_time = 5;</code>
+     * @param float $var
+     * @return $this
      */
     public function setClientSystemTime($var)
     {
         GPBUtil::checkDouble($var);
         $this->client_system_time = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
-     * client load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on user_time (0.85 => 85%)
      *
-     * <code>double client_user_time = 6;</code>
+     * Generated from protobuf field <code>double client_user_time = 6;</code>
+     * @return float
      */
     public function getClientUserTime()
     {
@@ -254,24 +258,25 @@
     }
 
     /**
-     * <pre>
-     * client load based on user_time (0.85 =&gt; 85%)
-     * </pre>
+     * client load based on user_time (0.85 => 85%)
      *
-     * <code>double client_user_time = 6;</code>
+     * Generated from protobuf field <code>double client_user_time = 6;</code>
+     * @param float $var
+     * @return $this
      */
     public function setClientUserTime($var)
     {
         GPBUtil::checkDouble($var);
         $this->client_user_time = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * X% latency percentiles (in nanoseconds)
-     * </pre>
      *
-     * <code>double latency_50 = 7;</code>
+     * Generated from protobuf field <code>double latency_50 = 7;</code>
+     * @return float
      */
     public function getLatency50()
     {
@@ -279,20 +284,23 @@
     }
 
     /**
-     * <pre>
      * X% latency percentiles (in nanoseconds)
-     * </pre>
      *
-     * <code>double latency_50 = 7;</code>
+     * Generated from protobuf field <code>double latency_50 = 7;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency50($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency_50 = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double latency_90 = 8;</code>
+     * Generated from protobuf field <code>double latency_90 = 8;</code>
+     * @return float
      */
     public function getLatency90()
     {
@@ -300,16 +308,21 @@
     }
 
     /**
-     * <code>double latency_90 = 8;</code>
+     * Generated from protobuf field <code>double latency_90 = 8;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency90($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency_90 = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double latency_95 = 9;</code>
+     * Generated from protobuf field <code>double latency_95 = 9;</code>
+     * @return float
      */
     public function getLatency95()
     {
@@ -317,16 +330,21 @@
     }
 
     /**
-     * <code>double latency_95 = 9;</code>
+     * Generated from protobuf field <code>double latency_95 = 9;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency95($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency_95 = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double latency_99 = 10;</code>
+     * Generated from protobuf field <code>double latency_99 = 10;</code>
+     * @return float
      */
     public function getLatency99()
     {
@@ -334,16 +352,21 @@
     }
 
     /**
-     * <code>double latency_99 = 10;</code>
+     * Generated from protobuf field <code>double latency_99 = 10;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency99($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency_99 = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double latency_999 = 11;</code>
+     * Generated from protobuf field <code>double latency_999 = 11;</code>
+     * @return float
      */
     public function getLatency999()
     {
@@ -351,20 +374,23 @@
     }
 
     /**
-     * <code>double latency_999 = 11;</code>
+     * Generated from protobuf field <code>double latency_999 = 11;</code>
+     * @param float $var
+     * @return $this
      */
     public function setLatency999($var)
     {
         GPBUtil::checkDouble($var);
         $this->latency_999 = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * server cpu usage percentage
-     * </pre>
      *
-     * <code>double server_cpu_usage = 12;</code>
+     * Generated from protobuf field <code>double server_cpu_usage = 12;</code>
+     * @return float
      */
     public function getServerCpuUsage()
     {
@@ -372,24 +398,25 @@
     }
 
     /**
-     * <pre>
      * server cpu usage percentage
-     * </pre>
      *
-     * <code>double server_cpu_usage = 12;</code>
+     * Generated from protobuf field <code>double server_cpu_usage = 12;</code>
+     * @param float $var
+     * @return $this
      */
     public function setServerCpuUsage($var)
     {
         GPBUtil::checkDouble($var);
         $this->server_cpu_usage = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of requests that succeeded/failed
-     * </pre>
      *
-     * <code>double successful_requests_per_second = 13;</code>
+     * Generated from protobuf field <code>double successful_requests_per_second = 13;</code>
+     * @return float
      */
     public function getSuccessfulRequestsPerSecond()
     {
@@ -397,20 +424,23 @@
     }
 
     /**
-     * <pre>
      * Number of requests that succeeded/failed
-     * </pre>
      *
-     * <code>double successful_requests_per_second = 13;</code>
+     * Generated from protobuf field <code>double successful_requests_per_second = 13;</code>
+     * @param float $var
+     * @return $this
      */
     public function setSuccessfulRequestsPerSecond($var)
     {
         GPBUtil::checkDouble($var);
         $this->successful_requests_per_second = $var;
+
+        return $this;
     }
 
     /**
-     * <code>double failed_requests_per_second = 14;</code>
+     * Generated from protobuf field <code>double failed_requests_per_second = 14;</code>
+     * @return float
      */
     public function getFailedRequestsPerSecond()
     {
@@ -418,12 +448,112 @@
     }
 
     /**
-     * <code>double failed_requests_per_second = 14;</code>
+     * Generated from protobuf field <code>double failed_requests_per_second = 14;</code>
+     * @param float $var
+     * @return $this
      */
     public function setFailedRequestsPerSecond($var)
     {
         GPBUtil::checkDouble($var);
         $this->failed_requests_per_second = $var;
+
+        return $this;
+    }
+
+    /**
+     * Number of polls called inside completion queue per request
+     *
+     * Generated from protobuf field <code>double client_polls_per_request = 15;</code>
+     * @return float
+     */
+    public function getClientPollsPerRequest()
+    {
+        return $this->client_polls_per_request;
+    }
+
+    /**
+     * Number of polls called inside completion queue per request
+     *
+     * Generated from protobuf field <code>double client_polls_per_request = 15;</code>
+     * @param float $var
+     * @return $this
+     */
+    public function setClientPollsPerRequest($var)
+    {
+        GPBUtil::checkDouble($var);
+        $this->client_polls_per_request = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>double server_polls_per_request = 16;</code>
+     * @return float
+     */
+    public function getServerPollsPerRequest()
+    {
+        return $this->server_polls_per_request;
+    }
+
+    /**
+     * Generated from protobuf field <code>double server_polls_per_request = 16;</code>
+     * @param float $var
+     * @return $this
+     */
+    public function setServerPollsPerRequest($var)
+    {
+        GPBUtil::checkDouble($var);
+        $this->server_polls_per_request = $var;
+
+        return $this;
+    }
+
+    /**
+     * Queries per CPU-sec over all servers or clients
+     *
+     * Generated from protobuf field <code>double server_queries_per_cpu_sec = 17;</code>
+     * @return float
+     */
+    public function getServerQueriesPerCpuSec()
+    {
+        return $this->server_queries_per_cpu_sec;
+    }
+
+    /**
+     * Queries per CPU-sec over all servers or clients
+     *
+     * Generated from protobuf field <code>double server_queries_per_cpu_sec = 17;</code>
+     * @param float $var
+     * @return $this
+     */
+    public function setServerQueriesPerCpuSec($var)
+    {
+        GPBUtil::checkDouble($var);
+        $this->server_queries_per_cpu_sec = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>double client_queries_per_cpu_sec = 18;</code>
+     * @return float
+     */
+    public function getClientQueriesPerCpuSec()
+    {
+        return $this->client_queries_per_cpu_sec;
+    }
+
+    /**
+     * Generated from protobuf field <code>double client_queries_per_cpu_sec = 18;</code>
+     * @param float $var
+     * @return $this
+     */
+    public function setClientQueriesPerCpuSec($var)
+    {
+        GPBUtil::checkDouble($var);
+        $this->client_queries_per_cpu_sec = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php b/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php
index 278f555..2146b47 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Scenarios.php
@@ -9,16 +9,14 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * A set of scenarios to be run with qps_json_driver
- * </pre>
  *
- * Protobuf type <code>grpc.testing.Scenarios</code>
+ * Generated from protobuf message <code>grpc.testing.Scenarios</code>
  */
 class Scenarios extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
      */
     private $scenarios;
 
@@ -28,7 +26,8 @@
     }
 
     /**
-     * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getScenarios()
     {
@@ -36,12 +35,16 @@
     }
 
     /**
-     * <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.Scenario scenarios = 1;</code>
+     * @param \Grpc\Testing\Scenario[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setScenarios(&$var)
+    public function setScenarios($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\Scenario::class);
-        $this->scenarios = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\Scenario::class);
+        $this->scenarios = $arr;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php
index 27a5b95..8ce623a 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SecurityParams.php
@@ -9,22 +9,24 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * presence of SecurityParams implies use of TLS
- * </pre>
  *
- * Protobuf type <code>grpc.testing.SecurityParams</code>
+ * Generated from protobuf message <code>grpc.testing.SecurityParams</code>
  */
 class SecurityParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>bool use_test_ca = 1;</code>
+     * Generated from protobuf field <code>bool use_test_ca = 1;</code>
      */
     private $use_test_ca = false;
     /**
-     * <code>string server_host_override = 2;</code>
+     * Generated from protobuf field <code>string server_host_override = 2;</code>
      */
     private $server_host_override = '';
+    /**
+     * Generated from protobuf field <code>string cred_type = 3;</code>
+     */
+    private $cred_type = '';
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
@@ -32,7 +34,8 @@
     }
 
     /**
-     * <code>bool use_test_ca = 1;</code>
+     * Generated from protobuf field <code>bool use_test_ca = 1;</code>
+     * @return bool
      */
     public function getUseTestCa()
     {
@@ -40,16 +43,21 @@
     }
 
     /**
-     * <code>bool use_test_ca = 1;</code>
+     * Generated from protobuf field <code>bool use_test_ca = 1;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setUseTestCa($var)
     {
         GPBUtil::checkBool($var);
         $this->use_test_ca = $var;
+
+        return $this;
     }
 
     /**
-     * <code>string server_host_override = 2;</code>
+     * Generated from protobuf field <code>string server_host_override = 2;</code>
+     * @return string
      */
     public function getServerHostOverride()
     {
@@ -57,12 +65,38 @@
     }
 
     /**
-     * <code>string server_host_override = 2;</code>
+     * Generated from protobuf field <code>string server_host_override = 2;</code>
+     * @param string $var
+     * @return $this
      */
     public function setServerHostOverride($var)
     {
         GPBUtil::checkString($var, True);
         $this->server_host_override = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>string cred_type = 3;</code>
+     * @return string
+     */
+    public function getCredType()
+    {
+        return $this->cred_type;
+    }
+
+    /**
+     * Generated from protobuf field <code>string cred_type = 3;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setCredType($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->cred_type = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php
index 0d84b80..acf7e18 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerArgs.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ServerArgs</code>
+ * Generated from protobuf message <code>grpc.testing.ServerArgs</code>
  */
 class ServerArgs extends \Google\Protobuf\Internal\Message
 {
@@ -21,7 +21,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerConfig setup = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerConfig setup = 1;</code>
+     * @return \Grpc\Testing\ServerConfig
      */
     public function getSetup()
     {
@@ -29,16 +30,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerConfig setup = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerConfig setup = 1;</code>
+     * @param \Grpc\Testing\ServerConfig $var
+     * @return $this
      */
-    public function setSetup(&$var)
+    public function setSetup($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ServerConfig::class);
         $this->writeOneof(1, $var);
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.Mark mark = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.Mark mark = 2;</code>
+     * @return \Grpc\Testing\Mark
      */
     public function getMark()
     {
@@ -46,14 +52,21 @@
     }
 
     /**
-     * <code>.grpc.testing.Mark mark = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.Mark mark = 2;</code>
+     * @param \Grpc\Testing\Mark $var
+     * @return $this
      */
-    public function setMark(&$var)
+    public function setMark($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Mark::class);
         $this->writeOneof(2, $var);
+
+        return $this;
     }
 
+    /**
+     * @return string
+     */
     public function getArgtype()
     {
         return $this->whichOneof("argtype");
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php
index e2bcede..8bd4c69 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerConfig.php
@@ -9,77 +9,73 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ServerConfig</code>
+ * Generated from protobuf message <code>grpc.testing.ServerConfig</code>
  */
 class ServerConfig extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>.grpc.testing.ServerType server_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerType server_type = 1;</code>
      */
     private $server_type = 0;
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 2;</code>
      */
     private $security_params = null;
     /**
-     * <pre>
      * Port on which to listen. Zero means pick unused port.
-     * </pre>
      *
-     * <code>int32 port = 4;</code>
+     * Generated from protobuf field <code>int32 port = 4;</code>
      */
     private $port = 0;
     /**
-     * <pre>
      * Only for async server. Number of threads used to serve the requests.
-     * </pre>
      *
-     * <code>int32 async_server_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_server_threads = 7;</code>
      */
     private $async_server_threads = 0;
     /**
-     * <pre>
      * Specify the number of cores to limit server to, if desired
-     * </pre>
      *
-     * <code>int32 core_limit = 8;</code>
+     * Generated from protobuf field <code>int32 core_limit = 8;</code>
      */
     private $core_limit = 0;
     /**
-     * <pre>
      * payload config, used in generic server.
      * Note this must NOT be used in proto (non-generic) servers. For proto servers,
      * 'response sizes' must be configured from the 'response_size' field of the
      * 'SimpleRequest' objects in RPC requests.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
      */
     private $payload_config = null;
     /**
-     * <pre>
      * Specify the cores we should run the server on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 10;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 10;</code>
      */
     private $core_list;
     /**
-     * <pre>
      * If we use an OTHER_SERVER client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_server_api = 11;</code>
+     * Generated from protobuf field <code>string other_server_api = 11;</code>
      */
     private $other_server_api = '';
     /**
-     * <pre>
-     * Buffer pool size (no buffer pool specified if unset)
-     * </pre>
+     * Number of threads that share each completion queue
      *
-     * <code>int32 resource_quota_size = 1001;</code>
+     * Generated from protobuf field <code>int32 threads_per_cq = 12;</code>
+     */
+    private $threads_per_cq = 0;
+    /**
+     * Buffer pool size (no buffer pool specified if unset)
+     *
+     * Generated from protobuf field <code>int32 resource_quota_size = 1001;</code>
      */
     private $resource_quota_size = 0;
+    /**
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 1002;</code>
+     */
+    private $channel_args;
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Control::initOnce();
@@ -87,7 +83,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerType server_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerType server_type = 1;</code>
+     * @return int
      */
     public function getServerType()
     {
@@ -95,16 +92,21 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerType server_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerType server_type = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setServerType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\ServerType::class);
         $this->server_type = $var;
+
+        return $this;
     }
 
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 2;</code>
+     * @return \Grpc\Testing\SecurityParams
      */
     public function getSecurityParams()
     {
@@ -112,20 +114,23 @@
     }
 
     /**
-     * <code>.grpc.testing.SecurityParams security_params = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.SecurityParams security_params = 2;</code>
+     * @param \Grpc\Testing\SecurityParams $var
+     * @return $this
      */
-    public function setSecurityParams(&$var)
+    public function setSecurityParams($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\SecurityParams::class);
         $this->security_params = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Port on which to listen. Zero means pick unused port.
-     * </pre>
      *
-     * <code>int32 port = 4;</code>
+     * Generated from protobuf field <code>int32 port = 4;</code>
+     * @return int
      */
     public function getPort()
     {
@@ -133,24 +138,25 @@
     }
 
     /**
-     * <pre>
      * Port on which to listen. Zero means pick unused port.
-     * </pre>
      *
-     * <code>int32 port = 4;</code>
+     * Generated from protobuf field <code>int32 port = 4;</code>
+     * @param int $var
+     * @return $this
      */
     public function setPort($var)
     {
         GPBUtil::checkInt32($var);
         $this->port = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Only for async server. Number of threads used to serve the requests.
-     * </pre>
      *
-     * <code>int32 async_server_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_server_threads = 7;</code>
+     * @return int
      */
     public function getAsyncServerThreads()
     {
@@ -158,24 +164,25 @@
     }
 
     /**
-     * <pre>
      * Only for async server. Number of threads used to serve the requests.
-     * </pre>
      *
-     * <code>int32 async_server_threads = 7;</code>
+     * Generated from protobuf field <code>int32 async_server_threads = 7;</code>
+     * @param int $var
+     * @return $this
      */
     public function setAsyncServerThreads($var)
     {
         GPBUtil::checkInt32($var);
         $this->async_server_threads = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Specify the number of cores to limit server to, if desired
-     * </pre>
      *
-     * <code>int32 core_limit = 8;</code>
+     * Generated from protobuf field <code>int32 core_limit = 8;</code>
+     * @return int
      */
     public function getCoreLimit()
     {
@@ -183,27 +190,28 @@
     }
 
     /**
-     * <pre>
      * Specify the number of cores to limit server to, if desired
-     * </pre>
      *
-     * <code>int32 core_limit = 8;</code>
+     * Generated from protobuf field <code>int32 core_limit = 8;</code>
+     * @param int $var
+     * @return $this
      */
     public function setCoreLimit($var)
     {
         GPBUtil::checkInt32($var);
         $this->core_limit = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * payload config, used in generic server.
      * Note this must NOT be used in proto (non-generic) servers. For proto servers,
      * 'response sizes' must be configured from the 'response_size' field of the
      * 'SimpleRequest' objects in RPC requests.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+     * @return \Grpc\Testing\PayloadConfig
      */
     public function getPayloadConfig()
     {
@@ -211,27 +219,28 @@
     }
 
     /**
-     * <pre>
      * payload config, used in generic server.
      * Note this must NOT be used in proto (non-generic) servers. For proto servers,
      * 'response sizes' must be configured from the 'response_size' field of the
      * 'SimpleRequest' objects in RPC requests.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadConfig payload_config = 9;</code>
+     * @param \Grpc\Testing\PayloadConfig $var
+     * @return $this
      */
-    public function setPayloadConfig(&$var)
+    public function setPayloadConfig($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\PayloadConfig::class);
         $this->payload_config = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Specify the cores we should run the server on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 10;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 10;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getCoreList()
     {
@@ -239,24 +248,25 @@
     }
 
     /**
-     * <pre>
      * Specify the cores we should run the server on, if desired
-     * </pre>
      *
-     * <code>repeated int32 core_list = 10;</code>
+     * Generated from protobuf field <code>repeated int32 core_list = 10;</code>
+     * @param int[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setCoreList(&$var)
+    public function setCoreList($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
-        $this->core_list = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::INT32);
+        $this->core_list = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * If we use an OTHER_SERVER client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_server_api = 11;</code>
+     * Generated from protobuf field <code>string other_server_api = 11;</code>
+     * @return string
      */
     public function getOtherServerApi()
     {
@@ -264,24 +274,51 @@
     }
 
     /**
-     * <pre>
      * If we use an OTHER_SERVER client_type, this string gives more detail
-     * </pre>
      *
-     * <code>string other_server_api = 11;</code>
+     * Generated from protobuf field <code>string other_server_api = 11;</code>
+     * @param string $var
+     * @return $this
      */
     public function setOtherServerApi($var)
     {
         GPBUtil::checkString($var, True);
         $this->other_server_api = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
-     * Buffer pool size (no buffer pool specified if unset)
-     * </pre>
+     * Number of threads that share each completion queue
      *
-     * <code>int32 resource_quota_size = 1001;</code>
+     * Generated from protobuf field <code>int32 threads_per_cq = 12;</code>
+     * @return int
+     */
+    public function getThreadsPerCq()
+    {
+        return $this->threads_per_cq;
+    }
+
+    /**
+     * Number of threads that share each completion queue
+     *
+     * Generated from protobuf field <code>int32 threads_per_cq = 12;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setThreadsPerCq($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->threads_per_cq = $var;
+
+        return $this;
+    }
+
+    /**
+     * Buffer pool size (no buffer pool specified if unset)
+     *
+     * Generated from protobuf field <code>int32 resource_quota_size = 1001;</code>
+     * @return int
      */
     public function getResourceQuotaSize()
     {
@@ -289,16 +326,40 @@
     }
 
     /**
-     * <pre>
      * Buffer pool size (no buffer pool specified if unset)
-     * </pre>
      *
-     * <code>int32 resource_quota_size = 1001;</code>
+     * Generated from protobuf field <code>int32 resource_quota_size = 1001;</code>
+     * @param int $var
+     * @return $this
      */
     public function setResourceQuotaSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->resource_quota_size = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 1002;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
+     */
+    public function getChannelArgs()
+    {
+        return $this->channel_args;
+    }
+
+    /**
+     * Generated from protobuf field <code>repeated .grpc.testing.ChannelArg channel_args = 1002;</code>
+     * @param \Grpc\Testing\ChannelArg[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
+     */
+    public function setChannelArgs($var)
+    {
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ChannelArg::class);
+        $this->channel_args = $arr;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php
index 98b2af7..aea2cb0 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStats.php
@@ -9,51 +9,53 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ServerStats</code>
+ * Generated from protobuf message <code>grpc.testing.ServerStats</code>
  */
 class ServerStats extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * wall clock time change in seconds since last reset
-     * </pre>
      *
-     * <code>double time_elapsed = 1;</code>
+     * Generated from protobuf field <code>double time_elapsed = 1;</code>
      */
     private $time_elapsed = 0.0;
     /**
-     * <pre>
      * change in user time (in seconds) used by the server since last reset
-     * </pre>
      *
-     * <code>double time_user = 2;</code>
+     * Generated from protobuf field <code>double time_user = 2;</code>
      */
     private $time_user = 0.0;
     /**
-     * <pre>
      * change in server time (in seconds) used by the server process and all
      * threads since last reset
-     * </pre>
      *
-     * <code>double time_system = 3;</code>
+     * Generated from protobuf field <code>double time_system = 3;</code>
      */
     private $time_system = 0.0;
     /**
-     * <pre>
      * change in total cpu time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 total_cpu_time = 4;</code>
+     * Generated from protobuf field <code>uint64 total_cpu_time = 4;</code>
      */
     private $total_cpu_time = 0;
     /**
-     * <pre>
      * change in idle time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 idle_cpu_time = 5;</code>
+     * Generated from protobuf field <code>uint64 idle_cpu_time = 5;</code>
      */
     private $idle_cpu_time = 0;
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     */
+    private $cq_poll_count = 0;
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     */
+    private $core_stats = null;
 
     public function __construct() {
         \GPBMetadata\Src\Proto\Grpc\Testing\Stats::initOnce();
@@ -61,11 +63,10 @@
     }
 
     /**
-     * <pre>
      * wall clock time change in seconds since last reset
-     * </pre>
      *
-     * <code>double time_elapsed = 1;</code>
+     * Generated from protobuf field <code>double time_elapsed = 1;</code>
+     * @return float
      */
     public function getTimeElapsed()
     {
@@ -73,24 +74,25 @@
     }
 
     /**
-     * <pre>
      * wall clock time change in seconds since last reset
-     * </pre>
      *
-     * <code>double time_elapsed = 1;</code>
+     * Generated from protobuf field <code>double time_elapsed = 1;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeElapsed($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_elapsed = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * change in user time (in seconds) used by the server since last reset
-     * </pre>
      *
-     * <code>double time_user = 2;</code>
+     * Generated from protobuf field <code>double time_user = 2;</code>
+     * @return float
      */
     public function getTimeUser()
     {
@@ -98,25 +100,26 @@
     }
 
     /**
-     * <pre>
      * change in user time (in seconds) used by the server since last reset
-     * </pre>
      *
-     * <code>double time_user = 2;</code>
+     * Generated from protobuf field <code>double time_user = 2;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeUser($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_user = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * change in server time (in seconds) used by the server process and all
      * threads since last reset
-     * </pre>
      *
-     * <code>double time_system = 3;</code>
+     * Generated from protobuf field <code>double time_system = 3;</code>
+     * @return float
      */
     public function getTimeSystem()
     {
@@ -124,25 +127,26 @@
     }
 
     /**
-     * <pre>
      * change in server time (in seconds) used by the server process and all
      * threads since last reset
-     * </pre>
      *
-     * <code>double time_system = 3;</code>
+     * Generated from protobuf field <code>double time_system = 3;</code>
+     * @param float $var
+     * @return $this
      */
     public function setTimeSystem($var)
     {
         GPBUtil::checkDouble($var);
         $this->time_system = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * change in total cpu time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 total_cpu_time = 4;</code>
+     * Generated from protobuf field <code>uint64 total_cpu_time = 4;</code>
+     * @return int|string
      */
     public function getTotalCpuTime()
     {
@@ -150,24 +154,25 @@
     }
 
     /**
-     * <pre>
      * change in total cpu time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 total_cpu_time = 4;</code>
+     * Generated from protobuf field <code>uint64 total_cpu_time = 4;</code>
+     * @param int|string $var
+     * @return $this
      */
     public function setTotalCpuTime($var)
     {
         GPBUtil::checkUint64($var);
         $this->total_cpu_time = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * change in idle time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 idle_cpu_time = 5;</code>
+     * Generated from protobuf field <code>uint64 idle_cpu_time = 5;</code>
+     * @return int|string
      */
     public function getIdleCpuTime()
     {
@@ -175,16 +180,70 @@
     }
 
     /**
-     * <pre>
      * change in idle time of the server (data from proc/stat)
-     * </pre>
      *
-     * <code>uint64 idle_cpu_time = 5;</code>
+     * Generated from protobuf field <code>uint64 idle_cpu_time = 5;</code>
+     * @param int|string $var
+     * @return $this
      */
     public function setIdleCpuTime($var)
     {
         GPBUtil::checkUint64($var);
         $this->idle_cpu_time = $var;
+
+        return $this;
+    }
+
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     * @return int|string
+     */
+    public function getCqPollCount()
+    {
+        return $this->cq_poll_count;
+    }
+
+    /**
+     * Number of polls called inside completion queue
+     *
+     * Generated from protobuf field <code>uint64 cq_poll_count = 6;</code>
+     * @param int|string $var
+     * @return $this
+     */
+    public function setCqPollCount($var)
+    {
+        GPBUtil::checkUint64($var);
+        $this->cq_poll_count = $var;
+
+        return $this;
+    }
+
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     * @return \Grpc\Core\Stats
+     */
+    public function getCoreStats()
+    {
+        return $this->core_stats;
+    }
+
+    /**
+     * Core library stats
+     *
+     * Generated from protobuf field <code>.grpc.core.Stats core_stats = 7;</code>
+     * @param \Grpc\Core\Stats $var
+     * @return $this
+     */
+    public function setCoreStats($var)
+    {
+        GPBUtil::checkMessage($var, \Grpc\Core\Stats::class);
+        $this->core_stats = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php
index d293f03..04f2ca7 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerStatus.php
@@ -9,28 +9,24 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.ServerStatus</code>
+ * Generated from protobuf message <code>grpc.testing.ServerStatus</code>
  */
 class ServerStatus extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>.grpc.testing.ServerStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerStats stats = 1;</code>
      */
     private $stats = null;
     /**
-     * <pre>
      * the port bound by the server
-     * </pre>
      *
-     * <code>int32 port = 2;</code>
+     * Generated from protobuf field <code>int32 port = 2;</code>
      */
     private $port = 0;
     /**
-     * <pre>
      * Number of cores available to the server
-     * </pre>
      *
-     * <code>int32 cores = 3;</code>
+     * Generated from protobuf field <code>int32 cores = 3;</code>
      */
     private $cores = 0;
 
@@ -40,7 +36,8 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerStats stats = 1;</code>
+     * @return \Grpc\Testing\ServerStats
      */
     public function getStats()
     {
@@ -48,20 +45,23 @@
     }
 
     /**
-     * <code>.grpc.testing.ServerStats stats = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.ServerStats stats = 1;</code>
+     * @param \Grpc\Testing\ServerStats $var
+     * @return $this
      */
-    public function setStats(&$var)
+    public function setStats($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\ServerStats::class);
         $this->stats = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * the port bound by the server
-     * </pre>
      *
-     * <code>int32 port = 2;</code>
+     * Generated from protobuf field <code>int32 port = 2;</code>
+     * @return int
      */
     public function getPort()
     {
@@ -69,24 +69,25 @@
     }
 
     /**
-     * <pre>
      * the port bound by the server
-     * </pre>
      *
-     * <code>int32 port = 2;</code>
+     * Generated from protobuf field <code>int32 port = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setPort($var)
     {
         GPBUtil::checkInt32($var);
         $this->port = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Number of cores available to the server
-     * </pre>
      *
-     * <code>int32 cores = 3;</code>
+     * Generated from protobuf field <code>int32 cores = 3;</code>
+     * @return int
      */
     public function getCores()
     {
@@ -94,16 +95,18 @@
     }
 
     /**
-     * <pre>
      * Number of cores available to the server
-     * </pre>
      *
-     * <code>int32 cores = 3;</code>
+     * Generated from protobuf field <code>int32 cores = 3;</code>
+     * @param int $var
+     * @return $this
      */
     public function setCores($var)
     {
         GPBUtil::checkInt32($var);
         $this->cores = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php b/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php
index 605c83c..4110e91 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/ServerType.php
@@ -5,28 +5,26 @@
 namespace Grpc\Testing;
 
 /**
- * Protobuf enum <code>grpc.testing.ServerType</code>
+ * Protobuf enum <code>Grpc\Testing\ServerType</code>
  */
 class ServerType
 {
     /**
-     * <code>SYNC_SERVER = 0;</code>
+     * Generated from protobuf enum <code>SYNC_SERVER = 0;</code>
      */
     const SYNC_SERVER = 0;
     /**
-     * <code>ASYNC_SERVER = 1;</code>
+     * Generated from protobuf enum <code>ASYNC_SERVER = 1;</code>
      */
     const ASYNC_SERVER = 1;
     /**
-     * <code>ASYNC_GENERIC_SERVER = 2;</code>
+     * Generated from protobuf enum <code>ASYNC_GENERIC_SERVER = 2;</code>
      */
     const ASYNC_GENERIC_SERVER = 2;
     /**
-     * <pre>
      * used for some language-specific variants
-     * </pre>
      *
-     * <code>OTHER_SERVER = 3;</code>
+     * Generated from protobuf enum <code>OTHER_SERVER = 3;</code>
      */
     const OTHER_SERVER = 3;
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php
index 29834a3..507db59 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleProtoParams.php
@@ -9,16 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.SimpleProtoParams</code>
+ * Generated from protobuf message <code>grpc.testing.SimpleProtoParams</code>
  */
 class SimpleProtoParams extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
      */
     private $req_size = 0;
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
      */
     private $resp_size = 0;
 
@@ -28,7 +28,8 @@
     }
 
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
+     * @return int
      */
     public function getReqSize()
     {
@@ -36,16 +37,21 @@
     }
 
     /**
-     * <code>int32 req_size = 1;</code>
+     * Generated from protobuf field <code>int32 req_size = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setReqSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->req_size = $var;
+
+        return $this;
     }
 
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
+     * @return int
      */
     public function getRespSize()
     {
@@ -53,12 +59,16 @@
     }
 
     /**
-     * <code>int32 resp_size = 2;</code>
+     * Generated from protobuf field <code>int32 resp_size = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setRespSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->resp_size = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php
index f84c953..e0c2d2d 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleRequest.php
@@ -9,81 +9,63 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Unary request.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.SimpleRequest</code>
+ * Generated from protobuf message <code>grpc.testing.SimpleRequest</code>
  */
 class SimpleRequest extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, server randomly chooses one from other formats.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
      */
     private $response_type = 0;
     /**
-     * <pre>
      * Desired payload size in the response from the server.
-     * </pre>
      *
-     * <code>int32 response_size = 2;</code>
+     * Generated from protobuf field <code>int32 response_size = 2;</code>
      */
     private $response_size = 0;
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
      */
     private $payload = null;
     /**
-     * <pre>
      * Whether SimpleResponse should include username.
-     * </pre>
      *
-     * <code>bool fill_username = 4;</code>
+     * Generated from protobuf field <code>bool fill_username = 4;</code>
      */
     private $fill_username = false;
     /**
-     * <pre>
      * Whether SimpleResponse should include OAuth scope.
-     * </pre>
      *
-     * <code>bool fill_oauth_scope = 5;</code>
+     * Generated from protobuf field <code>bool fill_oauth_scope = 5;</code>
      */
     private $fill_oauth_scope = false;
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue response_compressed = 6;</code>
      */
     private $response_compressed = null;
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
      */
     private $response_status = null;
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
      */
     private $expect_compressed = null;
 
@@ -93,13 +75,12 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, server randomly chooses one from other formats.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * @return int
      */
     public function getResponseType()
     {
@@ -107,26 +88,27 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, server randomly chooses one from other formats.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setResponseType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
         $this->response_type = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Desired payload size in the response from the server.
-     * </pre>
      *
-     * <code>int32 response_size = 2;</code>
+     * Generated from protobuf field <code>int32 response_size = 2;</code>
+     * @return int
      */
     public function getResponseSize()
     {
@@ -134,24 +116,25 @@
     }
 
     /**
-     * <pre>
      * Desired payload size in the response from the server.
-     * </pre>
      *
-     * <code>int32 response_size = 2;</code>
+     * Generated from protobuf field <code>int32 response_size = 2;</code>
+     * @param int $var
+     * @return $this
      */
     public function setResponseSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->response_size = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
+     * @return \Grpc\Testing\Payload
      */
     public function getPayload()
     {
@@ -159,24 +142,25 @@
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
+     * @param \Grpc\Testing\Payload $var
+     * @return $this
      */
-    public function setPayload(&$var)
+    public function setPayload($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
         $this->payload = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether SimpleResponse should include username.
-     * </pre>
      *
-     * <code>bool fill_username = 4;</code>
+     * Generated from protobuf field <code>bool fill_username = 4;</code>
+     * @return bool
      */
     public function getFillUsername()
     {
@@ -184,24 +168,25 @@
     }
 
     /**
-     * <pre>
      * Whether SimpleResponse should include username.
-     * </pre>
      *
-     * <code>bool fill_username = 4;</code>
+     * Generated from protobuf field <code>bool fill_username = 4;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setFillUsername($var)
     {
         GPBUtil::checkBool($var);
         $this->fill_username = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether SimpleResponse should include OAuth scope.
-     * </pre>
      *
-     * <code>bool fill_oauth_scope = 5;</code>
+     * Generated from protobuf field <code>bool fill_oauth_scope = 5;</code>
+     * @return bool
      */
     public function getFillOauthScope()
     {
@@ -209,27 +194,28 @@
     }
 
     /**
-     * <pre>
      * Whether SimpleResponse should include OAuth scope.
-     * </pre>
      *
-     * <code>bool fill_oauth_scope = 5;</code>
+     * Generated from protobuf field <code>bool fill_oauth_scope = 5;</code>
+     * @param bool $var
+     * @return $this
      */
     public function setFillOauthScope($var)
     {
         GPBUtil::checkBool($var);
         $this->fill_oauth_scope = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+     * @return \Grpc\Testing\BoolValue
      */
     public function getResponseCompressed()
     {
@@ -237,27 +223,28 @@
     }
 
     /**
-     * <pre>
      * Whether to request the server to compress the response. This field is
      * "nullable" in order to interoperate seamlessly with clients not able to
      * implement the full compression tests by introspecting the call to verify
      * the response's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue response_compressed = 6;</code>
+     * @param \Grpc\Testing\BoolValue $var
+     * @return $this
      */
-    public function setResponseCompressed(&$var)
+    public function setResponseCompressed($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
         $this->response_compressed = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * @return \Grpc\Testing\EchoStatus
      */
     public function getResponseStatus()
     {
@@ -265,24 +252,25 @@
     }
 
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * @param \Grpc\Testing\EchoStatus $var
+     * @return $this
      */
-    public function setResponseStatus(&$var)
+    public function setResponseStatus($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\EchoStatus::class);
         $this->response_status = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+     * @return \Grpc\Testing\BoolValue
      */
     public function getExpectCompressed()
     {
@@ -290,16 +278,18 @@
     }
 
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 8;</code>
+     * @param \Grpc\Testing\BoolValue $var
+     * @return $this
      */
-    public function setExpectCompressed(&$var)
+    public function setExpectCompressed($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
         $this->expect_compressed = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php
index ccc628e..d49f337 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/SimpleResponse.php
@@ -9,37 +9,29 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Unary response, as configured by the request.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.SimpleResponse</code>
+ * Generated from protobuf message <code>grpc.testing.SimpleResponse</code>
  */
 class SimpleResponse extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Payload to increase message size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
      */
     private $payload = null;
     /**
-     * <pre>
      * The user the request came from, for verifying authentication was
      * successful when the client expected it.
-     * </pre>
      *
-     * <code>string username = 2;</code>
+     * Generated from protobuf field <code>string username = 2;</code>
      */
     private $username = '';
     /**
-     * <pre>
      * OAuth scope.
-     * </pre>
      *
-     * <code>string oauth_scope = 3;</code>
+     * Generated from protobuf field <code>string oauth_scope = 3;</code>
      */
     private $oauth_scope = '';
 
@@ -49,11 +41,10 @@
     }
 
     /**
-     * <pre>
      * Payload to increase message size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @return \Grpc\Testing\Payload
      */
     public function getPayload()
     {
@@ -61,25 +52,26 @@
     }
 
     /**
-     * <pre>
      * Payload to increase message size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @param \Grpc\Testing\Payload $var
+     * @return $this
      */
-    public function setPayload(&$var)
+    public function setPayload($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
         $this->payload = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * The user the request came from, for verifying authentication was
      * successful when the client expected it.
-     * </pre>
      *
-     * <code>string username = 2;</code>
+     * Generated from protobuf field <code>string username = 2;</code>
+     * @return string
      */
     public function getUsername()
     {
@@ -87,25 +79,26 @@
     }
 
     /**
-     * <pre>
      * The user the request came from, for verifying authentication was
      * successful when the client expected it.
-     * </pre>
      *
-     * <code>string username = 2;</code>
+     * Generated from protobuf field <code>string username = 2;</code>
+     * @param string $var
+     * @return $this
      */
     public function setUsername($var)
     {
         GPBUtil::checkString($var, True);
         $this->username = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * OAuth scope.
-     * </pre>
      *
-     * <code>string oauth_scope = 3;</code>
+     * Generated from protobuf field <code>string oauth_scope = 3;</code>
+     * @return string
      */
     public function getOauthScope()
     {
@@ -113,16 +106,18 @@
     }
 
     /**
-     * <pre>
      * OAuth scope.
-     * </pre>
      *
-     * <code>string oauth_scope = 3;</code>
+     * Generated from protobuf field <code>string oauth_scope = 3;</code>
+     * @param string $var
+     * @return $this
      */
     public function setOauthScope($var)
     {
         GPBUtil::checkString($var, True);
         $this->oauth_scope = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php
index d7bbc70..a7460af 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallRequest.php
@@ -9,31 +9,25 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Client-streaming request.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.StreamingInputCallRequest</code>
+ * Generated from protobuf message <code>grpc.testing.StreamingInputCallRequest</code>
  */
 class StreamingInputCallRequest extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
      */
     private $payload = null;
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed. This field
      * is "nullable" in order to interoperate seamlessly with servers not able to
      * implement the full compression tests by introspecting the call to verify
      * the request's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
      */
     private $expect_compressed = null;
 
@@ -43,11 +37,10 @@
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @return \Grpc\Testing\Payload
      */
     public function getPayload()
     {
@@ -55,27 +48,28 @@
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @param \Grpc\Testing\Payload $var
+     * @return $this
      */
-    public function setPayload(&$var)
+    public function setPayload($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
         $this->payload = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed. This field
      * is "nullable" in order to interoperate seamlessly with servers not able to
      * implement the full compression tests by introspecting the call to verify
      * the request's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+     * @return \Grpc\Testing\BoolValue
      */
     public function getExpectCompressed()
     {
@@ -83,19 +77,21 @@
     }
 
     /**
-     * <pre>
      * Whether the server should expect this request to be compressed. This field
      * is "nullable" in order to interoperate seamlessly with servers not able to
      * implement the full compression tests by introspecting the call to verify
      * the request's compression status.
-     * </pre>
      *
-     * <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+     * Generated from protobuf field <code>.grpc.testing.BoolValue expect_compressed = 2;</code>
+     * @param \Grpc\Testing\BoolValue $var
+     * @return $this
      */
-    public function setExpectCompressed(&$var)
+    public function setExpectCompressed($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\BoolValue::class);
         $this->expect_compressed = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php
index fdd1d0d..41f3893 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingInputCallResponse.php
@@ -9,20 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Client-streaming response.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.StreamingInputCallResponse</code>
+ * Generated from protobuf message <code>grpc.testing.StreamingInputCallResponse</code>
  */
 class StreamingInputCallResponse extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Aggregated size of payloads received from the client.
-     * </pre>
      *
-     * <code>int32 aggregated_payload_size = 1;</code>
+     * Generated from protobuf field <code>int32 aggregated_payload_size = 1;</code>
      */
     private $aggregated_payload_size = 0;
 
@@ -32,11 +28,10 @@
     }
 
     /**
-     * <pre>
      * Aggregated size of payloads received from the client.
-     * </pre>
      *
-     * <code>int32 aggregated_payload_size = 1;</code>
+     * Generated from protobuf field <code>int32 aggregated_payload_size = 1;</code>
+     * @return int
      */
     public function getAggregatedPayloadSize()
     {
@@ -44,16 +39,18 @@
     }
 
     /**
-     * <pre>
      * Aggregated size of payloads received from the client.
-     * </pre>
      *
-     * <code>int32 aggregated_payload_size = 1;</code>
+     * Generated from protobuf field <code>int32 aggregated_payload_size = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setAggregatedPayloadSize($var)
     {
         GPBUtil::checkInt32($var);
         $this->aggregated_payload_size = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php
index 2aab5fa..69d9cec 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallRequest.php
@@ -9,48 +9,38 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Server-streaming request.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.StreamingOutputCallRequest</code>
+ * Generated from protobuf message <code>grpc.testing.StreamingOutputCallRequest</code>
  */
 class StreamingOutputCallRequest extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, the payload from each response in the stream
      * might be of different types. This is to simulate a mixed type of payload
      * stream.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
      */
     private $response_type = 0;
     /**
-     * <pre>
      * Configuration for each expected response message.
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
      */
     private $response_parameters;
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
      */
     private $payload = null;
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
      */
     private $response_status = null;
 
@@ -60,15 +50,14 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, the payload from each response in the stream
      * might be of different types. This is to simulate a mixed type of payload
      * stream.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * @return int
      */
     public function getResponseType()
     {
@@ -76,28 +65,29 @@
     }
 
     /**
-     * <pre>
      * DEPRECATED, don't use. To be removed shortly.
      * Desired payload type in the response from the server.
      * If response_type is RANDOM, the payload from each response in the stream
      * might be of different types. This is to simulate a mixed type of payload
      * stream.
-     * </pre>
      *
-     * <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.PayloadType response_type = 1;</code>
+     * @param int $var
+     * @return $this
      */
     public function setResponseType($var)
     {
         GPBUtil::checkEnum($var, \Grpc\Testing\PayloadType::class);
         $this->response_type = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Configuration for each expected response message.
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
      */
     public function getResponseParameters()
     {
@@ -105,24 +95,25 @@
     }
 
     /**
-     * <pre>
      * Configuration for each expected response message.
-     * </pre>
      *
-     * <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+     * Generated from protobuf field <code>repeated .grpc.testing.ResponseParameters response_parameters = 2;</code>
+     * @param \Grpc\Testing\ResponseParameters[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
      */
-    public function setResponseParameters(&$var)
+    public function setResponseParameters($var)
     {
-        GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ResponseParameters::class);
-        $this->response_parameters = $var;
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Testing\ResponseParameters::class);
+        $this->response_parameters = $arr;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
+     * @return \Grpc\Testing\Payload
      */
     public function getPayload()
     {
@@ -130,24 +121,25 @@
     }
 
     /**
-     * <pre>
      * Optional input payload sent along with the request.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 3;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 3;</code>
+     * @param \Grpc\Testing\Payload $var
+     * @return $this
      */
-    public function setPayload(&$var)
+    public function setPayload($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
         $this->payload = $var;
+
+        return $this;
     }
 
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * @return \Grpc\Testing\EchoStatus
      */
     public function getResponseStatus()
     {
@@ -155,16 +147,18 @@
     }
 
     /**
-     * <pre>
      * Whether server should return a given status
-     * </pre>
      *
-     * <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * Generated from protobuf field <code>.grpc.testing.EchoStatus response_status = 7;</code>
+     * @param \Grpc\Testing\EchoStatus $var
+     * @return $this
      */
-    public function setResponseStatus(&$var)
+    public function setResponseStatus($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\EchoStatus::class);
         $this->response_status = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php
index c06c78c..52315bb 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/StreamingOutputCallResponse.php
@@ -9,20 +9,16 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * <pre>
  * Server-streaming response, as configured by the request and parameters.
- * </pre>
  *
- * Protobuf type <code>grpc.testing.StreamingOutputCallResponse</code>
+ * Generated from protobuf message <code>grpc.testing.StreamingOutputCallResponse</code>
  */
 class StreamingOutputCallResponse extends \Google\Protobuf\Internal\Message
 {
     /**
-     * <pre>
      * Payload to increase response size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
      */
     private $payload = null;
 
@@ -32,11 +28,10 @@
     }
 
     /**
-     * <pre>
      * Payload to increase response size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @return \Grpc\Testing\Payload
      */
     public function getPayload()
     {
@@ -44,16 +39,18 @@
     }
 
     /**
-     * <pre>
      * Payload to increase response size.
-     * </pre>
      *
-     * <code>.grpc.testing.Payload payload = 1;</code>
+     * Generated from protobuf field <code>.grpc.testing.Payload payload = 1;</code>
+     * @param \Grpc\Testing\Payload $var
+     * @return $this
      */
-    public function setPayload(&$var)
+    public function setPayload($var)
     {
         GPBUtil::checkMessage($var, \Grpc\Testing\Payload::class);
         $this->payload = $var;
+
+        return $this;
     }
 
 }
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/Void.php b/src/php/tests/qps/generated_code/Grpc/Testing/Void.php
index 38c1008..623021d 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/Void.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/Void.php
@@ -9,7 +9,7 @@
 use Google\Protobuf\Internal\GPBUtil;
 
 /**
- * Protobuf type <code>grpc.testing.Void</code>
+ * Generated from protobuf message <code>grpc.testing.Void</code>
  */
 class Void extends \Google\Protobuf\Internal\Message
 {
diff --git a/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php b/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php
index 959d839..98c244f 100644
--- a/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php
+++ b/src/php/tests/qps/generated_code/Grpc/Testing/WorkerServiceClient.php
@@ -18,17 +18,19 @@
 //
 // An integration test service that covers all the method signature permutations
 // of unary/streaming requests/responses.
-namespace Grpc\Testing {
+namespace Grpc\Testing;
 
-  class WorkerServiceClient extends \Grpc\BaseStub {
+/**
+ */
+class WorkerServiceClient extends \Grpc\BaseStub {
 
     /**
      * @param string $hostname hostname
      * @param array $opts channel options
-     * @param Grpc\Channel $channel (optional) re-use channel object
+     * @param \Grpc\Channel $channel (optional) re-use channel object
      */
     public function __construct($hostname, $opts, $channel = null) {
-      parent::__construct($hostname, $opts, $channel);
+        parent::__construct($hostname, $opts, $channel);
     }
 
     /**
@@ -42,9 +44,9 @@
      * @param array $options call options
      */
     public function RunServer($metadata = [], $options = []) {
-      return $this->_bidiRequest('/grpc.testing.WorkerService/RunServer',
-      ['\Grpc\Testing\ServerStatus','decode'],
-      $metadata, $options);
+        return $this->_bidiRequest('/grpc.testing.WorkerService/RunServer',
+        ['\Grpc\Testing\ServerStatus','decode'],
+        $metadata, $options);
     }
 
     /**
@@ -58,9 +60,9 @@
      * @param array $options call options
      */
     public function RunClient($metadata = [], $options = []) {
-      return $this->_bidiRequest('/grpc.testing.WorkerService/RunClient',
-      ['\Grpc\Testing\ClientStatus','decode'],
-      $metadata, $options);
+        return $this->_bidiRequest('/grpc.testing.WorkerService/RunClient',
+        ['\Grpc\Testing\ClientStatus','decode'],
+        $metadata, $options);
     }
 
     /**
@@ -71,10 +73,10 @@
      */
     public function CoreCount(\Grpc\Testing\CoreRequest $argument,
       $metadata = [], $options = []) {
-      return $this->_simpleRequest('/grpc.testing.WorkerService/CoreCount',
-      $argument,
-      ['\Grpc\Testing\CoreResponse', 'decode'],
-      $metadata, $options);
+        return $this->_simpleRequest('/grpc.testing.WorkerService/CoreCount',
+        $argument,
+        ['\Grpc\Testing\CoreResponse', 'decode'],
+        $metadata, $options);
     }
 
     /**
@@ -85,12 +87,10 @@
      */
     public function QuitWorker(\Grpc\Testing\Void $argument,
       $metadata = [], $options = []) {
-      return $this->_simpleRequest('/grpc.testing.WorkerService/QuitWorker',
-      $argument,
-      ['\Grpc\Testing\Void', 'decode'],
-      $metadata, $options);
+        return $this->_simpleRequest('/grpc.testing.WorkerService/QuitWorker',
+        $argument,
+        ['\Grpc\Testing\Void', 'decode'],
+        $metadata, $options);
     }
 
-  }
-
 }
diff --git a/src/php/tests/qps/histogram.php b/src/php/tests/qps/histogram.php
new file mode 100644
index 0000000..c11a67c
--- /dev/null
+++ b/src/php/tests/qps/histogram.php
@@ -0,0 +1,93 @@
+<?php
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Histogram class for use in performance testing and measurement
+class Histogram {
+  private $resolution;
+  private $max_possible;
+  private $sum;
+  private $sum_of_squares;
+  private $multiplier;
+  private $count;
+  private $min_seen;
+  private $max_seen;
+  private $buckets;
+
+  private function bucket_for($value) {
+    return (int)(log($value) / log($this->multiplier));
+  }
+
+  public function __construct($resolution, $max_possible) {
+    $this->resolution = $resolution;
+    $this->max_possible = $max_possible;
+    $this->sum = 0;
+    $this->sum_of_squares = 0;
+    $this->multiplier = 1+$resolution;
+    $this->count = 0;
+    $this->min_seen = $max_possible;
+    $this->max_seen = 0;
+    $this->buckets = array_fill(0, $this->bucket_for($max_possible)+1, 0);
+  }
+
+  public function add($value) {
+    $this->sum += $value;
+    $this->sum_of_squares += $value * $value;
+    $this->count += 1;
+    if ($value < $this->min_seen) {
+      $this->min_seen = $value;
+    }
+    if ($value > $this->max_seen) {
+      $this->max_seen = $value;
+    }
+    $this->buckets[$this->bucket_for($value)] += 1;
+  }
+
+  public function minimum() {
+    return $this->min_seen;
+  }
+
+  public function maximum() {
+    return $this->max_seen;
+  }
+
+  public function sum() {
+    return $this->sum;
+  }
+
+  public function sum_of_squares() {
+    return $this->sum_of_squares;
+  }
+
+  public function count() {
+    return $this->count;
+  }
+
+  public function contents() {
+    return $this->buckets;
+  }
+
+  public function clean() {
+    $this->sum = 0;
+    $this->sum_of_squares = 0;
+    $this->count = 0;
+    $this->min_seen = $this->max_possible;
+    $this->max_seen = 0;
+    $this->buckets = array_fill(0, $this->bucket_for($this->max_possible)+1, 0);
+  }
+}
diff --git a/src/proto/grpc/testing/proxy-service.proto b/src/proto/grpc/testing/proxy-service.proto
index 8d0a949..deaabd1 100644
--- a/src/proto/grpc/testing/proxy-service.proto
+++ b/src/proto/grpc/testing/proxy-service.proto
@@ -15,6 +15,7 @@
 syntax = "proto3";
 
 import "src/proto/grpc/testing/control.proto";
+import "src/proto/grpc/testing/stats.proto";
 
 package grpc.testing;
 
@@ -25,5 +26,6 @@
 service ProxyClientService {
   rpc GetConfig(Void) returns (ClientConfig);
   rpc ReportTime(stream ProxyStat) returns (Void);
+  rpc ReportHist(stream HistogramData) returns (Void);
 }
 
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 7b9fd64..140f4ce 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -21,7 +21,6 @@
   'src/core/lib/support/arena.cc',
   'src/core/lib/support/atm.cc',
   'src/core/lib/support/avl.cc',
-  'src/core/lib/support/backoff.cc',
   'src/core/lib/support/cmdline.cc',
   'src/core/lib/support/cpu_iphone.cc',
   'src/core/lib/support/cpu_linux.cc',
@@ -62,6 +61,7 @@
   'src/core/lib/support/tmpfile_windows.cc',
   'src/core/lib/support/wrap_memcpy.cc',
   'src/core/lib/surface/init.cc',
+  'src/core/lib/backoff/backoff.cc',
   'src/core/lib/channel/channel_args.cc',
   'src/core/lib/channel/channel_stack.cc',
   'src/core/lib/channel/channel_stack_builder.cc',
diff --git a/src/ruby/end2end/load_grpc_with_gc_stress_driver.rb b/src/ruby/end2end/load_grpc_with_gc_stress_driver.rb
new file mode 100755
index 0000000..3668b95
--- /dev/null
+++ b/src/ruby/end2end/load_grpc_with_gc_stress_driver.rb
@@ -0,0 +1,32 @@
+#!/usr/bin/env ruby
+#
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+protos_lib_dir = File.join(this_dir, 'lib')
+grpc_lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(grpc_lib_dir) unless $LOAD_PATH.include?(grpc_lib_dir)
+$LOAD_PATH.unshift(protos_lib_dir) unless $LOAD_PATH.include?(protos_lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+GC.stress = 0x04
+
+require 'grpc'
+
+GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure)
+GRPC::Core::Server.new({})
+GRPC::Core::ChannelCredentials.new
+GRPC::Core::CallCredentials.new(proc { |noop| noop })
+GRPC::Core::CompressionOptions.new
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 933a3ac..b53f09e 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -315,8 +315,8 @@
     return;
   }
 
-  bg_thread_init_rb_mu = rb_mutex_new();
   rb_global_variable(&bg_thread_init_rb_mu);
+  bg_thread_init_rb_mu = rb_mutex_new();
 
   grpc_rb_mGRPC = rb_define_module("GRPC");
   grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
diff --git a/src/ruby/qps/histogram.rb b/src/ruby/qps/histogram.rb
index 1a27e17..e48fb84 100644
--- a/src/ruby/qps/histogram.rb
+++ b/src/ruby/qps/histogram.rb
@@ -16,6 +16,8 @@
 
 # Histogram class for use in performance testing and measurement
 
+require 'thread'
+
 class Histogram
   # Determine the bucket index for a given value
   # @param {number} value The value to check
@@ -27,6 +29,7 @@
   # @param {number} resolution The resolution of the histogram
   # @param {number} max_possible The maximum value for the histogram
   def initialize(resolution, max_possible)
+    @lock = Mutex.new
     @resolution=resolution
     @max_possible=max_possible
     @sum=0
@@ -70,4 +73,16 @@
   def contents
     @buckets
   end
+
+  def merge(hist)
+    @lock.synchronize do
+      @min_seen = hist.min_seen
+      @max_seen = hist.max_seen
+      @sum += hist.sum
+      @sum_of_squares += hist.sum_of_squares
+      @count += hist.count
+      received_bucket = hist.bucket.to_a
+      @buckets = @buckets.map.with_index{ |m,i| m + received_bucket[i].to_i }
+    end
+  end
 end
diff --git a/src/ruby/qps/proxy-worker.rb b/src/ruby/qps/proxy-worker.rb
index ae7006e..fc5db50 100755
--- a/src/ruby/qps/proxy-worker.rb
+++ b/src/ruby/qps/proxy-worker.rb
@@ -41,32 +41,49 @@
     @histmax = config.histogram_params.max_possible
     @histogram = Histogram.new(@histres, @histmax)
     @start_time = Time.now
-    # TODO(vjpai): Support multiple client channels by spawning off a PHP client per channel
-    if @use_c_ext
-      puts "Use protobuf c extension"
-      command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/vendor/google/protobuf/php/ext/google/protobuf/modules/protobuf.so " + "-d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " + File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/client.php " + @mytarget
-    else
-      puts "Use protobuf php extension"
-      command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " + File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/client.php " + @mytarget
-    end	
-    puts "Starting command: " + command
-    @php_pid = spawn(command)
+    @php_pid = Array.new(@config.client_channels)
+    (0..@config.client_channels-1).each do |chan|
+      Thread.new {
+        if @use_c_ext
+          puts "Use protobuf c extension"
+          command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) +
+            "/../../php/tests/qps/vendor/google/protobuf/php/ext/google/protobuf/modules/protobuf.so " +
+            "-d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " +
+            File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/client.php " + @mytarget + " #{chan%@config.server_targets.length}"
+        else
+          puts "Use protobuf php extension"
+          command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " +
+            File.expand_path(File.dirname(__FILE__)) + "/../../php/tests/qps/client.php " + @mytarget + " #{chan%@config.server_targets.length}"
+        end
+        puts "[ruby proxy] Starting #{chan}th php-client command use c protobuf #{@use_c_ext}: " + command
+        @php_pid[chan] = spawn(command)
+        while true
+          sleep
+        end
+      }
+    end
   end
   def stop
-    Process.kill("TERM", @php_pid)
-    Process.wait(@php_pid)
+    (0..@config.client_channels-1).each do |chan|
+      Process.kill("TERM", @php_pid[chan])
+      Process.wait(@php_pid[chan])
+    end
   end
   def get_config(_args, _call)
-    puts "Answering get_config"
     @config
   end
   def report_time(call)
-    puts "Starting a time reporting stream"
     call.each_remote_read do |lat|
       @histogram.add((lat.latency)*1e9)
     end
     Grpc::Testing::Void.new
   end
+  def report_hist(call)
+    call.each_remote_read do |lat|
+      @histogram.merge(lat)
+    end
+    Grpc::Testing::Void.new
+  end
   def mark(reset)
     lat = Grpc::Testing::HistogramData.new(
       bucket: @histogram.contents,
@@ -135,7 +152,7 @@
     opts.on('--driver_port PORT', '<port>') do |v|
       options['driver_port'] = v
     end
-    opts.on("-c", "--[no-]c_proto_ext", "Use protobuf C-extention") do |c|
+    opts.on("-c", "--[no-]use_protobuf_c_extension", "Use protobuf C-extention") do |c|
       options[:c_ext] = c
     end
   end.parse!
@@ -143,7 +160,8 @@
   # Configure any errors with client or server child threads to surface
   Thread.abort_on_exception = true
 
-  s = GRPC::RpcServer.new
+  # Make sure proxy_server can handle the large number of calls in benchmarks
+  s = GRPC::RpcServer.new(pool_size: 1024)
   port = s.add_http2_port("0.0.0.0:" + options['driver_port'].to_s,
                           :this_port_is_insecure)
   bmc = ProxyBenchmarkClientServiceImpl.new(port, options[:c_ext])
diff --git a/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb b/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb
index d238198..583b2ea 100644
--- a/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/proxy-service_pb.rb
@@ -4,6 +4,7 @@
 require 'google/protobuf'
 
 require 'src/proto/grpc/testing/control_pb'
+require 'src/proto/grpc/testing/stats_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_message "grpc.testing.ProxyStat" do
     optional :latency, :double, 1
diff --git a/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb b/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb
index 484cf05..e7bb59b 100644
--- a/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/proxy-service_services_pb.rb
@@ -32,6 +32,7 @@
 
         rpc :GetConfig, Void, ClientConfig
         rpc :ReportTime, stream(ProxyStat), Void
+        rpc :ReportHist, stream(HistogramData), Void
       end
 
       Stub = Service.rpc_stub_class
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index f3ac30c..5657df8 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -31,19 +31,11 @@
     return [f for f in out if not f.startswith("third_party/nanopb/")]
 
   def grpc_public_headers(libs):
-    excluded_files = ["include/grpc/support/atm_gcc_sync.h",
-                      "include/grpc/support/atm_windows.h",
-                      "include/grpc/support/sync_windows.h",
-                      "include/grpc/support/tls_gcc.h",
-                      "include/grpc/support/tls_msvc.h",
-                      "include/grpc/impl/codegen/atm_gcc_sync.h",
-                      "include/grpc/impl/codegen/atm_windows.h",
-                      "include/grpc/impl/codegen/sync_windows.h"]
     out = []
     for lib in libs:
       if lib.name in ("grpc", "gpr"):
         out += lib.get('public_headers', [])
-    return [f for f in out if not f in excluded_files]
+    return out
 
   def grpc_private_headers(libs):
     out = []
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index 5c92f9f..4b360cf 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -65,10 +65,13 @@
     end
 
     s.subspec 'GID' do |ss|
+      ss.ios.deployment_target = '7.0'
+
       ss.header_mappings_dir = "#{src_dir}"
 
       ss.source_files = "#{src_dir}/GRPCCall+GID.{h,m}"
 
+      ss.dependency "#{s.name}/Main", version
       ss.dependency 'Google/SignIn'
     end
   end
diff --git a/templates/include/grpc/module.modulemap.template b/templates/include/grpc/module.modulemap.template
index 8edc4b5..e18bc3d 100644
--- a/templates/include/grpc/module.modulemap.template
+++ b/templates/include/grpc/module.modulemap.template
@@ -1,31 +1,57 @@
 %YAML 1.2
 --- |
   <%!
+  # TODO (mxyan): Make this list from build.yaml
+  textual_headers = ["include/grpc/support/atm_gcc_atomic.h",
+                     "include/grpc/support/atm_gcc_sync.h",
+                     "include/grpc/support/atm_windows.h",
+                     "include/grpc/support/sync_custom.h",
+                     "include/grpc/support/sync_posix.h",
+                     "include/grpc/support/sync_windows.h",
+                     "include/grpc/support/tls_gcc.h",
+                     "include/grpc/support/tls_msvc.h",
+                     "include/grpc/support/tls_pthread.h",
+                     "include/grpc/impl/codegen/atm_gcc_atomic.h",
+                     "include/grpc/impl/codegen/atm_gcc_sync.h",
+                     "include/grpc/impl/codegen/atm_windows.h",
+                     "include/grpc/impl/codegen/sync_custom.h",
+                     "include/grpc/impl/codegen/sync_posix.h",
+                     "include/grpc/impl/codegen/sync_windows.h"]
+
   def grpc_public_headers_no_dir(libs):
-    excluded_files = ["include/grpc/support/atm_gcc_sync.h",
-                      "include/grpc/support/atm_windows.h",
-                      "include/grpc/support/sync_windows.h",
-                      "include/grpc/support/tls_gcc.h",
-                      "include/grpc/support/tls_msvc.h",
-                      "include/grpc/impl/codegen/atm_gcc_sync.h",
-                      "include/grpc/impl/codegen/atm_windows.h",
-                      "include/grpc/impl/codegen/sync_windows.h"]
     out = []
     for lib in libs:
       if lib.name in ("grpc", "gpr"):
         out += lib.get('public_headers', [])
-    out = [f for f in out if f not in excluded_files]
+    out = [f for f in out if f not in textual_headers]
+    out = [hdr.split('/', 2)[2] for hdr in out]
+    return out
+
+  # Generate the list of platform-specific headers as textual headers so that
+  # they are not built when the module is built but only when they are named by
+  # an #include directive.
+  def grpc_public_textual_headers_no_dir(libs):
+    out = []
+    for lib in libs:
+      if lib.name in ("grpc", "gpr"):
+        out += lib.get('public_headers', [])
+    out = [f for f in out if f in textual_headers]
     out = [hdr.split('/', 2)[2] for hdr in out]
     return out
 
   def header_lines(files):
     return ('\n  ').join('header "%s"' % f for f in files)
+
+  def textual_header_lines(files):
+    return ('\n  ').join('textual header "%s"' % f for f in files)
   %>
   framework module grpc {
     umbrella header "grpc.h"
 
     ${header_lines(grpc_public_headers_no_dir(libs))}
 
+    ${textual_header_lines(grpc_public_textual_headers_no_dir(libs))}
+
     export *
     module * { export * }
   }
diff --git a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
index aa34a69..af85a54 100644
--- a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
@@ -32,5 +32,8 @@
   <%include file="../../python_deps.include"/>
   <%include file="../../node_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
+  # Install Mako to generate files in grpc/grpc-node
+  RUN pip install Mako
+
   # Define the default command.
   CMD ["bash"]
diff --git a/test/core/backoff/BUILD b/test/core/backoff/BUILD
new file mode 100644
index 0000000..4ae7620
--- /dev/null
+++ b/test/core/backoff/BUILD
@@ -0,0 +1,36 @@
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
+licenses(["notice"])  # Apache v2
+
+package(
+    features = [
+        "-layering_check",
+        "-parse_headers",
+    ],
+)
+
+grpc_cc_test(
+    name = "backoff_test",
+    srcs = ["backoff_test.c"],
+    language = "C",
+    deps = [
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
+)
diff --git a/test/core/backoff/backoff_test.c b/test/core/backoff/backoff_test.c
new file mode 100644
index 0000000..a29cce6
--- /dev/null
+++ b/test/core/backoff/backoff_test.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/backoff/backoff.h"
+
+#include <grpc/support/log.h>
+
+#include "test/core/util/test_config.h"
+
+static void test_constant_backoff(void) {
+  grpc_backoff backoff;
+  grpc_backoff_init(&backoff, 200 /* initial timeout */, 1.0 /* multiplier */,
+                    0.0 /* jitter */, 100 /* min timeout */,
+                    1000 /* max timeout */);
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+  for (int i = 0; i < 10000; i++) {
+    next = grpc_backoff_step(&exec_ctx, &backoff);
+    GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+    exec_ctx.now = next;
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_min_connect(void) {
+  grpc_backoff backoff;
+  grpc_backoff_init(&backoff, 100 /* initial timeout */, 1.0 /* multiplier */,
+                    0.0 /* jitter */, 200 /* min timeout */,
+                    1000 /* max timeout */);
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_no_jitter_backoff(void) {
+  grpc_backoff backoff;
+  grpc_backoff_init(&backoff, 2 /* initial timeout */, 2.0 /* multiplier */,
+                    0.0 /* jitter */, 1 /* min timeout */,
+                    513 /* max timeout */);
+  // x_1 = 2
+  // x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  exec_ctx.now = 0;
+  exec_ctx.now_is_valid = true;
+  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 2);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 6);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 14);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 30);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 62);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 126);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 254);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 510);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 1022);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  // Hit the maximum timeout. From this point onwards, retries will increase
+  // only by max timeout.
+  GPR_ASSERT(next == 1535);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 2048);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next == 2561);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_jitter_backoff(void) {
+  const int64_t initial_timeout = 500;
+  const double jitter = 0.1;
+  grpc_backoff backoff;
+  grpc_backoff_init(&backoff, (grpc_millis)initial_timeout,
+                    1.0 /* multiplier */, jitter, 100 /* min timeout */,
+                    1000 /* max timeout */);
+
+  backoff.rng_state = 0;  // force consistent PRNG
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 500);
+
+  int64_t expected_next_lower_bound =
+      (int64_t)((double)initial_timeout * (1 - jitter));
+  int64_t expected_next_upper_bound =
+      (int64_t)((double)initial_timeout * (1 + jitter));
+
+  for (int i = 0; i < 10000; i++) {
+    next = grpc_backoff_step(&exec_ctx, &backoff);
+
+    // next-now must be within (jitter*100)% of the previous timeout.
+    const int64_t timeout_millis = next - grpc_exec_ctx_now(&exec_ctx);
+    GPR_ASSERT(timeout_millis >= expected_next_lower_bound);
+    GPR_ASSERT(timeout_millis <= expected_next_upper_bound);
+
+    expected_next_lower_bound =
+        (int64_t)((double)timeout_millis * (1 - jitter));
+    expected_next_upper_bound =
+        (int64_t)((double)timeout_millis * (1 + jitter));
+    exec_ctx.now = next;
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  gpr_time_init();
+
+  test_constant_backoff();
+  test_min_connect();
+  test_no_jitter_backoff();
+  test_jitter_backoff();
+
+  return 0;
+}
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index fff0c79..b7b28a9 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -84,13 +84,18 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_completion_queue *shutdown_cq;
 
-  hex = gpr_dump(client_payload, client_payload_length,
-                 GPR_DUMP_HEX | GPR_DUMP_ASCII);
+  if (client_payload_length < 4 * 1024) {
+    hex = gpr_dump(client_payload, client_payload_length,
+                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
 
-  /* Add a debug log */
-  gpr_log(GPR_INFO, "TEST: %s", hex);
+    /* Add a debug log */
+    gpr_log(GPR_INFO, "TEST: %s", hex);
 
-  gpr_free(hex);
+    gpr_free(hex);
+  } else {
+    gpr_log(GPR_INFO, "TEST: (%" PRIdPTR " byte long string)",
+            client_payload_length);
+  }
 
   /* Init grpc */
   grpc_init();
diff --git a/test/core/bad_client/tests/window_overflow.c b/test/core/bad_client/tests/window_overflow.c
index 18c647a..e4b5f97 100644
--- a/test/core/bad_client/tests/window_overflow.c
+++ b/test/core/bad_client/tests/window_overflow.c
@@ -69,7 +69,7 @@
 #define MAX_FRAME_SIZE 16384
 #define MESSAGES_PER_FRAME (MAX_FRAME_SIZE / 5)
 #define FRAME_SIZE (MESSAGES_PER_FRAME * 5)
-#define SEND_SIZE (100 * 1024)
+#define SEND_SIZE (6 * 1024 * 1024)
 #define NUM_FRAMES (SEND_SIZE / FRAME_SIZE + 1)
   grpc_test_init(argc, argv);
 
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 7c3614b..a07ef89 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -125,7 +125,7 @@
       .context = NULL,
       .path = path,
       .start_time = gpr_now(GPR_CLOCK_MONOTONIC),
-      .deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC),
+      .deadline = GRPC_MILLIS_INF_FUTURE,
       .arena = NULL};
   grpc_error *error = grpc_call_stack_init(&exec_ctx, channel_stack, 1,
                                            free_call, call_stack, &args);
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
index 364e180..4597285 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
@@ -106,7 +106,7 @@
     deadline_seconds--;
 
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_timer_check(&exec_ctx, gpr_now(GPR_CLOCK_MONOTONIC), NULL);
+    grpc_timer_check(&exec_ctx, NULL);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   return false;
diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c
index 9b1ddad..f0a2ee5 100644
--- a/test/core/end2end/fixtures/h2_ssl_cert.c
+++ b/test/core/end2end/fixtures/h2_ssl_cert.c
@@ -319,7 +319,7 @@
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
-  op->flags = 0;
+  op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY;
   op->reserved = NULL;
   op++;
   error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
diff --git a/test/core/end2end/fixtures/http_proxy_fixture.c b/test/core/end2end/fixtures/http_proxy_fixture.c
index a4cfc77..d29401f 100644
--- a/test/core/end2end/fixtures/http_proxy_fixture.c
+++ b/test/core/end2end/fixtures/http_proxy_fixture.c
@@ -412,8 +412,8 @@
   GPR_ASSERT(resolved_addresses->naddrs >= 1);
   // Connect to requested address.
   // The connection callback inherits our reference to conn.
-  const gpr_timespec deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN));
+  const grpc_millis deadline =
+      grpc_exec_ctx_now(exec_ctx) + 10 * GPR_MS_PER_SEC;
   grpc_tcp_client_connect(exec_ctx, &conn->on_server_connect_done,
                           &conn->server_endpoint, conn->pollset_set, NULL,
                           &resolved_addresses->addrs[0], deadline);
@@ -469,14 +469,12 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   do {
     gpr_ref(&proxy->users);
-    const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    const gpr_timespec deadline =
-        gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN));
     grpc_pollset_worker* worker = NULL;
     gpr_mu_lock(proxy->mu);
     GRPC_LOG_IF_ERROR(
         "grpc_pollset_work",
-        grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline));
+        grpc_pollset_work(&exec_ctx, proxy->pollset, &worker,
+                          grpc_exec_ctx_now(&exec_ctx) + GPR_MS_PER_SEC));
     gpr_mu_unlock(proxy->mu);
     grpc_exec_ctx_flush(&exec_ctx);
   } while (!gpr_unref(&proxy->users));
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 1228c9f..0a787bb 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -60,7 +60,9 @@
 
 static gpr_timespec now_impl(gpr_clock_type clock_type) {
   GPR_ASSERT(clock_type != GPR_TIMESPAN);
-  return g_now;
+  gpr_timespec ts = g_now;
+  ts.clock_type = clock_type;
+  return ts;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -407,10 +409,8 @@
   r->addrs = addresses;
   r->lb_addrs = NULL;
   grpc_timer_init(
-      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),
-      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx),
-      gpr_now(GPR_CLOCK_MONOTONIC));
+      exec_ctx, &r->timer, GPR_MS_PER_SEC + grpc_exec_ctx_now(exec_ctx),
+      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx));
 }
 
 grpc_ares_request *my_dns_lookup_ares(
@@ -424,10 +424,8 @@
   r->addrs = NULL;
   r->lb_addrs = lb_addrs;
   grpc_timer_init(
-      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),
-      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx),
-      gpr_now(GPR_CLOCK_MONOTONIC));
+      exec_ctx, &r->timer, GPR_MS_PER_SEC + grpc_exec_ctx_now(exec_ctx),
+      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx));
   return NULL;
 }
 
@@ -487,10 +485,8 @@
   fc->ep = ep;
   fc->deadline = deadline;
   grpc_timer_init(
-      exec_ctx, &fc->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                         gpr_time_from_millis(1, GPR_TIMESPAN)),
-      GRPC_CLOSURE_CREATE(do_connect, fc, grpc_schedule_on_exec_ctx),
-      gpr_now(GPR_CLOCK_MONOTONIC));
+      exec_ctx, &fc->timer, GPR_MS_PER_SEC + grpc_exec_ctx_now(exec_ctx),
+      GRPC_CLOSURE_CREATE(do_connect, fc, grpc_schedule_on_exec_ctx));
 }
 
 static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index bf0d08a..e3fd5a8 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -92,7 +92,7 @@
     op = g_state.ops;
     op->op = GRPC_OP_SEND_INITIAL_METADATA;
     op->data.send_initial_metadata.count = 0;
-    op->flags = 0;
+    op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY;
     op->reserved = NULL;
     op++;
     GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
diff --git a/test/core/end2end/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c
index c97d11b..d442f12 100644
--- a/test/core/end2end/tests/bad_ping.c
+++ b/test/core/end2end/tests/bad_ping.c
@@ -155,14 +155,16 @@
   cq_verify(cqv);
 
   // Send too many pings to the server to trigger the punishment:
-  // The first ping is sent after data frames, it won't trigger a ping strike.
-  // Each of the following pings will trigger a ping strike, and we need at
-  // least (MAX_PING_STRIKES + 1) strikes to trigger the punishment. So
-  // (MAX_PING_STRIKES + 2) pings are needed here.
+  // Each ping will trigger a ping strike, and we need at least MAX_PING_STRIKES
+  // strikes to trigger the punishment. So (MAX_PING_STRIKES + 1) pings are
+  // needed here.
   int i;
-  for (i = 200; i < 202 + MAX_PING_STRIKES; i++) {
-    grpc_channel_ping(f.client, f.cq, tag(i), NULL);
-    CQ_EXPECT_COMPLETION(cqv, tag(i), 1);
+  for (i = 1; i <= MAX_PING_STRIKES + 1; i++) {
+    grpc_channel_ping(f.client, f.cq, tag(200 + i), NULL);
+    CQ_EXPECT_COMPLETION(cqv, tag(200 + i), 1);
+    if (i == MAX_PING_STRIKES + 1) {
+      CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+    }
     cq_verify(cqv);
   }
 
@@ -190,7 +192,6 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
-  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c
index 8d01f23..c428014 100644
--- a/test/core/end2end/tests/keepalive_timeout.c
+++ b/test/core/end2end/tests/keepalive_timeout.c
@@ -98,21 +98,21 @@
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
 
-  grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER,
-                                .key = GRPC_ARG_KEEPALIVE_TIME_MS,
-                                .value.integer = 1500},
-                               {.type = GRPC_ARG_INTEGER,
-                                .key = GRPC_ARG_KEEPALIVE_TIMEOUT_MS,
-                                .value.integer = 0},
-                               {.type = GRPC_ARG_INTEGER,
-                                .key = GRPC_ARG_HTTP2_BDP_PROBE,
-                                .value.integer = 0}};
-
-  grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(keepalive_args),
-                                   .args = keepalive_args};
+  grpc_arg keepalive_arg_elems[] = {{.type = GRPC_ARG_INTEGER,
+                                     .key = GRPC_ARG_KEEPALIVE_TIME_MS,
+                                     .value.integer = 1500},
+                                    {.type = GRPC_ARG_INTEGER,
+                                     .key = GRPC_ARG_KEEPALIVE_TIMEOUT_MS,
+                                     .value.integer = 0},
+                                    {.type = GRPC_ARG_INTEGER,
+                                     .key = GRPC_ARG_HTTP2_BDP_PROBE,
+                                     .value.integer = 0}};
+  grpc_channel_args keepalive_args = {
+      .num_args = GPR_ARRAY_SIZE(keepalive_arg_elems),
+      .args = keepalive_arg_elems};
 
   grpc_end2end_test_fixture f =
-      begin_test(config, "keepalive_timeout", &client_args, NULL);
+      begin_test(config, "keepalive_timeout", &keepalive_args, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
diff --git a/test/core/http/httpcli_test.c b/test/core/http/httpcli_test.c
index 8a53903..cc1c16d 100644
--- a/test/core/http/httpcli_test.c
+++ b/test/core/http/httpcli_test.c
@@ -35,8 +35,9 @@
 static gpr_mu *g_mu;
 static grpc_polling_entity g_pops;
 
-static gpr_timespec n_seconds_time(int seconds) {
-  return grpc_timeout_seconds_to_deadline(seconds);
+static grpc_millis n_seconds_time(int seconds) {
+  return grpc_timespec_to_millis_round_up(
+      grpc_timeout_seconds_to_deadline(seconds));
 }
 
 static void on_finish(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@@ -86,8 +87,7 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
-                          &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                          n_seconds_time(1))));
+                          &worker, n_seconds_time(1))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -128,8 +128,7 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
-                          &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                          n_seconds_time(1))));
+                          &worker, n_seconds_time(1))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
index c7455bd..f8a3cfd 100644
--- a/test/core/http/httpscli_test.c
+++ b/test/core/http/httpscli_test.c
@@ -35,8 +35,9 @@
 static gpr_mu *g_mu;
 static grpc_polling_entity g_pops;
 
-static gpr_timespec n_seconds_time(int seconds) {
-  return grpc_timeout_seconds_to_deadline(seconds);
+static grpc_millis n_seconds_time(int seconds) {
+  return grpc_timespec_to_millis_round_up(
+      grpc_timeout_seconds_to_deadline(seconds));
 }
 
 static void on_finish(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@@ -87,8 +88,7 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
-                          &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                          n_seconds_time(1))));
+                          &worker, n_seconds_time(1))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -130,8 +130,7 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
-                          &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                          n_seconds_time(1))));
+                          &worker, n_seconds_time(1))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index f8570ed..61e901f 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -176,10 +176,11 @@
                                 size_t num_bytes, size_t write_size,
                                 size_t slice_size, bool shutdown) {
   struct read_and_write_test_state state;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
   grpc_endpoint_test_fixture f =
       begin_test(config, "read_and_write_test", slice_size);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(20));
   gpr_log(GPR_DEBUG, "num_bytes=%" PRIuPTR " write_size=%" PRIuPTR
                      " slice_size=%" PRIuPTR " shutdown=%d",
           num_bytes, write_size, slice_size, shutdown);
@@ -235,11 +236,10 @@
   gpr_mu_lock(g_mu);
   while (!state.read_done || !state.write_done) {
     grpc_pollset_worker *worker = NULL;
-    GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
+    GPR_ASSERT(grpc_exec_ctx_now(&exec_ctx) < deadline);
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
   }
   gpr_mu_unlock(g_mu);
   grpc_exec_ctx_flush(&exec_ctx);
@@ -265,14 +265,14 @@
                                 int want_fail_count) {
   grpc_exec_ctx_flush(exec_ctx);
   gpr_mu_lock(g_mu);
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
-  while (gpr_time_cmp(gpr_now(deadline.clock_type), deadline) < 0 &&
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
+  while (grpc_exec_ctx_now(exec_ctx) < deadline &&
          *fail_count < want_fail_count) {
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(exec_ctx, g_pollset, &worker,
-                          gpr_now(deadline.clock_type), deadline)));
+        grpc_pollset_work(exec_ctx, g_pollset, &worker, deadline)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_flush(exec_ctx);
     gpr_mu_lock(g_mu);
diff --git a/test/core/iomgr/ev_epollsig_linux_test.c b/test/core/iomgr/ev_epollsig_linux_test.c
index cca07bf..37aadac 100644
--- a/test/core/iomgr/ev_epollsig_linux_test.c
+++ b/test/core/iomgr/ev_epollsig_linux_test.c
@@ -238,10 +238,8 @@
     grpc_pollset_worker *worker;
     gpr_mu_lock(shared->mu);
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, shared->pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          gpr_inf_future(GPR_CLOCK_MONOTONIC))));
+        "pollset_work", grpc_pollset_work(&exec_ctx, shared->pollset, &worker,
+                                          GRPC_MILLIS_INF_FUTURE)));
     gpr_mu_unlock(shared->mu);
     grpc_exec_ctx_finish(&exec_ctx);
   }
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index 881277a..1c62f34 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -252,10 +252,8 @@
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          gpr_inf_future(GPR_CLOCK_MONOTONIC))));
+        "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                                          GRPC_MILLIS_INF_FUTURE)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -371,10 +369,8 @@
     grpc_pollset_worker *worker = NULL;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          gpr_inf_future(GPR_CLOCK_MONOTONIC))));
+        "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                                          GRPC_MILLIS_INF_FUTURE)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -477,10 +473,8 @@
   while (a.cb_that_ran == NULL) {
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          gpr_inf_future(GPR_CLOCK_MONOTONIC))));
+        "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                                          GRPC_MILLIS_INF_FUTURE)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -503,10 +497,8 @@
   while (b.cb_that_ran == NULL) {
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          gpr_inf_future(GPR_CLOCK_MONOTONIC))));
+        "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                                          GRPC_MILLIS_INF_FUTURE)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
diff --git a/test/core/iomgr/pollset_set_test.c b/test/core/iomgr/pollset_set_test.c
index 5750ac0..3dd4bc8 100644
--- a/test/core/iomgr/pollset_set_test.c
+++ b/test/core/iomgr/pollset_set_test.c
@@ -203,7 +203,7 @@
    */
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_pollset_worker *worker;
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   test_fd tfds[10];
   test_pollset pollsets[3];
@@ -256,10 +256,10 @@
     make_test_fds_readable(tfds, num_fds);
 
     gpr_mu_lock(pollsets[i].mu);
-    deadline = grpc_timeout_milliseconds_to_deadline(2);
+    deadline = grpc_timespec_to_millis_round_up(
+        grpc_timeout_milliseconds_to_deadline(2));
     GPR_ASSERT(GRPC_ERROR_NONE ==
-               grpc_pollset_work(&exec_ctx, pollsets[i].ps, &worker,
-                                 gpr_now(GPR_CLOCK_MONOTONIC), deadline));
+               grpc_pollset_work(&exec_ctx, pollsets[i].ps, &worker, deadline));
     gpr_mu_unlock(pollsets[i].mu);
 
     grpc_exec_ctx_flush(&exec_ctx);
@@ -308,7 +308,7 @@
    */
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_pollset_worker *worker;
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   test_fd tfds[3];
   test_pollset pollset;
@@ -338,10 +338,10 @@
   make_test_fds_readable(tfds, num_fds);
 
   gpr_mu_lock(pollset.mu);
-  deadline = grpc_timeout_milliseconds_to_deadline(2);
+  deadline = grpc_timespec_to_millis_round_up(
+      grpc_timeout_milliseconds_to_deadline(2));
   GPR_ASSERT(GRPC_ERROR_NONE ==
-             grpc_pollset_work(&exec_ctx, pollset.ps, &worker,
-                               gpr_now(GPR_CLOCK_MONOTONIC), deadline));
+             grpc_pollset_work(&exec_ctx, pollset.ps, &worker, deadline));
   gpr_mu_unlock(pollset.mu);
   grpc_exec_ctx_flush(&exec_ctx);
 
@@ -381,7 +381,7 @@
    */
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_pollset_worker *worker;
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   test_fd tfds[3];
   test_pollset pollsets[2];
@@ -407,10 +407,10 @@
   make_test_fds_readable(tfds, num_fds);
 
   gpr_mu_lock(pollsets[0].mu);
-  deadline = grpc_timeout_milliseconds_to_deadline(2);
+  deadline = grpc_timespec_to_millis_round_up(
+      grpc_timeout_milliseconds_to_deadline(2));
   GPR_ASSERT(GRPC_ERROR_NONE ==
-             grpc_pollset_work(&exec_ctx, pollsets[0].ps, &worker,
-                               gpr_now(GPR_CLOCK_MONOTONIC), deadline));
+             grpc_pollset_work(&exec_ctx, pollsets[0].ps, &worker, deadline));
   gpr_mu_unlock(pollsets[0].mu);
   grpc_exec_ctx_flush(&exec_ctx);
 
diff --git a/test/core/iomgr/resolve_address_posix_test.c b/test/core/iomgr/resolve_address_posix_test.c
index e4be99f..cb9d608 100644
--- a/test/core/iomgr/resolve_address_posix_test.c
+++ b/test/core/iomgr/resolve_address_posix_test.c
@@ -72,35 +72,33 @@
   gpr_free(args->pollset);
 }
 
-static gpr_timespec n_sec_deadline(int seconds) {
-  return gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                      gpr_time_from_seconds(seconds, GPR_TIMESPAN));
+static grpc_millis n_sec_deadline(int seconds) {
+  return grpc_timespec_to_millis_round_up(
+      grpc_timeout_seconds_to_deadline(seconds));
 }
 
 static void actually_poll(void *argsp) {
   args_struct *args = argsp;
-  gpr_timespec deadline = n_sec_deadline(10);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis deadline = n_sec_deadline(10);
   while (true) {
     bool done = gpr_atm_acq_load(&args->done_atm) != 0;
     if (done) {
       break;
     }
-    gpr_timespec time_left =
-        gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME));
-    gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRId64 ".%09d", done,
-            time_left.tv_sec, time_left.tv_nsec);
-    GPR_ASSERT(gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) >= 0);
+    grpc_millis time_left = deadline - grpc_exec_ctx_now(&exec_ctx);
+    gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRIdPTR, done, time_left);
+    GPR_ASSERT(time_left >= 0);
     grpc_pollset_worker *worker = NULL;
-    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     gpr_mu_lock(args->mu);
-    GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, args->pollset, &worker,
-                          gpr_now(GPR_CLOCK_REALTIME), n_sec_deadline(1)));
+    GRPC_LOG_IF_ERROR("pollset_work",
+                      grpc_pollset_work(&exec_ctx, args->pollset, &worker,
+                                        n_sec_deadline(1)));
     gpr_mu_unlock(args->mu);
-    grpc_exec_ctx_finish(&exec_ctx);
+    grpc_exec_ctx_flush(&exec_ctx);
   }
   gpr_event_set(&args->ev, (void *)1);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void poll_pollset_until_request_done(args_struct *args) {
diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c
index 1110c04..178bbbb 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -68,34 +68,32 @@
   gpr_free(args->pollset);
 }
 
-static gpr_timespec n_sec_deadline(int seconds) {
-  return gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                      gpr_time_from_seconds(seconds, GPR_TIMESPAN));
+static grpc_millis n_sec_deadline(int seconds) {
+  return grpc_timespec_to_millis_round_up(
+      grpc_timeout_seconds_to_deadline(seconds));
 }
 
 static void poll_pollset_until_request_done(args_struct *args) {
-  gpr_timespec deadline = n_sec_deadline(10);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis deadline = n_sec_deadline(10);
   while (true) {
     bool done = gpr_atm_acq_load(&args->done_atm) != 0;
     if (done) {
       break;
     }
-    gpr_timespec time_left =
-        gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME));
-    gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRId64 ".%09d", done,
-            time_left.tv_sec, time_left.tv_nsec);
-    GPR_ASSERT(gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) >= 0);
+    grpc_millis time_left = deadline - grpc_exec_ctx_now(&exec_ctx);
+    gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRIdPTR, done, time_left);
+    GPR_ASSERT(time_left >= 0);
     grpc_pollset_worker *worker = NULL;
-    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     gpr_mu_lock(args->mu);
-    GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, args->pollset, &worker,
-                          gpr_now(GPR_CLOCK_REALTIME), n_sec_deadline(1)));
+    GRPC_LOG_IF_ERROR("pollset_work",
+                      grpc_pollset_work(&exec_ctx, args->pollset, &worker,
+                                        n_sec_deadline(1)));
     gpr_mu_unlock(args->mu);
-    grpc_exec_ctx_finish(&exec_ctx);
+    grpc_exec_ctx_flush(&exec_ctx);
   }
   gpr_event_set(&args->ev, (void *)1);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void must_succeed(grpc_exec_ctx *exec_ctx, void *argsp,
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 1032da9..b8b76d1 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -46,8 +46,8 @@
 static int g_connections_complete = 0;
 static grpc_endpoint *g_connecting = NULL;
 
-static gpr_timespec test_deadline(void) {
-  return grpc_timeout_seconds_to_deadline(10);
+static grpc_millis test_deadline(void) {
+  return grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
 }
 
 static void finish_connection() {
@@ -109,7 +109,7 @@
                          (socklen_t *)&resolved_addr.len) == 0);
   GRPC_CLOSURE_INIT(&done, must_succeed, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
-                          &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+                          &resolved_addr, GRPC_MILLIS_INF_FUTURE);
 
   /* await the connection */
   do {
@@ -127,8 +127,8 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          grpc_timeout_seconds_to_deadline(5))));
+                          grpc_timespec_to_millis_round_up(
+                              grpc_timeout_seconds_to_deadline(5)))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_flush(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -159,25 +159,24 @@
   /* connect to a broken address */
   GRPC_CLOSURE_INIT(&done, must_fail, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
-                          &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+                          &resolved_addr, GRPC_MILLIS_INF_FUTURE);
 
   gpr_mu_lock(g_mu);
 
   /* wait for the connection callback to finish */
   while (g_connections_complete == connections_complete_before) {
     grpc_pollset_worker *worker = NULL;
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec polling_deadline = test_deadline();
-    switch (grpc_timer_check(&exec_ctx, now, &polling_deadline)) {
+    grpc_millis polling_deadline = test_deadline();
+    switch (grpc_timer_check(&exec_ctx, &polling_deadline)) {
       case GRPC_TIMERS_FIRED:
         break;
       case GRPC_TIMERS_NOT_CHECKED:
-        polling_deadline = now;
+        polling_deadline = 0;
       /* fall through */
       case GRPC_TIMERS_CHECKED_AND_EMPTY:
         GPR_ASSERT(GRPC_LOG_IF_ERROR(
             "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                                              now, polling_deadline)));
+                                              polling_deadline)));
         break;
     }
     gpr_mu_unlock(g_mu);
diff --git a/test/core/iomgr/tcp_client_uv_test.c b/test/core/iomgr/tcp_client_uv_test.c
index 0f1db47..edfccbe 100644
--- a/test/core/iomgr/tcp_client_uv_test.c
+++ b/test/core/iomgr/tcp_client_uv_test.c
@@ -42,8 +42,8 @@
 static int g_connections_complete = 0;
 static grpc_endpoint *g_connecting = NULL;
 
-static gpr_timespec test_deadline(void) {
-  return grpc_timeout_seconds_to_deadline(10);
+static grpc_millis test_deadline(void) {
+  return grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
 }
 
 static void finish_connection(grpc_exec_ctx *exec_ctx) {
@@ -110,7 +110,7 @@
                                 (int *)&resolved_addr.len) == 0);
   GRPC_CLOSURE_INIT(&done, must_succeed, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, NULL, NULL,
-                          &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+                          &resolved_addr, GRPC_MILLIS_INF_FUTURE);
 
   gpr_mu_lock(g_mu);
 
@@ -119,8 +119,8 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          grpc_timeout_seconds_to_deadline(5))));
+                          grpc_timespec_to_millis_round_up(
+                              grpc_timeout_seconds_to_deadline(5)))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_flush(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -154,7 +154,7 @@
   /* connect to a broken address */
   GRPC_CLOSURE_INIT(&done, must_fail, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, NULL, NULL,
-                          &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+                          &resolved_addr, GRPC_MILLIS_INF_FUTURE);
 
   gpr_mu_lock(g_mu);
 
@@ -162,17 +162,17 @@
   while (g_connections_complete == connections_complete_before) {
     grpc_pollset_worker *worker = NULL;
     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec polling_deadline = test_deadline();
-    switch (grpc_timer_check(&exec_ctx, now, &polling_deadline)) {
+    grpc_millis polling_deadline = test_deadline();
+    switch (grpc_timer_check(&exec_ctx, &polling_deadline)) {
       case GRPC_TIMERS_FIRED:
         break;
       case GRPC_TIMERS_NOT_CHECKED:
-        polling_deadline = now;
+        polling_deadline = grpc_timespec_to_millis_round_up(now);
       /* fall through */
       case GRPC_TIMERS_CHECKED_AND_EMPTY:
         GPR_ASSERT(GRPC_LOG_IF_ERROR(
             "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                                              now, polling_deadline)));
+                                              polling_deadline)));
         break;
     }
     gpr_mu_unlock(g_mu);
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index cfb3cf8..6501160 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -162,7 +162,8 @@
   grpc_endpoint *ep;
   struct read_socket_state state;
   size_t written_bytes;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(20));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   gpr_log(GPR_INFO, "Read test of size %" PRIuPTR ", slice size %" PRIuPTR,
@@ -194,8 +195,7 @@
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -215,7 +215,8 @@
   grpc_endpoint *ep;
   struct read_socket_state state;
   ssize_t written_bytes;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(20));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   gpr_log(GPR_INFO, "Start large read test, slice size %" PRIuPTR, slice_size);
@@ -246,8 +247,7 @@
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -319,8 +319,8 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC),
-                          grpc_timeout_milliseconds_to_deadline(10))));
+                          grpc_timespec_to_millis_round_up(
+                              grpc_timeout_milliseconds_to_deadline(10)))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     do {
@@ -353,7 +353,8 @@
   uint8_t current_data = 0;
   grpc_slice_buffer outgoing;
   grpc_closure write_done_closure;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(20));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   gpr_log(GPR_INFO,
@@ -390,8 +391,7 @@
     }
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(&exec_ctx);
     gpr_mu_lock(g_mu);
@@ -419,7 +419,8 @@
   struct read_socket_state state;
   size_t written_bytes;
   int fd;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(20);
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(20));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_closure fd_released_cb;
   int fd_released_done = 0;
@@ -457,8 +458,7 @@
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
     gpr_log(GPR_DEBUG, "wakeup: read=%" PRIdPTR " target=%" PRIdPTR,
             state.read_bytes, state.target_read_bytes);
     gpr_mu_unlock(g_mu);
@@ -476,8 +476,7 @@
     grpc_pollset_worker *worker = NULL;
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
-        grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+        grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
     gpr_log(GPR_DEBUG, "wakeup: fd_released_done=%d", fd_released_done);
   }
   gpr_mu_unlock(g_mu);
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 4d84608..782dfb4 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -230,7 +230,8 @@
 
 static grpc_error *tcp_connect(grpc_exec_ctx *exec_ctx, const test_addr *remote,
                                on_connect_result *result) {
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
+  grpc_millis deadline =
+      grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
   int clifd;
   int nconnects_before;
   const struct sockaddr *remote_addr =
@@ -253,11 +254,10 @@
   }
   gpr_log(GPR_DEBUG, "wait");
   while (g_nconnects == nconnects_before &&
-         gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
+         deadline > grpc_exec_ctx_now(exec_ctx)) {
     grpc_pollset_worker *worker = NULL;
     grpc_error *err;
-    if ((err = grpc_pollset_work(exec_ctx, g_pollset, &worker,
-                                 gpr_now(GPR_CLOCK_MONOTONIC), deadline)) !=
+    if ((err = grpc_pollset_work(exec_ctx, g_pollset, &worker, deadline)) !=
         GRPC_ERROR_NONE) {
       gpr_mu_unlock(g_mu);
       close(clifd);
diff --git a/test/core/iomgr/tcp_server_uv_test.c b/test/core/iomgr/tcp_server_uv_test.c
index bd8ccb4..9fafd31 100644
--- a/test/core/iomgr/tcp_server_uv_test.c
+++ b/test/core/iomgr/tcp_server_uv_test.c
@@ -207,7 +207,7 @@
     GPR_ASSERT(GRPC_LOG_IF_ERROR(
         "pollset_work",
         grpc_pollset_work(exec_ctx, g_pollset, &worker,
-                          gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+                          grpc_timespec_to_millis_round_up(deadline))));
     gpr_mu_unlock(g_mu);
     grpc_exec_ctx_finish(exec_ctx);
     gpr_mu_lock(g_mu);
@@ -246,7 +246,7 @@
   GPR_ASSERT(GRPC_ERROR_NONE ==
              grpc_tcp_server_add_port(s, &resolved_addr, &svr_port));
   GPR_ASSERT(svr_port > 0);
-  GPR_ASSERT(uv_ip6_addr("::", svr_port, (struct sockaddr_in6 *)addr) == 0);
+  GPR_ASSERT((uv_ip6_addr("::", svr_port, (struct sockaddr_in6 *)addr)) == 0);
   /* Cannot use wildcard (port==0), because add_port() will try to reuse the
      same port as a previous add_port(). */
   svr1_port = grpc_pick_unused_port_or_die();
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 5f8b01f..c3d9f9d 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -41,51 +41,45 @@
 }
 
 static void add_test(void) {
-  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   int i;
   grpc_timer timers[20];
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   gpr_log(GPR_INFO, "add_test");
 
-  grpc_timer_list_init(start);
+  grpc_timer_list_init(&exec_ctx);
   grpc_timer_trace.value = 1;
   grpc_timer_check_trace.value = 1;
   memset(cb_called, 0, sizeof(cb_called));
 
+  grpc_millis start = grpc_exec_ctx_now(&exec_ctx);
+
   /* 10 ms timers.  will expire in the current epoch */
   for (i = 0; i < 10; i++) {
-    grpc_timer_init(
-        &exec_ctx, &timers[i],
-        gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
-        GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
-        start);
+    grpc_timer_init(&exec_ctx, &timers[i], start + 10,
+                    GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)i,
+                                        grpc_schedule_on_exec_ctx));
   }
 
   /* 1010 ms timers.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
-    grpc_timer_init(
-        &exec_ctx, &timers[i],
-        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)),
-        GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
-        start);
+    grpc_timer_init(&exec_ctx, &timers[i], start + 1010,
+                    GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)i,
+                                        grpc_schedule_on_exec_ctx));
   }
 
   /* collect timers.  Only the first batch should be ready. */
-  GPR_ASSERT(grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(500, GPR_TIMESPAN)),
-                 NULL) == GRPC_TIMERS_FIRED);
+  exec_ctx.now = start + 500;
+  GPR_ASSERT(grpc_timer_check(&exec_ctx, NULL) == GRPC_TIMERS_FIRED);
   grpc_exec_ctx_finish(&exec_ctx);
   for (i = 0; i < 20; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(600, GPR_TIMESPAN)),
-                 NULL) == GRPC_TIMERS_CHECKED_AND_EMPTY);
+  exec_ctx.now = start + 600;
+  GPR_ASSERT(grpc_timer_check(&exec_ctx, NULL) ==
+             GRPC_TIMERS_CHECKED_AND_EMPTY);
   grpc_exec_ctx_finish(&exec_ctx);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
@@ -93,20 +87,17 @@
   }
 
   /* collect the rest of the timers */
-  GPR_ASSERT(grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(1500, GPR_TIMESPAN)),
-                 NULL) == GRPC_TIMERS_FIRED);
+  exec_ctx.now = start + 1500;
+  GPR_ASSERT(grpc_timer_check(&exec_ctx, NULL) == GRPC_TIMERS_FIRED);
   grpc_exec_ctx_finish(&exec_ctx);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(1600, GPR_TIMESPAN)),
-                 NULL) == GRPC_TIMERS_CHECKED_AND_EMPTY);
+  exec_ctx.now = start + 1600;
+  GPR_ASSERT(grpc_timer_check(&exec_ctx, NULL) ==
+             GRPC_TIMERS_CHECKED_AND_EMPTY);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
@@ -116,10 +107,6 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static gpr_timespec tfm(int m) {
-  return gpr_time_from_millis(m, GPR_CLOCK_REALTIME);
-}
-
 /* Cleaning up a list with pending timers. */
 void destruction_test(void) {
   grpc_timer timers[5];
@@ -127,32 +114,30 @@
 
   gpr_log(GPR_INFO, "destruction_test");
 
-  grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
+  exec_ctx.now_is_valid = true;
+  exec_ctx.now = 0;
+  grpc_timer_list_init(&exec_ctx);
   grpc_timer_trace.value = 1;
   grpc_timer_check_trace.value = 1;
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_timer_init(
-      &exec_ctx, &timers[0], tfm(100),
-      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)0, grpc_schedule_on_exec_ctx),
-      gpr_time_0(GPR_CLOCK_REALTIME));
+      &exec_ctx, &timers[0], 100,
+      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)0, grpc_schedule_on_exec_ctx));
   grpc_timer_init(
-      &exec_ctx, &timers[1], tfm(3),
-      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)1, grpc_schedule_on_exec_ctx),
-      gpr_time_0(GPR_CLOCK_REALTIME));
+      &exec_ctx, &timers[1], 3,
+      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)1, grpc_schedule_on_exec_ctx));
   grpc_timer_init(
-      &exec_ctx, &timers[2], tfm(100),
-      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)2, grpc_schedule_on_exec_ctx),
-      gpr_time_0(GPR_CLOCK_REALTIME));
+      &exec_ctx, &timers[2], 100,
+      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)2, grpc_schedule_on_exec_ctx));
   grpc_timer_init(
-      &exec_ctx, &timers[3], tfm(3),
-      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)3, grpc_schedule_on_exec_ctx),
-      gpr_time_0(GPR_CLOCK_REALTIME));
+      &exec_ctx, &timers[3], 3,
+      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)3, grpc_schedule_on_exec_ctx));
   grpc_timer_init(
-      &exec_ctx, &timers[4], tfm(1),
-      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)4, grpc_schedule_on_exec_ctx),
-      gpr_time_0(GPR_CLOCK_REALTIME));
-  GPR_ASSERT(grpc_timer_check(&exec_ctx, tfm(2), NULL) == GRPC_TIMERS_FIRED);
+      &exec_ctx, &timers[4], 1,
+      GRPC_CLOSURE_CREATE(cb, (void *)(intptr_t)4, grpc_schedule_on_exec_ctx));
+  exec_ctx.now = 2;
+  GPR_ASSERT(grpc_timer_check(&exec_ctx, NULL) == GRPC_TIMERS_FIRED);
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_ASSERT(1 == cb_called[4][1]);
   grpc_timer_cancel(&exec_ctx, &timers[0]);
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 1d051be..2e44d0a 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -226,7 +226,7 @@
   grpc_udp_server *s = grpc_udp_server_create(NULL);
   int i;
   int number_of_reads_before;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   grpc_pollset *pollsets[1];
   LOG_TEST("test_receive");
   gpr_log(GPR_INFO, "clients=%d", number_of_clients);
@@ -252,7 +252,8 @@
   gpr_mu_lock(g_mu);
 
   for (i = 0; i < number_of_clients; i++) {
-    deadline = grpc_timeout_seconds_to_deadline(10);
+    deadline =
+        grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10));
 
     number_of_reads_before = g_number_of_reads;
     /* Create a socket, send a packet to the UDP server. */
@@ -262,14 +263,13 @@
                        (socklen_t)resolved_addr.len) == 0);
     GPR_ASSERT(5 == write(clifd, "hello", 5));
     while (g_number_of_reads == number_of_reads_before &&
-           gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
+           deadline > grpc_exec_ctx_now(&exec_ctx)) {
       grpc_pollset_worker *worker = NULL;
       GPR_ASSERT(GRPC_LOG_IF_ERROR(
           "pollset_work",
-          grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                            gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+          grpc_pollset_work(&exec_ctx, g_pollset, &worker, deadline)));
       gpr_mu_unlock(g_mu);
-      grpc_exec_ctx_finish(&exec_ctx);
+      grpc_exec_ctx_flush(&exec_ctx);
       gpr_mu_lock(g_mu);
     }
     GPR_ASSERT(g_number_of_reads == number_of_reads_before + 1);
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 5ac5807..34f3101 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -194,14 +194,13 @@
 static void test_oauth2_token_fetcher_creds_parsing_ok(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response =
       http_response(200, valid_oauth2_json_response);
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
                  &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_OK);
-  GPR_ASSERT(token_lifetime.tv_sec == 3599);
-  GPR_ASSERT(token_lifetime.tv_nsec == 0);
+  GPR_ASSERT(token_lifetime == 3599 * GPR_MS_PER_SEC);
   GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDKEY(token_md), "authorization") == 0);
   GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(token_md),
                                 "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") ==
@@ -214,7 +213,7 @@
 static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response =
       http_response(401, valid_oauth2_json_response);
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
@@ -227,7 +226,7 @@
 static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response = http_response(200, "");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
                  &exec_ctx, &response, &token_md, &token_lifetime) ==
@@ -239,7 +238,7 @@
 static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response =
       http_response(200,
                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
@@ -255,7 +254,7 @@
 static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response = http_response(200,
                                                  "{"
                                                  " \"expires_in\":3599, "
@@ -270,7 +269,7 @@
 static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response =
       http_response(200,
                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
@@ -287,7 +286,7 @@
     void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdelem token_md = GRPC_MDNULL;
-  gpr_timespec token_lifetime;
+  grpc_millis token_lifetime;
   grpc_httpcli_response response =
       http_response(200,
                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
@@ -555,7 +554,7 @@
 
 static int compute_engine_httpcli_get_success_override(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   validate_compute_engine_http_request(request);
   *response = http_response(200, valid_oauth2_json_response);
@@ -565,7 +564,7 @@
 
 static int compute_engine_httpcli_get_failure_override(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   validate_compute_engine_http_request(request);
   *response = http_response(403, "Not Authorized.");
@@ -575,7 +574,7 @@
 
 static int httpcli_post_should_not_be_called(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    const char *body_bytes, size_t body_size, gpr_timespec deadline,
+    const char *body_bytes, size_t body_size, grpc_millis deadline,
     grpc_closure *on_done, grpc_httpcli_response *response) {
   GPR_ASSERT("HTTP POST should not be called" == NULL);
   return 1;
@@ -583,7 +582,7 @@
 
 static int httpcli_get_should_not_be_called(grpc_exec_ctx *exec_ctx,
                                             const grpc_httpcli_request *request,
-                                            gpr_timespec deadline,
+                                            grpc_millis deadline,
                                             grpc_closure *on_done,
                                             grpc_httpcli_response *response) {
   GPR_ASSERT("HTTP GET should not be called" == NULL);
@@ -663,7 +662,7 @@
 
 static int refresh_token_httpcli_post_success(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    const char *body, size_t body_size, gpr_timespec deadline,
+    const char *body, size_t body_size, grpc_millis deadline,
     grpc_closure *on_done, grpc_httpcli_response *response) {
   validate_refresh_token_http_request(request, body, body_size);
   *response = http_response(200, valid_oauth2_json_response);
@@ -673,7 +672,7 @@
 
 static int refresh_token_httpcli_post_failure(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    const char *body, size_t body_size, gpr_timespec deadline,
+    const char *body, size_t body_size, grpc_millis deadline,
     grpc_closure *on_done, grpc_httpcli_response *response) {
   validate_refresh_token_http_request(request, body, body_size);
   *response = http_response(403, "Not Authorized.");
@@ -932,7 +931,7 @@
 
 static int default_creds_gce_detection_httpcli_get_success_override(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   *response = http_response(200, "");
   grpc_http_header *headers = gpr_malloc(sizeof(*headers) * 1);
@@ -996,7 +995,7 @@
 
 static int default_creds_gce_detection_httpcli_get_failure_override(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   /* No magic header. */
   GPR_ASSERT(strcmp(request->http.path, "/") == 0);
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index 9b17fb5..a4bfe01 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -324,7 +324,7 @@
 
 static int httpcli_post_should_not_be_called(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    const char *body_bytes, size_t body_size, gpr_timespec deadline,
+    const char *body_bytes, size_t body_size, grpc_millis deadline,
     grpc_closure *on_done, grpc_httpcli_response *response) {
   GPR_ASSERT("HTTP POST should not be called" == NULL);
   return 1;
@@ -332,7 +332,7 @@
 
 static int httpcli_get_google_keys_for_email(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   *response = http_response(200, good_google_email_keys());
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
@@ -379,7 +379,7 @@
 
 static int httpcli_get_custom_keys_for_email(
     grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_closure *on_done,
+    grpc_millis deadline, grpc_closure *on_done,
     grpc_httpcli_response *response) {
   *response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
@@ -413,7 +413,7 @@
 
 static int httpcli_get_jwk_set(grpc_exec_ctx *exec_ctx,
                                const grpc_httpcli_request *request,
-                               gpr_timespec deadline, grpc_closure *on_done,
+                               grpc_millis deadline, grpc_closure *on_done,
                                grpc_httpcli_response *response) {
   *response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
@@ -425,7 +425,7 @@
 
 static int httpcli_get_openid_config(grpc_exec_ctx *exec_ctx,
                                      const grpc_httpcli_request *request,
-                                     gpr_timespec deadline,
+                                     grpc_millis deadline,
                                      grpc_closure *on_done,
                                      grpc_httpcli_response *response) {
   *response = http_response(200, gpr_strdup(good_openid_config));
@@ -471,7 +471,7 @@
 
 static int httpcli_get_bad_json(grpc_exec_ctx *exec_ctx,
                                 const grpc_httpcli_request *request,
-                                gpr_timespec deadline, grpc_closure *on_done,
+                                grpc_millis deadline, grpc_closure *on_done,
                                 grpc_httpcli_response *response) {
   *response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
@@ -581,7 +581,7 @@
 
 static int httpcli_get_should_not_be_called(grpc_exec_ctx *exec_ctx,
                                             const grpc_httpcli_request *request,
-                                            gpr_timespec deadline,
+                                            grpc_millis deadline,
                                             grpc_closure *on_done,
                                             grpc_httpcli_response *response) {
   GPR_ASSERT(0);
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index d240403..73d6c5b 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -104,8 +104,7 @@
             "pollset_work",
             grpc_pollset_work(&exec_ctx,
                               grpc_polling_entity_pollset(&request.pops),
-                              &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                              gpr_inf_future(GPR_CLOCK_MONOTONIC)))) {
+                              &worker, GRPC_MILLIS_INF_FUTURE))) {
       request.is_done = true;
     }
   }
diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c
index 3144717..29c38df 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -110,8 +110,7 @@
             "pollset_work",
             grpc_pollset_work(&exec_ctx,
                               grpc_polling_entity_pollset(&sync.pops), &worker,
-                              gpr_now(GPR_CLOCK_MONOTONIC),
-                              gpr_inf_future(GPR_CLOCK_MONOTONIC))))
+                              GRPC_MILLIS_INF_FUTURE)))
       sync.is_done = true;
     gpr_mu_unlock(sync.mu);
     grpc_exec_ctx_flush(&exec_ctx);
diff --git a/test/core/security/ssl_server_fuzzer.c b/test/core/security/ssl_server_fuzzer.c
index 9858b11..f9b754b 100644
--- a/test/core/security/ssl_server_fuzzer.c
+++ b/test/core/security/ssl_server_fuzzer.c
@@ -84,8 +84,7 @@
   grpc_security_status status =
       grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
   GPR_ASSERT(status == GRPC_SECURITY_OK);
-  gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                       gpr_time_from_seconds(1, GPR_TIMESPAN));
+  grpc_millis deadline = GPR_MS_PER_SEC + grpc_exec_ctx_now(&exec_ctx);
 
   struct handshake_state state;
   state.done_callback_called = false;
diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c
index 5faa635..cec6fb9 100644
--- a/test/core/security/verify_jwt.c
+++ b/test/core/security/verify_jwt.c
@@ -102,11 +102,9 @@
   gpr_mu_lock(sync.mu);
   while (!sync.is_done) {
     grpc_pollset_worker *worker = NULL;
-    if (!GRPC_LOG_IF_ERROR(
-            "pollset_work",
-            grpc_pollset_work(&exec_ctx, sync.pollset, &worker,
-                              gpr_now(GPR_CLOCK_MONOTONIC),
-                              gpr_inf_future(GPR_CLOCK_MONOTONIC))))
+    if (!GRPC_LOG_IF_ERROR("pollset_work",
+                           grpc_pollset_work(&exec_ctx, sync.pollset, &worker,
+                                             GRPC_MILLIS_INF_FUTURE)))
       sync.is_done = true;
     gpr_mu_unlock(sync.mu);
     grpc_exec_ctx_flush(&exec_ctx);
diff --git a/test/core/slice/BUILD b/test/core/slice/BUILD
index f86a3a6..ad2308a 100644
--- a/test/core/slice/BUILD
+++ b/test/core/slice/BUILD
@@ -21,10 +21,22 @@
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
+    name = "percent_encode_fuzzer",
+    srcs = ["percent_encode_fuzzer.c"],
+    language = "C",
+    corpus = "percent_encode_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_fuzzer(
     name = "percent_decode_fuzzer",
     srcs = ["percent_decode_fuzzer.c"],
     language = "C",
-    corpus = "response_corpus",
+    corpus = "percent_decode_corpus",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/support/BUILD b/test/core/support/BUILD
index 096576e..407c3ef 100644
--- a/test/core/support/BUILD
+++ b/test/core/support/BUILD
@@ -39,16 +39,6 @@
 )
 
 grpc_cc_test(
-    name = "backoff_test",
-    srcs = ["backoff_test.c"],
-    language = "C",
-    deps = [
-        "//:gpr",
-        "//test/core/util:gpr_test_util",
-    ],
-)
-
-grpc_cc_test(
     name = "cmdline_test",
     srcs = ["cmdline_test.c"],
     language = "C",
diff --git a/test/core/support/backoff_test.c b/test/core/support/backoff_test.c
deleted file mode 100644
index 23e3005..0000000
--- a/test/core/support/backoff_test.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/support/backoff.h"
-
-#include <grpc/support/log.h>
-
-#include "test/core/util/test_config.h"
-
-static void test_constant_backoff(void) {
-  gpr_backoff backoff;
-  gpr_backoff_init(&backoff, 200 /* initial timeout */, 1.0 /* multiplier */,
-                   0.0 /* jitter */, 100 /* min timeout */,
-                   1000 /* max timeout */);
-
-  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
-  gpr_timespec next = gpr_backoff_begin(&backoff, now);
-  GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
-  for (int i = 0; i < 10000; i++) {
-    next = gpr_backoff_step(&backoff, now);
-    GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
-    now = next;
-  }
-}
-
-static void test_min_connect(void) {
-  gpr_backoff backoff;
-  gpr_backoff_init(&backoff, 100 /* initial timeout */, 1.0 /* multiplier */,
-                   0.0 /* jitter */, 200 /* min timeout */,
-                   1000 /* max timeout */);
-
-  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
-  gpr_timespec next = gpr_backoff_begin(&backoff, now);
-  GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
-}
-
-static void test_no_jitter_backoff(void) {
-  gpr_backoff backoff;
-  gpr_backoff_init(&backoff, 2 /* initial timeout */, 2.0 /* multiplier */,
-                   0.0 /* jitter */, 1 /* min timeout */,
-                   513 /* max timeout */);
-  // x_1 = 2
-  // x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
-  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
-  gpr_timespec next = gpr_backoff_begin(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(6, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(14, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(30, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(62, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(126, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(254, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(510, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1022, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  // Hit the maximum timeout. From this point onwards, retries will increase
-  // only by max timeout.
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1535, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2048, GPR_TIMESPAN), next) == 0);
-  now = next;
-  next = gpr_backoff_step(&backoff, now);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2561, GPR_TIMESPAN), next) == 0);
-}
-
-static void test_jitter_backoff(void) {
-  const int64_t initial_timeout = 500;
-  const double jitter = 0.1;
-  gpr_backoff backoff;
-  gpr_backoff_init(&backoff, initial_timeout, 1.0 /* multiplier */, jitter,
-                   100 /* min timeout */, 1000 /* max timeout */);
-
-  backoff.rng_state = 0;  // force consistent PRNG
-
-  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
-  gpr_timespec next = gpr_backoff_begin(&backoff, now);
-  GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 500);
-
-  int64_t expected_next_lower_bound =
-      (int64_t)((double)initial_timeout * (1 - jitter));
-  int64_t expected_next_upper_bound =
-      (int64_t)((double)initial_timeout * (1 + jitter));
-
-  for (int i = 0; i < 10000; i++) {
-    next = gpr_backoff_step(&backoff, now);
-
-    // next-now must be within (jitter*100)% of the previous timeout.
-    const int64_t timeout_millis = gpr_time_to_millis(gpr_time_sub(next, now));
-    GPR_ASSERT(timeout_millis >= expected_next_lower_bound);
-    GPR_ASSERT(timeout_millis <= expected_next_upper_bound);
-
-    expected_next_lower_bound =
-        (int64_t)((double)timeout_millis * (1 - jitter));
-    expected_next_upper_bound =
-        (int64_t)((double)timeout_millis * (1 + jitter));
-    now = next;
-  }
-}
-
-int main(int argc, char **argv) {
-  grpc_test_init(argc, argv);
-  gpr_time_init();
-
-  test_constant_backoff();
-  test_min_connect();
-  test_no_jitter_backoff();
-  test_jitter_backoff();
-
-  return 0;
-}
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index ec2cd86..3595885 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -135,14 +135,12 @@
 
   gpr_mu_lock(args->mu);
   while (gpr_atm_acq_load(&args->stop) == 0) {
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_timespec deadline =
-        gpr_time_add(now, gpr_time_from_millis(100, GPR_TIMESPAN));
+    grpc_millis deadline = grpc_exec_ctx_now(&exec_ctx) + 100;
 
     grpc_pollset_worker *worker = NULL;
-    if (!GRPC_LOG_IF_ERROR("pollset_work",
-                           grpc_pollset_work(&exec_ctx, args->pollset, &worker,
-                                             now, deadline))) {
+    if (!GRPC_LOG_IF_ERROR(
+            "pollset_work",
+            grpc_pollset_work(&exec_ctx, args->pollset, &worker, deadline))) {
       gpr_atm_rel_store(&args->stop, 1);
     }
     gpr_mu_unlock(args->mu);
diff --git a/test/core/transport/bdp_estimator_test.c b/test/core/transport/bdp_estimator_test.c
index dda48f4..4912ad5 100644
--- a/test/core/transport/bdp_estimator_test.c
+++ b/test/core/transport/bdp_estimator_test.c
@@ -24,9 +24,22 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 #include <limits.h>
+#include "src/core/lib/iomgr/timer_manager.h"
 #include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
+extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+
+static int g_clock = 0;
+
+static gpr_timespec fake_gpr_now(gpr_clock_type clock_type) {
+  return (gpr_timespec){
+      .tv_sec = g_clock, .tv_nsec = 0, .clock_type = clock_type,
+  };
+}
+
+static void inc_time(void) { g_clock += 30; }
+
 static void test_noop(void) {
   gpr_log(GPR_INFO, "test_noop");
   grpc_bdp_estimator est;
@@ -44,16 +57,19 @@
 static void add_samples(grpc_bdp_estimator *estimator, int64_t *samples,
                         size_t n) {
   grpc_bdp_estimator_add_incoming_bytes(estimator, 1234567);
-  GPR_ASSERT(grpc_bdp_estimator_need_ping(estimator) == true);
+  inc_time();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == true);
   grpc_bdp_estimator_schedule_ping(estimator);
   grpc_bdp_estimator_start_ping(estimator);
   for (size_t i = 0; i < n; i++) {
     grpc_bdp_estimator_add_incoming_bytes(estimator, samples[i]);
-    GPR_ASSERT(grpc_bdp_estimator_need_ping(estimator) == false);
+    GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == false);
   }
   gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                gpr_time_from_millis(1, GPR_TIMESPAN)));
-  grpc_bdp_estimator_complete_ping(estimator);
+  grpc_bdp_estimator_complete_ping(&exec_ctx, estimator);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void add_sample(grpc_bdp_estimator *estimator, int64_t sample) {
@@ -130,7 +146,9 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
+  gpr_now_impl = fake_gpr_now;
   grpc_init();
+  grpc_timer_manager_set_threading(false);
   test_noop();
   test_get_estimate_no_samples();
   test_get_estimate_1_sample();
diff --git a/test/core/transport/status_conversion_test.c b/test/core/transport/status_conversion_test.c
index 8955896..de8fa44 100644
--- a/test/core/transport/status_conversion_test.c
+++ b/test/core/transport/status_conversion_test.c
@@ -22,8 +22,13 @@
 
 #define GRPC_STATUS_TO_HTTP2_ERROR(a, b) \
   GPR_ASSERT(grpc_status_to_http2_error(a) == (b))
-#define HTTP2_ERROR_TO_GRPC_STATUS(a, deadline, b) \
-  GPR_ASSERT(grpc_http2_error_to_grpc_status(a, deadline) == (b))
+#define HTTP2_ERROR_TO_GRPC_STATUS(a, deadline, b)                           \
+  do {                                                                       \
+    grpc_exec_ctx my_exec_ctx = GRPC_EXEC_CTX_INIT;                          \
+    GPR_ASSERT(grpc_http2_error_to_grpc_status(&my_exec_ctx, a, deadline) == \
+               (b));                                                         \
+    grpc_exec_ctx_finish(&my_exec_ctx);                                      \
+  } while (0)
 #define GRPC_STATUS_TO_HTTP2_STATUS(a, b) \
   GPR_ASSERT(grpc_status_to_http2_status(a) == (b))
 #define HTTP2_STATUS_TO_GRPC_STATUS(a, b) \
@@ -79,7 +84,7 @@
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAVAILABLE, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DATA_LOSS, 200);
 
-  const gpr_timespec before_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis before_deadline = GRPC_MILLIS_INF_FUTURE;
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_NO_ERROR, before_deadline,
                              GRPC_STATUS_INTERNAL);
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_PROTOCOL_ERROR, before_deadline,
@@ -107,7 +112,7 @@
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_INADEQUATE_SECURITY, before_deadline,
                              GRPC_STATUS_PERMISSION_DENIED);
 
-  const gpr_timespec after_deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+  const grpc_millis after_deadline = 0;
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_NO_ERROR, after_deadline,
                              GRPC_STATUS_INTERNAL);
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_PROTOCOL_ERROR, after_deadline,
diff --git a/test/core/transport/timeout_encoding_test.c b/test/core/transport/timeout_encoding_test.c
index 6388ffb..30357fa 100644
--- a/test/core/transport/timeout_encoding_test.c
+++ b/test/core/transport/timeout_encoding_test.c
@@ -25,12 +25,13 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/murmur_hash.h"
 #include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
 
-static void assert_encodes_as(gpr_timespec ts, const char *s) {
+static void assert_encodes_as(grpc_millis ts, const char *s) {
   char buffer[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_http2_encode_timeout(ts, buffer);
   gpr_log(GPR_INFO, "check '%s' == '%s'", buffer, s);
@@ -39,47 +40,43 @@
 
 void test_encoding(void) {
   LOG_TEST("test_encoding");
-  assert_encodes_as(gpr_time_from_micros(-1, GPR_TIMESPAN), "1n");
-  assert_encodes_as(gpr_time_from_seconds(-10, GPR_TIMESPAN), "1n");
-  assert_encodes_as(gpr_time_from_nanos(10, GPR_TIMESPAN), "10n");
-  assert_encodes_as(gpr_time_from_nanos(999999999, GPR_TIMESPAN), "1S");
-  assert_encodes_as(gpr_time_from_micros(1, GPR_TIMESPAN), "1u");
-  assert_encodes_as(gpr_time_from_micros(10, GPR_TIMESPAN), "10u");
-  assert_encodes_as(gpr_time_from_micros(100, GPR_TIMESPAN), "100u");
-  assert_encodes_as(gpr_time_from_micros(890, GPR_TIMESPAN), "890u");
-  assert_encodes_as(gpr_time_from_micros(900, GPR_TIMESPAN), "900u");
-  assert_encodes_as(gpr_time_from_micros(901, GPR_TIMESPAN), "901u");
-  assert_encodes_as(gpr_time_from_millis(1, GPR_TIMESPAN), "1m");
-  assert_encodes_as(gpr_time_from_millis(2, GPR_TIMESPAN), "2m");
-  assert_encodes_as(gpr_time_from_micros(10001, GPR_TIMESPAN), "10100u");
-  assert_encodes_as(gpr_time_from_micros(999999, GPR_TIMESPAN), "1S");
-  assert_encodes_as(gpr_time_from_millis(1000, GPR_TIMESPAN), "1S");
-  assert_encodes_as(gpr_time_from_millis(2000, GPR_TIMESPAN), "2S");
-  assert_encodes_as(gpr_time_from_millis(2500, GPR_TIMESPAN), "2500m");
-  assert_encodes_as(gpr_time_from_millis(59900, GPR_TIMESPAN), "59900m");
-  assert_encodes_as(gpr_time_from_seconds(50, GPR_TIMESPAN), "50S");
-  assert_encodes_as(gpr_time_from_seconds(59, GPR_TIMESPAN), "59S");
-  assert_encodes_as(gpr_time_from_seconds(60, GPR_TIMESPAN), "1M");
-  assert_encodes_as(gpr_time_from_seconds(80, GPR_TIMESPAN), "80S");
-  assert_encodes_as(gpr_time_from_seconds(90, GPR_TIMESPAN), "90S");
-  assert_encodes_as(gpr_time_from_minutes(2, GPR_TIMESPAN), "2M");
-  assert_encodes_as(gpr_time_from_minutes(20, GPR_TIMESPAN), "20M");
-  assert_encodes_as(gpr_time_from_hours(1, GPR_TIMESPAN), "1H");
-  assert_encodes_as(gpr_time_from_hours(10, GPR_TIMESPAN), "10H");
-  assert_encodes_as(gpr_time_from_seconds(1000000000, GPR_TIMESPAN),
-                    "1000000000S");
+  assert_encodes_as(-1, "1n");
+  assert_encodes_as(-10, "1n");
+  assert_encodes_as(1, "1m");
+  assert_encodes_as(10, "10m");
+  assert_encodes_as(100, "100m");
+  assert_encodes_as(890, "890m");
+  assert_encodes_as(900, "900m");
+  assert_encodes_as(901, "901m");
+  assert_encodes_as(1000, "1S");
+  assert_encodes_as(2000, "2S");
+  assert_encodes_as(2500, "2500m");
+  assert_encodes_as(59900, "59900m");
+  assert_encodes_as(50000, "50S");
+  assert_encodes_as(59000, "59S");
+  assert_encodes_as(60000, "1M");
+  assert_encodes_as(80000, "80S");
+  assert_encodes_as(90000, "90S");
+  assert_encodes_as(120000, "2M");
+  assert_encodes_as(20 * 60 * GPR_MS_PER_SEC, "20M");
+  assert_encodes_as(60 * 60 * GPR_MS_PER_SEC, "1H");
+  assert_encodes_as(10 * 60 * 60 * GPR_MS_PER_SEC, "10H");
 }
 
-static void assert_decodes_as(const char *buffer, gpr_timespec expected) {
-  gpr_timespec got;
-  gpr_log(GPR_INFO, "check decoding '%s'", buffer);
+static void assert_decodes_as(const char *buffer, grpc_millis expected) {
+  grpc_millis got;
+  uint32_t hash = gpr_murmur_hash3(buffer, strlen(buffer), 0);
+  gpr_log(GPR_INFO, "check decoding '%s' (hash=0x%x)", buffer, hash);
   GPR_ASSERT(1 == grpc_http2_decode_timeout(
                       grpc_slice_from_static_string(buffer), &got));
-  GPR_ASSERT(0 == gpr_time_cmp(got, expected));
+  if (got != expected) {
+    gpr_log(GPR_ERROR, "got:'%" PRIdPTR "' != expected:'%" PRIdPTR "'", got,
+            expected);
+    abort();
+  }
 }
 
-void decode_suite(char ext,
-                  gpr_timespec (*answer)(int64_t x, gpr_clock_type clock)) {
+void decode_suite(char ext, grpc_millis (*answer)(int64_t x)) {
   long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
                       1234567, 12345678, 123456789, 98765432, 9876543, 987654,
                       98765,   9876,     987,       98,       9};
@@ -87,41 +84,57 @@
   char *input;
   for (i = 0; i < GPR_ARRAY_SIZE(test_vals); i++) {
     gpr_asprintf(&input, "%ld%c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
+    assert_decodes_as(input, answer(test_vals[i]));
     gpr_free(input);
 
     gpr_asprintf(&input, "   %ld%c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
+    assert_decodes_as(input, answer(test_vals[i]));
     gpr_free(input);
 
     gpr_asprintf(&input, "%ld %c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
+    assert_decodes_as(input, answer(test_vals[i]));
     gpr_free(input);
 
     gpr_asprintf(&input, "%ld %c  ", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
+    assert_decodes_as(input, answer(test_vals[i]));
     gpr_free(input);
   }
 }
 
+static grpc_millis millis_from_nanos(int64_t x) {
+  return (grpc_millis)(x / GPR_NS_PER_MS + (x % GPR_NS_PER_MS != 0));
+}
+static grpc_millis millis_from_micros(int64_t x) {
+  return (grpc_millis)(x / GPR_US_PER_MS + (x % GPR_US_PER_MS != 0));
+}
+static grpc_millis millis_from_millis(int64_t x) { return (grpc_millis)x; }
+static grpc_millis millis_from_seconds(int64_t x) {
+  return (grpc_millis)(x * GPR_MS_PER_SEC);
+}
+static grpc_millis millis_from_minutes(int64_t x) {
+  return (grpc_millis)(x * 60 * GPR_MS_PER_SEC);
+}
+static grpc_millis millis_from_hours(int64_t x) {
+  return (grpc_millis)(x * 3600 * GPR_MS_PER_SEC);
+}
+
 void test_decoding(void) {
   LOG_TEST("test_decoding");
-  decode_suite('n', gpr_time_from_nanos);
-  decode_suite('u', gpr_time_from_micros);
-  decode_suite('m', gpr_time_from_millis);
-  decode_suite('S', gpr_time_from_seconds);
-  decode_suite('M', gpr_time_from_minutes);
-  decode_suite('H', gpr_time_from_hours);
-  assert_decodes_as("1000000000S",
-                    gpr_time_from_seconds(1000 * 1000 * 1000, GPR_TIMESPAN));
-  assert_decodes_as("1000000000000000000000u", gpr_inf_future(GPR_TIMESPAN));
-  assert_decodes_as("1000000001S", gpr_inf_future(GPR_TIMESPAN));
-  assert_decodes_as("2000000001S", gpr_inf_future(GPR_TIMESPAN));
-  assert_decodes_as("9999999999S", gpr_inf_future(GPR_TIMESPAN));
+  decode_suite('n', millis_from_nanos);
+  decode_suite('u', millis_from_micros);
+  decode_suite('m', millis_from_millis);
+  decode_suite('S', millis_from_seconds);
+  decode_suite('M', millis_from_minutes);
+  decode_suite('H', millis_from_hours);
+  assert_decodes_as("1000000000S", millis_from_seconds(1000 * 1000 * 1000));
+  assert_decodes_as("1000000000000000000000u", GRPC_MILLIS_INF_FUTURE);
+  assert_decodes_as("1000000001S", GRPC_MILLIS_INF_FUTURE);
+  assert_decodes_as("2000000001S", GRPC_MILLIS_INF_FUTURE);
+  assert_decodes_as("9999999999S", GRPC_MILLIS_INF_FUTURE);
 }
 
 static void assert_decoding_fails(const char *s) {
-  gpr_timespec x;
+  grpc_millis x;
   GPR_ASSERT(0 ==
              grpc_http2_decode_timeout(grpc_slice_from_static_string(s), &x));
 }
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 10eefe1..abb50a0 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -89,12 +89,16 @@
 )
 
 grpc_cc_library(
-    name = "one_corpus_entry_fuzzer",
-    srcs = ["one_corpus_entry_fuzzer.c"],
+    name = "fuzzer_corpus_test",
+    srcs = ["fuzzer_corpus_test.cc"],
     deps = [
         ":gpr_test_util",
         "//:grpc",
     ],
+    external_deps = [
+        "gtest",
+        "gflags",
+    ],
 )
 
 sh_library(
diff --git a/test/core/util/fuzzer_corpus_test.cc b/test/core/util/fuzzer_corpus_test.cc
new file mode 100644
index 0000000..a5e99a1
--- /dev/null
+++ b/test/core/util/fuzzer_corpus_test.cc
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+
+#include <dirent.h>
+#include <gflags/gflags.h>
+#include <grpc/support/log.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "src/core/lib/iomgr/load_file.h"
+#include "test/core/util/test_config.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+extern "C" bool squelch;
+extern "C" bool leak_check;
+
+DEFINE_string(file, "", "Use this file as test data");
+DEFINE_string(directory, "", "Use this directory as test data");
+
+class FuzzerCorpusTest : public ::testing::TestWithParam<std::string> {};
+
+TEST_P(FuzzerCorpusTest, RunOneExample) {
+  gpr_log(GPR_DEBUG, "Example file: %s", GetParam().c_str());
+  grpc_slice buffer;
+  squelch = false;
+  leak_check = false;
+  GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
+                               grpc_load_file(GetParam().c_str(), 0, &buffer)));
+  LLVMFuzzerTestOneInput(GRPC_SLICE_START_PTR(buffer),
+                         GRPC_SLICE_LENGTH(buffer));
+  grpc_slice_unref(buffer);
+}
+
+class ExampleGenerator
+    : public ::testing::internal::ParamGeneratorInterface<std::string> {
+ public:
+  virtual ::testing::internal::ParamIteratorInterface<std::string>* Begin()
+      const;
+  virtual ::testing::internal::ParamIteratorInterface<std::string>* End() const;
+
+ private:
+  void Materialize() const {
+    if (examples_.empty()) {
+      if (!FLAGS_file.empty()) examples_.push_back(FLAGS_file);
+      if (!FLAGS_directory.empty()) {
+        DIR* dp;
+        struct dirent* ep;
+        dp = opendir(FLAGS_directory.c_str());
+
+        if (dp != NULL) {
+          while ((ep = readdir(dp)) != nullptr) {
+            if (ep->d_type == DT_REG) {
+              examples_.push_back(FLAGS_directory + "/" + ep->d_name);
+            }
+          }
+
+          (void)closedir(dp);
+        } else {
+          perror("Couldn't open the directory");
+          abort();
+        }
+      }
+    }
+  }
+
+  mutable std::vector<std::string> examples_;
+};
+
+class ExampleIterator
+    : public ::testing::internal::ParamIteratorInterface<std::string> {
+ public:
+  ExampleIterator(const ExampleGenerator& base_,
+                  std::vector<std::string>::const_iterator begin)
+      : base_(base_), begin_(begin), current_(begin) {}
+
+  virtual const ExampleGenerator* BaseGenerator() const { return &base_; }
+
+  virtual void Advance() { current_++; }
+  virtual ExampleIterator* Clone() const { return new ExampleIterator(*this); }
+  virtual const std::string* Current() const { return &*current_; }
+
+  virtual bool Equals(const ParamIteratorInterface<std::string>& other) const {
+    return &base_ == other.BaseGenerator() &&
+           current_ == dynamic_cast<const ExampleIterator*>(&other)->current_;
+  }
+
+ private:
+  ExampleIterator(const ExampleIterator& other)
+      : base_(other.base_), begin_(other.begin_), current_(other.current_) {}
+
+  const ExampleGenerator& base_;
+  const std::vector<std::string>::const_iterator begin_;
+  std::vector<std::string>::const_iterator current_;
+};
+
+::testing::internal::ParamIteratorInterface<std::string>*
+ExampleGenerator::Begin() const {
+  Materialize();
+  return new ExampleIterator(*this, examples_.begin());
+}
+
+::testing::internal::ParamIteratorInterface<std::string>*
+ExampleGenerator::End() const {
+  Materialize();
+  return new ExampleIterator(*this, examples_.end());
+}
+
+INSTANTIATE_TEST_CASE_P(
+    CorpusExamples, FuzzerCorpusTest,
+    ::testing::internal::ParamGenerator<std::string>(new ExampleGenerator));
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+  ::testing::InitGoogleTest(&argc, argv);
+
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/util/grpc_fuzzer.bzl b/test/core/util/grpc_fuzzer.bzl
index 41f6cdc..55b6f1c 100644
--- a/test/core/util/grpc_fuzzer.bzl
+++ b/test/core/util/grpc_fuzzer.bzl
@@ -12,19 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//bazel:grpc_build_system.bzl", "grpc_cc_binary")
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
 
 def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs):
-  grpc_cc_binary(
-    name = '%s/one_entry.bin' % name,
+  grpc_cc_test(
+    name = name,
     srcs = srcs,
-    deps = deps + ["//test/core/util:one_corpus_entry_fuzzer"],
+    deps = deps + ["//test/core/util:fuzzer_corpus_test"],
+    data = [corpus],
+    args = ['--directory', '$(location %s)' % corpus],
+    external_deps = [
+      'gtest',
+    ],
     **kwargs
   )
-  for entry in native.glob(['%s/*' % corpus]):
-    native.sh_test(
-      name = '%s/one_entry/%s' % (name, entry),
-      data = [':%s/one_entry.bin' % name, entry],
-      srcs = ['//test/core/util:fuzzer_one_entry_runner'],
-      args = ['$(location :%s/one_entry.bin)' % name, '$(location %s)' % entry]
-    )
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index ba4028db..7b94ac4 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -88,7 +88,7 @@
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("port_server_client/free");
   grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
-                   grpc_timeout_seconds_to_deadline(30),
+                   grpc_exec_ctx_now(&exec_ctx) + 30 * GPR_MS_PER_SEC,
                    GRPC_CLOSURE_CREATE(freed_port_from_server, &pr,
                                        grpc_schedule_on_exec_ctx),
                    &rsp);
@@ -100,8 +100,8 @@
     if (!GRPC_LOG_IF_ERROR(
             "pollset_work",
             grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&pr.pops),
-                              &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                              grpc_timeout_seconds_to_deadline(1)))) {
+                              &worker,
+                              grpc_exec_ctx_now(&exec_ctx) + GPR_MS_PER_SEC))) {
       pr.done = 1;
     }
   }
@@ -173,7 +173,7 @@
     grpc_resource_quota *resource_quota =
         grpc_resource_quota_create("port_server_client/pick_retry");
     grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pops, resource_quota, &req,
-                     grpc_timeout_seconds_to_deadline(10),
+                     grpc_exec_ctx_now(exec_ctx) + 30 * GPR_MS_PER_SEC,
                      GRPC_CLOSURE_CREATE(got_port_from_server, pr,
                                          grpc_schedule_on_exec_ctx),
                      &pr->response);
@@ -224,7 +224,7 @@
       grpc_resource_quota_create("port_server_client/pick");
   grpc_httpcli_get(
       &exec_ctx, &context, &pr.pops, resource_quota, &req,
-      grpc_timeout_seconds_to_deadline(30),
+      grpc_exec_ctx_now(&exec_ctx) + 30 * GPR_MS_PER_SEC,
       GRPC_CLOSURE_CREATE(got_port_from_server, &pr, grpc_schedule_on_exec_ctx),
       &pr.response);
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
@@ -235,8 +235,8 @@
     if (!GRPC_LOG_IF_ERROR(
             "pollset_work",
             grpc_pollset_work(&exec_ctx, grpc_polling_entity_pollset(&pr.pops),
-                              &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                              grpc_timeout_seconds_to_deadline(1)))) {
+                              &worker,
+                              grpc_exec_ctx_now(&exec_ctx) + GPR_MS_PER_SEC))) {
       pr.port = 0;
     }
   }
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index d3a1de8..611ecb3 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -31,6 +31,7 @@
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
 
 static void on_server_destroyed(grpc_exec_ctx *exec_ctx, void *data,
                                 grpc_error *error) {
@@ -78,14 +79,13 @@
 
 void test_tcp_server_poll(test_tcp_server *server, int seconds) {
   grpc_pollset_worker *worker = NULL;
-  gpr_timespec deadline =
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                   gpr_time_from_seconds(seconds, GPR_TIMESPAN));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_millis deadline = grpc_timespec_to_millis_round_up(
+      grpc_timeout_seconds_to_deadline(seconds));
   gpr_mu_lock(server->mu);
-  GRPC_LOG_IF_ERROR("pollset_work",
-                    grpc_pollset_work(&exec_ctx, server->pollset, &worker,
-                                      gpr_now(GPR_CLOCK_MONOTONIC), deadline));
+  GRPC_LOG_IF_ERROR(
+      "pollset_work",
+      grpc_pollset_work(&exec_ctx, server->pollset, &worker, deadline));
   gpr_mu_unlock(server->mu);
   grpc_exec_ctx_finish(&exec_ctx);
 }
diff --git a/test/cpp/common/alarm_cpp_test.cc b/test/cpp/common/alarm_cpp_test.cc
index 212972d..7adc310 100644
--- a/test/cpp/common/alarm_cpp_test.cc
+++ b/test/cpp/common/alarm_cpp_test.cc
@@ -142,7 +142,7 @@
   void* output_tag;
   bool ok;
   const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(0));
+      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -158,7 +158,7 @@
   void* output_tag;
   bool ok;
   const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(0));
+      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 41090d1..f938aea 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -105,6 +105,13 @@
     expectations_[tag(i)] = expect_ok;
     return *this;
   }
+  // AcceptOnce sets the expected ok value for a specific tag, but does not
+  // require it to appear
+  // If it does, sets *seen to true
+  Verifier& AcceptOnce(int i, bool expect_ok, bool* seen) {
+    maybe_expectations_[tag(i)] = MaybeExpect{expect_ok, seen};
+    return *this;
+  }
 
   // Next waits for 1 async tag to complete, checks its
   // expectations, and returns the tag
@@ -122,12 +129,7 @@
     } else {
       EXPECT_TRUE(cq->Next(&got_tag, &ok));
     }
-    auto it = expectations_.find(got_tag);
-    EXPECT_TRUE(it != expectations_.end());
-    if (!ignore_ok) {
-      EXPECT_EQ(it->second, ok);
-    }
-    expectations_.erase(it);
+    GotTag(got_tag, ok, ignore_ok);
     return detag(got_tag);
   }
 
@@ -138,7 +140,7 @@
   // This version of Verify allows optionally ignoring the
   // outcome of the expectation
   void Verify(CompletionQueue* cq, bool ignore_ok) {
-    GPR_ASSERT(!expectations_.empty());
+    GPR_ASSERT(!expectations_.empty() || !maybe_expectations_.empty());
     while (!expectations_.empty()) {
       Next(cq, ignore_ok);
     }
@@ -177,16 +179,43 @@
           EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline),
                     CompletionQueue::GOT_EVENT);
         }
-        auto it = expectations_.find(got_tag);
-        EXPECT_TRUE(it != expectations_.end());
-        EXPECT_EQ(it->second, ok);
-        expectations_.erase(it);
+        GotTag(got_tag, ok, false);
       }
     }
   }
 
  private:
+  void GotTag(void* got_tag, bool ok, bool ignore_ok) {
+    auto it = expectations_.find(got_tag);
+    if (it != expectations_.end()) {
+      if (!ignore_ok) {
+        EXPECT_EQ(it->second, ok);
+      }
+      expectations_.erase(it);
+    } else {
+      auto it2 = maybe_expectations_.find(got_tag);
+      if (it2 != maybe_expectations_.end()) {
+        if (it2->second.seen != nullptr) {
+          EXPECT_FALSE(*it2->second.seen);
+          *it2->second.seen = true;
+        }
+        if (!ignore_ok) {
+          EXPECT_EQ(it2->second.ok, ok);
+        }
+      } else {
+        gpr_log(GPR_ERROR, "Unexpected tag: %p", tag);
+        abort();
+      }
+    }
+  }
+
+  struct MaybeExpect {
+    bool ok;
+    bool* seen;
+  };
+
   std::map<void*, bool> expectations_;
+  std::map<void*, MaybeExpect> maybe_expectations_;
   bool spin_;
 };
 
@@ -223,11 +252,8 @@
   bool disable_blocking;
   bool inproc;
   bool health_check_service;
-  // Although the below grpc::string's are logically const, we can't declare
-  // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
-  // manage vector insertion using a copy constructor
-  grpc::string credentials_type;
-  grpc::string message_content;
+  const grpc::string credentials_type;
+  const grpc::string message_content;
 };
 
 static std::ostream& operator<<(std::ostream& out,
@@ -539,31 +565,19 @@
 
   cli_stream->Write(send_request, tag(3));
 
-  // 65536(64KB) is the default flow control window size. Should change this
-  // number when default flow control window size changes. For the write of
-  // send_request larger than the flow control window size, tag:3 will not come
-  // up until server read is initiated. For write of send_request smaller than
-  // the flow control window size, the request can take the free ride with
-  // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking)
-        .Expect(2, true)
-        .Expect(3, true)
-        .Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
-  }
+  bool seen3 = false;
+
+  Verifier(GetParam().disable_blocking)
+      .Expect(2, true)
+      .AcceptOnce(3, true, &seen3)
+      .Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking)
-        .Expect(3, true)
-        .Expect(4, true)
-        .Verify(cq_.get());
-  }
+  Verifier(GetParam().disable_blocking)
+      .AcceptOnce(3, true, &seen3)
+      .Expect(4, true)
+      .Verify(cq_.get());
 
   EXPECT_EQ(send_request.message(), recv_request.message());
 
@@ -588,6 +602,7 @@
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
+  EXPECT_TRUE(seen3);
 }
 
 // One ping, two pongs.
@@ -834,31 +849,19 @@
 
   cli_stream->WriteLast(send_request, WriteOptions(), tag(3));
 
-  // 65536(64KB) is the default flow control window size. Should change this
-  // number when default flow control window size changes. For the write of
-  // send_request larger than the flow control window size, tag:3 will not come
-  // up until server read is initiated. For write of send_request smaller than
-  // the flow control window size, the request can take the free ride with
-  // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking)
-        .Expect(2, true)
-        .Expect(3, true)
-        .Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
-  }
+  bool seen3 = false;
+
+  Verifier(GetParam().disable_blocking)
+      .Expect(2, true)
+      .AcceptOnce(3, true, &seen3)
+      .Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking)
-        .Expect(3, true)
-        .Expect(4, true)
-        .Verify(cq_.get());
-  }
+  Verifier(GetParam().disable_blocking)
+      .AcceptOnce(3, true, &seen3)
+      .Expect(4, true)
+      .Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   srv_stream.Read(&recv_request, tag(5));
@@ -877,6 +880,7 @@
   Verifier(GetParam().disable_blocking).Expect(8, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
+  EXPECT_TRUE(seen3);
 }
 
 // One ping, one pong. Using server:WriteLast api
@@ -902,31 +906,19 @@
 
   cli_stream->WriteLast(send_request, WriteOptions(), tag(3));
 
-  // 65536(64KB) is the default flow control window size. Should change this
-  // number when default flow control window size changes. For the write of
-  // send_request larger than the flow control window size, tag:3 will not come
-  // up until server read is initiated. For write of send_request smaller than
-  // the flow control window size, the request can take the free ride with
-  // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking)
-        .Expect(2, true)
-        .Expect(3, true)
-        .Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
-  }
+  bool seen3 = false;
+
+  Verifier(GetParam().disable_blocking)
+      .Expect(2, true)
+      .AcceptOnce(3, true, &seen3)
+      .Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
-    Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
-  } else {
-    Verifier(GetParam().disable_blocking)
-        .Expect(3, true)
-        .Expect(4, true)
-        .Verify(cq_.get());
-  }
+  Verifier(GetParam().disable_blocking)
+      .AcceptOnce(3, true, &seen3)
+      .Expect(4, true)
+      .Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   srv_stream.Read(&recv_request, tag(5));
@@ -947,6 +939,7 @@
   Verifier(GetParam().disable_blocking).Expect(9, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
+  EXPECT_TRUE(seen3);
 }
 
 // Metadata tests
@@ -1788,7 +1781,7 @@
   GPR_ASSERT(!credentials_types.empty());
 
   messages.push_back("Hello");
-  for (int sz = 1; sz < test_big_limit; sz *= 2) {
+  for (int sz = 1; sz <= test_big_limit; sz *= 32) {
     grpc::string big_msg;
     for (int i = 0; i < sz * 1024; i++) {
       char c = 'a' + (i % 26);
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 5dae5b0..810ee30 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -198,10 +198,7 @@
   void Log() const;
   bool use_proxy;
   bool inproc;
-  // Although the below grpc::string is logically const, we can't declare
-  // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
-  // manage vector insertion using a copy constructor
-  grpc::string credentials_type;
+  const grpc::string credentials_type;
 };
 
 static std::ostream& operator<<(std::ostream& out,
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 33b3510..9450182 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -145,7 +145,7 @@
 
       if (check_deadline) {
         EXPECT_TRUE(gpr_time_similar(deadline, srv_ctx.raw_deadline(),
-                                     gpr_time_from_millis(100, GPR_TIMESPAN)));
+                                     gpr_time_from_millis(1000, GPR_TIMESPAN)));
       }
 
       ByteBuffer recv_buffer;
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 9cc5a81..c6d3600 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -257,6 +257,7 @@
   gpr_log(GPR_INFO, "Starting test(s)..");
 
   std::vector<std::thread> test_threads;
+  std::vector<std::unique_ptr<StressTestInteropClient>> clients;
 
   // Create and start the test threads.
   // Note that:
@@ -282,9 +283,9 @@
       // Create stub(s) for each channel
       for (int stub_idx = 0; stub_idx < FLAGS_num_stubs_per_channel;
            stub_idx++) {
-        StressTestInteropClient* client = new StressTestInteropClient(
+        clients.emplace_back(new StressTestInteropClient(
             ++thread_idx, *it, channel, test_selector, FLAGS_test_duration_secs,
-            FLAGS_sleep_duration_ms, FLAGS_do_not_abort_on_transient_failures);
+            FLAGS_sleep_duration_ms, FLAGS_do_not_abort_on_transient_failures));
 
         bool is_already_created = false;
         // QpsGauge name
@@ -293,7 +294,7 @@
                       server_idx, channel_idx, stub_idx);
 
         test_threads.emplace_back(std::thread(
-            &StressTestInteropClient::MainLoop, client,
+            &StressTestInteropClient::MainLoop, clients.back().get(),
             metrics_service.CreateQpsGauge(buffer, &is_already_created)));
 
         // The QpsGauge should not have been already created
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index cadc9b2..cf9a42e 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -554,7 +554,7 @@
   grpc_exec_ctx_flush(&exec_ctx);
   grpc_call_stack *call_stack = static_cast<grpc_call_stack *>(
       gpr_zalloc(channel_stack->call_stack_size));
-  gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
   gpr_timespec start_time = gpr_now(GPR_CLOCK_MONOTONIC);
   grpc_slice method = grpc_slice_from_static_string("/foo/bar");
   grpc_call_final_info final_info;
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index 070034f..6f9dee7 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -321,7 +321,7 @@
 
   grpc_metadata_batch b;
   grpc_metadata_batch_init(&b);
-  b.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  b.deadline = GRPC_MILLIS_INF_FUTURE;
   std::vector<grpc_mdelem> elems = Metadata::GetElems(f.exec_ctx());
   std::vector<grpc_linked_mdelem> storage(elems.size());
   for (size_t i = 0; i < elems.size(); i++) {
@@ -410,7 +410,7 @@
 
   grpc_metadata_batch b;
   grpc_metadata_batch_init(&b);
-  b.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  b.deadline = GRPC_MILLIS_INF_FUTURE;
   std::vector<grpc_mdelem> elems =
       RepresentativeClientInitialMetadata::GetElems(f.exec_ctx());
   std::vector<grpc_linked_mdelem> storage(elems.size());
@@ -542,7 +542,7 @@
   grpc_metadata_batch_init(&b);
   grpc_metadata_batch b_recv;
   grpc_metadata_batch_init(&b_recv);
-  b.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  b.deadline = GRPC_MILLIS_INF_FUTURE;
   std::vector<grpc_mdelem> elems =
       RepresentativeClientInitialMetadata::GetElems(f.exec_ctx());
   std::vector<grpc_linked_mdelem> storage(elems.size());
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 5c9405f..57a69ac 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -73,9 +73,9 @@
 /* Queues a completion tag if deadline is > 0.
  * Does nothing if deadline is 0 (i.e gpr_time_0(GPR_CLOCK_MONOTONIC)) */
 static grpc_error* pollset_work(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
-                                grpc_pollset_worker** worker, gpr_timespec now,
-                                gpr_timespec deadline) {
-  if (gpr_time_cmp(deadline, gpr_time_0(GPR_CLOCK_MONOTONIC)) == 0) {
+                                grpc_pollset_worker** worker,
+                                grpc_millis deadline) {
+  if (deadline == 0) {
     gpr_log(GPR_DEBUG, "no-op");
     return GRPC_ERROR_NONE;
   }
diff --git a/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc
index bd5f02e..56b80df 100644
--- a/test/cpp/microbenchmarks/bm_error.cc
+++ b/test/cpp/microbenchmarks/bm_error.cc
@@ -159,39 +159,39 @@
 // Fixtures for tests: generate different kinds of errors
 class ErrorNone {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return GRPC_ERROR_NONE; }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
 };
 
 class ErrorCancelled {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
 };
 
 class SimpleError {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return error_.get(); }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
   ErrorPtr error_{GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error")};
 };
 
 class ErrorWithGrpcStatus {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return error_.get(); }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
   ErrorPtr error_{grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
       GRPC_STATUS_UNIMPLEMENTED)};
@@ -199,11 +199,11 @@
 
 class ErrorWithHttpError {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return error_.get(); }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
   ErrorPtr error_{grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_HTTP2_ERROR,
       GRPC_HTTP2_COMPRESSION_ERROR)};
@@ -211,11 +211,11 @@
 
 class ErrorWithNestedGrpcStatus {
  public:
-  gpr_timespec deadline() const { return deadline_; }
+  grpc_millis deadline() const { return deadline_; }
   grpc_error* error() const { return error_.get(); }
 
  private:
-  const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
   ErrorPtr nested_error_{grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
       GRPC_STATUS_UNIMPLEMENTED)};
@@ -248,12 +248,14 @@
 static void BM_ErrorGetStatus(benchmark::State& state) {
   TrackCounters track_counters;
   Fixture fixture;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   while (state.KeepRunning()) {
     grpc_status_code status;
     grpc_slice slice;
-    grpc_error_get_status(fixture.error(), fixture.deadline(), &status, &slice,
-                          NULL);
+    grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(),
+                          &status, &slice, NULL);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
 }
 
@@ -261,11 +263,13 @@
 static void BM_ErrorGetStatusCode(benchmark::State& state) {
   TrackCounters track_counters;
   Fixture fixture;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   while (state.KeepRunning()) {
     grpc_status_code status;
-    grpc_error_get_status(fixture.error(), fixture.deadline(), &status, NULL,
-                          NULL);
+    grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(),
+                          &status, NULL, NULL);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
 }
 
@@ -273,11 +277,13 @@
 static void BM_ErrorHttpError(benchmark::State& state) {
   TrackCounters track_counters;
   Fixture fixture;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   while (state.KeepRunning()) {
     grpc_http2_error_code error;
-    grpc_error_get_status(fixture.error(), fixture.deadline(), NULL, NULL,
-                          &error);
+    grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(), NULL,
+                          NULL, &error);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
 }
 
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
index 2656566..adb5e66 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -29,6 +29,7 @@
 extern "C" {
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/iomgr/timer_manager.h"
 #include "test/core/util/trickle_endpoint.h"
 }
 
@@ -45,6 +46,22 @@
 namespace grpc {
 namespace testing {
 
+gpr_atm g_now_us = 0;
+
+static gpr_timespec fake_now(gpr_clock_type clock_type) {
+  gpr_timespec t;
+  gpr_atm now = gpr_atm_no_barrier_load(&g_now_us);
+  t.tv_sec = now / GPR_US_PER_SEC;
+  t.tv_nsec = (now % GPR_US_PER_SEC) * GPR_NS_PER_US;
+  t.clock_type = clock_type;
+  return t;
+}
+
+static void inc_time() {
+  gpr_atm_no_barrier_fetch_add(&g_now_us, 100);
+  grpc_timer_manager_tick();
+}
+
 static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
 
 template <class A0>
@@ -158,6 +175,7 @@
 
   void Step(bool update_stats) {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    inc_time();
     size_t client_backlog =
         grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.client);
     size_t server_backlog =
@@ -212,9 +230,8 @@
                           int64_t iteration) {
   while (true) {
     fixture->Log(iteration);
-    switch (fixture->cq()->AsyncNext(
-        t, ok, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                            gpr_time_from_micros(100, GPR_TIMESPAN)))) {
+    switch (
+        fixture->cq()->AsyncNext(t, ok, gpr_inf_past(GPR_CLOCK_MONOTONIC))) {
       case CompletionQueue::TIMEOUT:
         fixture->Step(iteration != -1);
         break;
@@ -289,9 +306,15 @@
       inner_loop(false);
     }
     response_rw.Finish(Status::OK, tag(1));
-    need_tags = (1 << 0) | (1 << 1);
+    grpc::Status status;
+    request_rw->Finish(&status, tag(2));
+    need_tags = (1 << 0) | (1 << 1) | (1 << 2);
     while (need_tags) {
       TrickleCQNext(fixture.get(), &t, &ok, -1);
+      if (t == tag(0) && ok) {
+        request_rw->Read(&recv_response, tag(0));
+        continue;
+      }
       int i = (int)(intptr_t)t;
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
@@ -419,8 +442,12 @@
 }
 }
 
+extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+
 int main(int argc, char** argv) {
   ::benchmark::Initialize(&argc, argv);
   ::grpc::testing::InitTest(&argc, &argv, false);
+  grpc_timer_manager_set_threading(false);
+  gpr_now_impl = ::grpc::testing::fake_now;
   ::benchmark::RunSpecifiedBenchmarks();
 }
diff --git a/test/cpp/microbenchmarks/bm_pollset.cc b/test/cpp/microbenchmarks/bm_pollset.cc
index 1fc1f2f..eab1e89 100644
--- a/test/cpp/microbenchmarks/bm_pollset.cc
+++ b/test/cpp/microbenchmarks/bm_pollset.cc
@@ -117,11 +117,9 @@
   gpr_mu* mu;
   grpc_pollset_init(ps, &mu);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  gpr_timespec now = gpr_time_0(GPR_CLOCK_MONOTONIC);
-  gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
   gpr_mu_lock(mu);
   while (state.KeepRunning()) {
-    GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, NULL, now, deadline));
+    GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, NULL, 0));
   }
   grpc_closure shutdown_ps_closure;
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,
@@ -223,8 +221,6 @@
   gpr_mu* mu;
   grpc_pollset_init(ps, &mu);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  gpr_timespec now = gpr_time_0(GPR_CLOCK_MONOTONIC);
-  gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   grpc_wakeup_fd wakeup_fd;
   GRPC_ERROR_UNREF(grpc_wakeup_fd_init(&wakeup_fd));
   grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read");
@@ -245,7 +241,8 @@
   grpc_fd_notify_on_read(&exec_ctx, wakeup, continue_closure);
   gpr_mu_lock(mu);
   while (!done) {
-    GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, NULL, now, deadline));
+    GRPC_ERROR_UNREF(
+        grpc_pollset_work(&exec_ctx, ps, NULL, GRPC_MILLIS_INF_FUTURE));
   }
   grpc_fd_orphan(&exec_ctx, wakeup, NULL, NULL, false /* already_closed */,
                  "done");
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index ecd28c3..a7f8504 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -85,7 +85,7 @@
   }
 
   virtual ~FullstackFixture() {
-    server_->Shutdown();
+    server_->Shutdown(gpr_inf_past(GPR_CLOCK_MONOTONIC));
     cq_->Shutdown();
     void* tag;
     bool ok;
@@ -212,7 +212,7 @@
   }
 
   virtual ~EndpointPairFixture() {
-    server_->Shutdown();
+    server_->Shutdown(gpr_inf_past(GPR_CLOCK_MONOTONIC));
     cq_->Shutdown();
     void* tag;
     bool ok;
diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc
index cc851ca..7d0371b 100644
--- a/test/cpp/naming/resolver_component_test.cc
+++ b/test/cpp/naming/resolver_component_test.cc
@@ -199,10 +199,10 @@
     grpc_pollset_worker *worker = NULL;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     gpr_mu_lock(args->mu);
-    GRPC_LOG_IF_ERROR(
-        "pollset_work",
-        grpc_pollset_work(&exec_ctx, args->pollset, &worker,
-                          gpr_now(GPR_CLOCK_REALTIME), NSecondDeadline(1)));
+    GRPC_LOG_IF_ERROR("pollset_work",
+                      grpc_pollset_work(&exec_ctx, args->pollset, &worker,
+                                        grpc_timespec_to_millis_round_up(
+                                            NSecondDeadline(1))));
     gpr_mu_unlock(args->mu);
     grpc_exec_ctx_finish(&exec_ctx);
   }
diff --git a/tools/debug/core/chttp2_ref_leak.py b/tools/debug/core/chttp2_ref_leak.py
new file mode 100755
index 0000000..d693dd9
--- /dev/null
+++ b/tools/debug/core/chttp2_ref_leak.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python2.7
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Reads stdin to find chttp2_refcount log lines, and prints reference leaks
+# to stdout
+
+import collections
+import sys
+import re
+
+def new_obj():
+  return ['destroy']
+
+outstanding = collections.defaultdict(new_obj)
+
+# Sample log line:
+# chttp2:unref:0x629000005200 2->1 destroy [src/core/ext/transport/chttp2/transport/chttp2_transport.c:599]
+
+for line in sys.stdin:
+  m = re.search(r'chttp2:(  ref|unref):0x([a-fA-F0-9]+) [^ ]+ ([^[]+) \[(.*)\]', line)
+  if m:
+    if m.group(1) == '  ref':
+      outstanding[m.group(2)].append(m.group(3))
+    else:
+      outstanding[m.group(2)].remove(m.group(3))
+
+for obj, remaining in outstanding.items():
+  if remaining:
+    print 'LEAKED: %s %r' % (obj, remaining)
+
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index 4f18dba..d0e5af6 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -102,5 +102,8 @@
 
 RUN mkdir /var/local/jenkins
 
+# Install Mako to generate files in grpc/grpc-node
+RUN pip install Mako
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 584dd0a..0f7e8cd 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -933,6 +933,7 @@
 include/grpc/support/useful.h \
 include/grpc/support/workaround_list.h \
 src/core/ext/transport/inproc/inproc_transport.h \
+src/core/lib/backoff/backoff.h \
 src/core/lib/channel/channel_args.h \
 src/core/lib/channel/channel_stack.h \
 src/core/lib/channel/channel_stack_builder.h \
@@ -952,6 +953,7 @@
 src/core/lib/http/format_request.h \
 src/core/lib/http/httpcli.h \
 src/core/lib/http/parser.h \
+src/core/lib/iomgr/block_annotate.h \
 src/core/lib/iomgr/call_combiner.h \
 src/core/lib/iomgr/closure.h \
 src/core/lib/iomgr/combiner.h \
@@ -1028,8 +1030,6 @@
 src/core/lib/support/atomic.h \
 src/core/lib/support/atomic_with_atm.h \
 src/core/lib/support/atomic_with_std.h \
-src/core/lib/support/backoff.h \
-src/core/lib/support/block_annotate.h \
 src/core/lib/support/env.h \
 src/core/lib/support/memory.h \
 src/core/lib/support/mpscq.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ee593e3..d465403 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1056,6 +1056,8 @@
 src/core/ext/transport/inproc/inproc_transport.cc \
 src/core/ext/transport/inproc/inproc_transport.h \
 src/core/lib/README.md \
+src/core/lib/backoff/backoff.cc \
+src/core/lib/backoff/backoff.h \
 src/core/lib/channel/README.md \
 src/core/lib/channel/channel_args.cc \
 src/core/lib/channel/channel_args.h \
@@ -1096,6 +1098,7 @@
 src/core/lib/http/parser.cc \
 src/core/lib/http/parser.h \
 src/core/lib/iomgr/README.md \
+src/core/lib/iomgr/block_annotate.h \
 src/core/lib/iomgr/call_combiner.cc \
 src/core/lib/iomgr/call_combiner.h \
 src/core/lib/iomgr/closure.cc \
@@ -1301,9 +1304,6 @@
 src/core/lib/support/atomic_with_atm.h \
 src/core/lib/support/atomic_with_std.h \
 src/core/lib/support/avl.cc \
-src/core/lib/support/backoff.cc \
-src/core/lib/support/backoff.h \
-src/core/lib/support/block_annotate.h \
 src/core/lib/support/cmdline.cc \
 src/core/lib/support/cpu_iphone.cc \
 src/core/lib/support/cpu_linux.cc \
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index dd98a12..b6cc43e 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -60,7 +60,7 @@
 
 # python
 pip install virtualenv --user python
-pip install -U six tox setuptools twisted pyyaml --user python
+pip install -U Mako six tox setuptools twisted pyyaml --user python
 export PYTHONPATH=/Library/Python/3.4/site-packages
 
 # set xcode version for Obj-C tests
diff --git a/tools/internal_ci/linux/grpc_interop_toprod.sh b/tools/internal_ci/linux/grpc_interop_toprod.sh
index 3d06185..97a7d5d 100755
--- a/tools/internal_ci/linux/grpc_interop_toprod.sh
+++ b/tools/internal_ci/linux/grpc_interop_toprod.sh
@@ -28,5 +28,5 @@
     --cloud_to_prod \
     --cloud_to_prod_auth \
     --prod_servers default gateway_v4 \
-    --use_docker --internal_ci -t -j 12 $@
+    --use_docker --internal_ci --allow_flakes -t -j 12 $@
 
diff --git a/tools/jenkins/run_full_performance.sh b/tools/jenkins/run_full_performance.sh
index 9598fd7..195cc68 100755
--- a/tools/jenkins/run_full_performance.sh
+++ b/tools/jenkins/run_full_performance.sh
@@ -21,7 +21,7 @@
 
 # run 8core client vs 8core server
 tools/run_tests/run_performance_tests.py \
-    -l c++ csharp node ruby java python go node_express php_protobuf_php php_protobuf_c \
+    -l c++ csharp node ruby java python go node_express php7 php7_protobuf_c \
     --netperf \
     --category scalable \
     --bq_result_table performance_test.performance_experiment \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 95556b2..babdfeb 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -104,6 +104,23 @@
       "gpr", 
       "gpr_test_util", 
       "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "backoff_test", 
+    "src": [
+      "test/core/backoff/backoff_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
       "grpc_test_util", 
       "test_tcp_server"
     ], 
@@ -734,21 +751,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "gpr_backoff_test", 
-    "src": [
-      "test/core/support/backoff_test.c"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "gpr_cmdline_test", 
     "src": [
       "test/core/support/cmdline_test.c"
@@ -7773,7 +7775,6 @@
       "src/core/lib/support/arena.cc", 
       "src/core/lib/support/atm.cc", 
       "src/core/lib/support/avl.cc", 
-      "src/core/lib/support/backoff.cc", 
       "src/core/lib/support/cmdline.cc", 
       "src/core/lib/support/cpu_iphone.cc", 
       "src/core/lib/support/cpu_linux.cc", 
@@ -7854,8 +7855,6 @@
       "src/core/lib/support/atomic.h", 
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
-      "src/core/lib/support/backoff.h", 
-      "src/core/lib/support/block_annotate.h", 
       "src/core/lib/support/env.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
@@ -7903,8 +7902,6 @@
       "src/core/lib/support/atomic.h", 
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
-      "src/core/lib/support/backoff.h", 
-      "src/core/lib/support/block_annotate.h", 
       "src/core/lib/support/env.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
@@ -7997,6 +7994,7 @@
     "language": "c", 
     "name": "grpc_base", 
     "src": [
+      "src/core/lib/backoff/backoff.cc", 
       "src/core/lib/channel/channel_args.cc", 
       "src/core/lib/channel/channel_stack.cc", 
       "src/core/lib/channel/channel_stack_builder.cc", 
@@ -8150,6 +8148,7 @@
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
       "include/grpc/support/workaround_list.h", 
+      "src/core/lib/backoff/backoff.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
@@ -8168,6 +8167,7 @@
       "src/core/lib/http/format_request.h", 
       "src/core/lib/http/httpcli.h", 
       "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/block_annotate.h", 
       "src/core/lib/iomgr/call_combiner.h", 
       "src/core/lib/iomgr/closure.h", 
       "src/core/lib/iomgr/combiner.h", 
@@ -8283,6 +8283,7 @@
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
       "include/grpc/support/workaround_list.h", 
+      "src/core/lib/backoff/backoff.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
@@ -8301,6 +8302,7 @@
       "src/core/lib/http/format_request.h", 
       "src/core/lib/http/httpcli.h", 
       "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/block_annotate.h", 
       "src/core/lib/iomgr/call_combiner.h", 
       "src/core/lib/iomgr/closure.h", 
       "src/core/lib/iomgr/combiner.h", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 1fefb52..8341842 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -121,6 +121,28 @@
     ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "backoff_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
     "exclude_iomgrs": [
       "uv"
     ], 
@@ -805,28 +827,6 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "gpr_backoff_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ]
-  }, 
-  {
-    "args": [], 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
     "name": "gpr_cmdline_test", 
     "platforms": [
       "linux", 
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index 7914b0e..5cfab14 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -27,4 +27,5 @@
 ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1
+ruby src/ruby/end2end/load_grpc_with_gc_stress_driver.rb || EXIT_CODE=1
 exit $EXIT_CODE
diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
index e46d4e0..e7d8db8 100755
--- a/tools/run_tests/performance/build_performance.sh
+++ b/tools/run_tests/performance/build_performance.sh
@@ -31,6 +31,7 @@
   make CONFIG=${CONFIG} EMBED_OPENSSL=true EMBED_ZLIB=true qps_worker qps_json_driver -j8
 fi
 
+PHP_ALREADY_BUILT=""
 for language in $@
 do
   case "$language" in
@@ -43,6 +44,14 @@
   "go")
     tools/run_tests/performance/build_performance_go.sh
     ;;
+  "php7"|"php7_protobuf_c")
+    if [ -n "$PHP_ALREADY_BUILT" ]; then
+      echo "Skipping PHP build as already built by $PHP_ALREADY_BUILT"
+    else
+      PHP_ALREADY_BUILT=$language
+      tools/run_tests/performance/build_performance_php7.sh
+    fi
+    ;;
   "csharp")
     python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --compiler coreclr
     ;;
diff --git a/tools/run_tests/performance/build_performance_php7.sh b/tools/run_tests/performance/build_performance_php7.sh
new file mode 100755
index 0000000..141c9fd
--- /dev/null
+++ b/tools/run_tests/performance/build_performance_php7.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd $(dirname $0)/../../..
+CONFIG=${CONFIG:-opt}
+python tools/run_tests/run_tests.py -l php7 -c $CONFIG --build_only -j 8
+
+# Set up all dependences needed for PHP QPS test
+cd src/php/tests/qps
+composer install
+# Install protobuf C-extension for php
+cd vendor/google/protobuf/php/ext/google/protobuf
+phpize
+./configure
+make
+
diff --git a/tools/run_tests/performance/massage_qps_stats.py b/tools/run_tests/performance/massage_qps_stats.py
index 9b93553..ebbfe6c 100644
--- a/tools/run_tests/performance/massage_qps_stats.py
+++ b/tools/run_tests/performance/massage_qps_stats.py
@@ -74,6 +74,7 @@
     stats["core_http2_initiate_write_due_to_transport_flow_control_unstalled"] = massage_qps_stats_helpers.counter(core_stats, "http2_initiate_write_due_to_transport_flow_control_unstalled")
     stats["core_http2_initiate_write_due_to_ping_response"] = massage_qps_stats_helpers.counter(core_stats, "http2_initiate_write_due_to_ping_response")
     stats["core_http2_initiate_write_due_to_force_rst_stream"] = massage_qps_stats_helpers.counter(core_stats, "http2_initiate_write_due_to_force_rst_stream")
+    stats["core_http2_spurious_writes_begun"] = massage_qps_stats_helpers.counter(core_stats, "http2_spurious_writes_begun")
     stats["core_hpack_recv_indexed"] = massage_qps_stats_helpers.counter(core_stats, "hpack_recv_indexed")
     stats["core_hpack_recv_lithdr_incidx"] = massage_qps_stats_helpers.counter(core_stats, "hpack_recv_lithdr_incidx")
     stats["core_hpack_recv_lithdr_incidx_v"] = massage_qps_stats_helpers.counter(core_stats, "hpack_recv_lithdr_incidx_v")
diff --git a/tools/run_tests/performance/run_worker_php.sh b/tools/run_tests/performance/run_worker_php.sh
index e524d52..8c7ceef 100755
--- a/tools/run_tests/performance/run_worker_php.sh
+++ b/tools/run_tests/performance/run_worker_php.sh
@@ -17,17 +17,7 @@
 set -ex
 
 cd $(dirname $0)/../../..
-repo=$(pwd)
-# First set up all dependences needed for PHP QPS test
-cd $repo
-cd src/php/tests/qps
-composer install
-# Install protobuf C-extension for php
-cd vendor/google/protobuf/php/ext/google/protobuf
-phpize
-./configure
-make
+
 # The proxy worker for PHP is implemented in Ruby
-cd $repo
 ruby src/ruby/qps/proxy-worker.rb $@
 
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 5019358..8f01eb4 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -800,39 +800,54 @@
     return 'ruby'
 
 
-class PhpLanguage:
+class Php7Language:
 
-  def __init__(self, use_protobuf_c_extension=False):
+  def __init__(self, php7_protobuf_c=False):
     pass
-    self.use_protobuf_c_extension=use_protobuf_c_extension
+    self.php7_protobuf_c=php7_protobuf_c
     self.safename = str(self)
 
   def worker_cmdline(self):
-    if self.use_protobuf_c_extension:
-        return ['tools/run_tests/performance/run_worker_php.sh -c']
+    if self.php7_protobuf_c:
+        return ['tools/run_tests/performance/run_worker_php.sh --use_protobuf_c_extension']
     return ['tools/run_tests/performance/run_worker_php.sh']
 
   def worker_port_offset(self):
+    if self.php7_protobuf_c:
+        return 900
     return 800
 
   def scenarios(self):
-    php_extension_mode='php_protobuf_php_extension'
-    if self.use_protobuf_c_extension:
-        php_extension_mode='php_protobuf_c_extension'
+    php7_extension_mode='php7_protobuf_php_extension'
+    if self.php7_protobuf_c:
+        php7_extension_mode='php7_protobuf_c_extension'
     
     yield _ping_pong_scenario(
-        '%s_to_cpp_protobuf_sync_unary_ping_pong' % php_extension_mode, 
+        '%s_to_cpp_protobuf_sync_unary_ping_pong' % php7_extension_mode,
         rpc_type='UNARY', client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
         server_language='c++', async_server_threads=1)
 
     yield _ping_pong_scenario(
-        '%s_to_cpp_protobuf_sync_streaming_ping_pong' % php_extension_mode, 
+        '%s_to_cpp_protobuf_sync_streaming_ping_pong' % php7_extension_mode,
         rpc_type='STREAMING', client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
         server_language='c++', async_server_threads=1)
 
-  def __str__(self):
-    return 'php'
+    # TODO(ddyihai): Investigate why when async_server_threads=1/CPU usage 340%, the QPS performs
+    # better than async_server_threads=0/CPU usage 490%.
+    yield _ping_pong_scenario(
+        '%s_to_cpp_protobuf_sync_unary_qps_unconstrained' % php7_extension_mode,
+        rpc_type='UNARY', client_type='SYNC_CLIENT', server_type='ASYNC_SERVER',
+        server_language='c++', outstanding=1, async_server_threads=1, unconstrained_client='sync')
 
+    yield _ping_pong_scenario(
+        '%s_to_cpp_protobuf_sync_streaming_qps_unconstrained' % php7_extension_mode,
+        rpc_type='STREAMING', client_type='SYNC_CLIENT', server_type='ASYNC_SERVER',
+        server_language='c++', outstanding=1, async_server_threads=1, unconstrained_client='sync')
+
+  def __str__(self):
+    if self.php7_protobuf_c:
+        return 'php7_protobuf_c'
+    return 'php7'
 
 class JavaLanguage:
 
@@ -1031,8 +1046,8 @@
     'node' : NodeLanguage(),
     'node_express': NodeExpressLanguage(),
     'ruby' : RubyLanguage(),
-    'php_protobuf_php' : PhpLanguage(),
-    'php_protobuf_c' : PhpLanguage(use_protobuf_c_extension=True),
+    'php7' : Php7Language(),
+    'php7_protobuf_c' : Php7Language(php7_protobuf_c=True),
     'java' : JavaLanguage(),
     'python' : PythonLanguage(),
     'go' : GoLanguage(),
diff --git a/tools/run_tests/performance/scenario_result_schema.json b/tools/run_tests/performance/scenario_result_schema.json
index 2f0fd91..169221d 100644
--- a/tools/run_tests/performance/scenario_result_schema.json
+++ b/tools/run_tests/performance/scenario_result_schema.json
@@ -382,6 +382,11 @@
       }, 
       {
         "mode": "NULLABLE", 
+        "name": "core_http2_spurious_writes_begun", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
         "name": "core_hpack_recv_indexed", 
         "type": "INTEGER"
       }, 
@@ -1174,6 +1179,11 @@
       }, 
       {
         "mode": "NULLABLE", 
+        "name": "core_http2_spurious_writes_begun", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
         "name": "core_hpack_recv_indexed", 
         "type": "INTEGER"
       }, 
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 82a3bc1..d523095 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -306,8 +306,8 @@
         else:
           self._state = _FAILURE
           if not self._suppress_failure_message:
-            message('FAILED', '%s [ret=%d, pid=%d]' % (
-                self._spec.shortname, self._process.returncode, self._process.pid),
+            message('FAILED', '%s [ret=%d, pid=%d, time=%.1fsec]' % (
+                self._spec.shortname, self._process.returncode, self._process.pid, elapsed),
                 stdout(), do_newline=True)
           self.result.state = 'FAILED'
           self.result.num_failures += 1
@@ -326,7 +326,7 @@
             self.result.cpu_estimated = float('%.01f' % self._spec.cpu_cost)
             measurement = '; cpu_cost=%.01f; estimated=%.01f' % (self.result.cpu_measured, self.result.cpu_estimated)
         if not self._quiet_success:
-          message('PASSED', '%s [time=%.1fsec; retries=%d:%d%s]' % (
+          message('PASSED', '%s [time=%.1fsec, retries=%d:%d%s]' % (
               self._spec.shortname, elapsed, self._retries, self._timeout_retries, measurement),
               stdout() if self._spec.verbose_success else None,
               do_newline=self._newline_on_success or self._travis)
@@ -334,6 +334,8 @@
     elif (self._state == _RUNNING and
           self._spec.timeout_seconds is not None and
           time.time() - self._start > self._spec.timeout_seconds):
+      elapsed = time.time() - self._start
+      self.result.elapsed_time = elapsed
       if self._timeout_retries < self._spec.timeout_retries:
         message('TIMEOUT_FLAKE', '%s [pid=%d]' % (self._spec.shortname, self._process.pid), stdout(), do_newline=True)
         self._timeout_retries += 1
@@ -344,7 +346,7 @@
         self._process.terminate()
         self.start()
       else:
-        message('TIMEOUT', '%s [pid=%d]' % (self._spec.shortname, self._process.pid), stdout(), do_newline=True)
+        message('TIMEOUT', '%s [pid=%d, time=%.1fsec]' % (self._spec.shortname, self._process.pid, elapsed), stdout(), do_newline=True)
         self.kill()
         self.result.state = 'TIMEOUT'
         self.result.num_failures += 1
diff --git a/tools/run_tests/python_utils/upload_test_results.py b/tools/run_tests/python_utils/upload_test_results.py
index 580e7f7..15e8277 100644
--- a/tools/run_tests/python_utils/upload_test_results.py
+++ b/tools/run_tests/python_utils/upload_test_results.py
@@ -102,6 +102,15 @@
       test_results['timestamp'] = time.strftime('%Y-%m-%d %H:%M:%S')
 
       row = big_query_utils.make_row(str(uuid.uuid4()), test_results)
-      if not big_query_utils.insert_rows(bq, _PROJECT_ID, _DATASET_ID, bq_table, [row]):
-        print('Error uploading result to bigquery.')
-        sys.exit(1)
+
+      # TODO(jtattermusch): rows are inserted one by one, very inefficient
+      max_retries = 3
+      for attempt in range(max_retries):
+        if big_query_utils.insert_rows(bq, _PROJECT_ID, _DATASET_ID, bq_table, [row]):
+          break
+        else:
+          if attempt < max_retries - 1:
+            print('Error uploading result to bigquery, will retry.')
+          else:
+            print('Error uploading result to bigquery, all attempts failed.')
+            sys.exit(1)
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 1c41679..7c65067 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -1551,8 +1551,11 @@
 
 
 def _has_epollexclusive():
+  binary = 'bins/%s/check_epollexclusive' % args.config
+  if not os.path.exists(binary):
+    return False
   try:
-    subprocess.check_call('bins/%s/check_epollexclusive' % args.config)
+    subprocess.check_call(binary)
     return True
   except subprocess.CalledProcessError, e:
     return False