Merge github.com:grpc/grpc into grpc_millis
diff --git a/BUILD b/BUILD
index 75fac5c..0836eab 100644
--- a/BUILD
+++ b/BUILD
@@ -467,7 +467,6 @@
         "src/core/lib/support/arena.c",
         "src/core/lib/support/atm.c",
         "src/core/lib/support/avl.c",
-        "src/core/lib/support/backoff.c",
         "src/core/lib/support/cmdline.c",
         "src/core/lib/support/cpu_iphone.c",
         "src/core/lib/support/cpu_linux.c",
@@ -514,8 +513,7 @@
         "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/iomgr/block_annotate.h",
         "src/core/lib/support/env.h",
         "src/core/lib/support/memory.h",
         "src/core/lib/support/mpscq.h",
@@ -692,6 +690,7 @@
         "src/core/lib/transport/timeout_encoding.c",
         "src/core/lib/transport/transport.c",
         "src/core/lib/transport/transport_op_string.c",
+        "src/core/lib/backoff/backoff.c",
     ],
     hdrs = [
         "src/core/lib/channel/channel_args.h",
@@ -809,6 +808,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 2530aef..84265c3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -392,6 +392,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)
@@ -438,7 +439,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)
@@ -779,7 +779,6 @@
   src/core/lib/support/arena.c
   src/core/lib/support/atm.c
   src/core/lib/support/avl.c
-  src/core/lib/support/backoff.c
   src/core/lib/support/cmdline.c
   src/core/lib/support/cpu_iphone.c
   src/core/lib/support/cpu_linux.c
@@ -952,6 +951,7 @@
 
 add_library(grpc
   src/core/lib/surface/init.c
+  src/core/lib/backoff/backoff.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -1302,6 +1302,7 @@
 
 add_library(grpc_cronet
   src/core/lib/surface/init.c
+  src/core/lib/backoff/backoff.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -1620,6 +1621,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.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -1882,6 +1884,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.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -2130,6 +2133,7 @@
 add_library(grpc_unsecure
   src/core/lib/surface/init.c
   src/core/lib/surface/init_unsecure.c
+  src/core/lib/backoff/backoff.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -2830,6 +2834,7 @@
   src/core/ext/transport/chttp2/transport/stream_map.c
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
+  src/core/lib/backoff/backoff.c
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
@@ -5178,6 +5183,37 @@
 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_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_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
 )
@@ -6319,35 +6355,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_BUILD_INCLUDE_DIR}
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CARES_PLATFORM_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 2d80bc9..03a428f 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
@@ -987,7 +988,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
@@ -1342,6 +1342,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 \
@@ -1374,7 +1375,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 \
@@ -1740,6 +1740,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"
@@ -1800,8 +1802,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"
@@ -2751,7 +2751,6 @@
     src/core/lib/support/arena.c \
     src/core/lib/support/atm.c \
     src/core/lib/support/avl.c \
-    src/core/lib/support/backoff.c \
     src/core/lib/support/cmdline.c \
     src/core/lib/support/cpu_iphone.c \
     src/core/lib/support/cpu_linux.c \
@@ -2897,6 +2896,7 @@
 
 LIBGRPC_SRC = \
     src/core/lib/surface/init.c \
+    src/core/lib/backoff/backoff.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -3245,6 +3245,7 @@
 
 LIBGRPC_CRONET_SRC = \
     src/core/lib/surface/init.c \
+    src/core/lib/backoff/backoff.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -3560,6 +3561,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.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -3811,6 +3813,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.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -4035,6 +4038,7 @@
 LIBGRPC_UNSECURE_SRC = \
     src/core/lib/surface/init.c \
     src/core/lib/surface/init_unsecure.c \
+    src/core/lib/backoff/backoff.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -4718,6 +4722,7 @@
     src/core/ext/transport/chttp2/transport/stream_map.c \
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
+    src/core/lib/backoff/backoff.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -8764,6 +8769,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 \
 
@@ -9948,38 +9985,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 1d4565a..c19343a 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -599,7 +599,6 @@
         'src/core/lib/support/arena.c',
         'src/core/lib/support/atm.c',
         'src/core/lib/support/avl.c',
-        'src/core/lib/support/backoff.c',
         'src/core/lib/support/cmdline.c',
         'src/core/lib/support/cpu_iphone.c',
         'src/core/lib/support/cpu_linux.c',
@@ -657,6 +656,7 @@
       ],
       'sources': [
         'src/core/lib/surface/init.c',
+        'src/core/lib/backoff/backoff.c',
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
diff --git a/build.yaml b/build.yaml
index 69fe928..58351cc 100644
--- a/build.yaml
+++ b/build.yaml
@@ -66,7 +66,6 @@
   - src/core/lib/support/arena.c
   - src/core/lib/support/atm.c
   - src/core/lib/support/avl.c
-  - src/core/lib/support/backoff.c
   - src/core/lib/support/cmdline.c
   - src/core/lib/support/cpu_iphone.c
   - src/core/lib/support/cpu_linux.c
@@ -143,7 +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
@@ -185,6 +183,7 @@
   - grpc++_codegen_base
 - name: grpc_base
   src:
+  - src/core/lib/backoff/backoff.c
   - src/core/lib/channel/channel_args.c
   - src/core/lib/channel/channel_stack.c
   - src/core/lib/channel/channel_stack_builder.c
@@ -335,6 +334,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
@@ -1748,6 +1748,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
@@ -2161,14 +2171,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 3e8328b..f9f8491 100644
--- a/config.m4
+++ b/config.m4
@@ -45,7 +45,6 @@
     src/core/lib/support/arena.c \
     src/core/lib/support/atm.c \
     src/core/lib/support/avl.c \
-    src/core/lib/support/backoff.c \
     src/core/lib/support/cmdline.c \
     src/core/lib/support/cpu_iphone.c \
     src/core/lib/support/cpu_linux.c \
@@ -86,6 +85,7 @@
     src/core/lib/support/tmpfile_windows.c \
     src/core/lib/support/wrap_memcpy.c \
     src/core/lib/surface/init.c \
+    src/core/lib/backoff/backoff.c \
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
@@ -684,6 +684,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 493f00c..cf60a68 100644
--- a/config.w32
+++ b/config.w32
@@ -22,7 +22,6 @@
     "src\\core\\lib\\support\\arena.c " +
     "src\\core\\lib\\support\\atm.c " +
     "src\\core\\lib\\support\\avl.c " +
-    "src\\core\\lib\\support\\backoff.c " +
     "src\\core\\lib\\support\\cmdline.c " +
     "src\\core\\lib\\support\\cpu_iphone.c " +
     "src\\core\\lib\\support\\cpu_linux.c " +
@@ -63,6 +62,7 @@
     "src\\core\\lib\\support\\tmpfile_windows.c " +
     "src\\core\\lib\\support\\wrap_memcpy.c " +
     "src\\core\\lib\\surface\\init.c " +
+    "src\\core\\lib\\backoff\\backoff.c " +
     "src\\core\\lib\\channel\\channel_args.c " +
     "src\\core\\lib\\channel\\channel_stack.c " +
     "src\\core\\lib\\channel\\channel_stack_builder.c " +
@@ -697,6 +697,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 be4b689..03bfe01 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -188,7 +188,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',
@@ -206,7 +205,6 @@
                       'src/core/lib/support/arena.c',
                       'src/core/lib/support/atm.c',
                       'src/core/lib/support/avl.c',
-                      'src/core/lib/support/backoff.c',
                       'src/core/lib/support/cmdline.c',
                       'src/core/lib/support/cpu_iphone.c',
                       'src/core/lib/support/cpu_linux.c',
@@ -318,6 +316,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',
@@ -468,6 +467,7 @@
                       'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
                       'src/core/ext/filters/workarounds/workaround_utils.h',
                       'src/core/lib/surface/init.c',
+                      'src/core/lib/backoff/backoff.c',
                       'src/core/lib/channel/channel_args.c',
                       'src/core/lib/channel/channel_stack.c',
                       'src/core/lib/channel/channel_stack_builder.c',
@@ -729,7 +729,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',
@@ -813,6 +812,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',
diff --git a/grpc.gemspec b/grpc.gemspec
index d4372d6..7aab115 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -87,7 +87,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 )
@@ -105,7 +104,6 @@
   s.files += %w( src/core/lib/support/arena.c )
   s.files += %w( src/core/lib/support/atm.c )
   s.files += %w( src/core/lib/support/avl.c )
-  s.files += %w( src/core/lib/support/backoff.c )
   s.files += %w( src/core/lib/support/cmdline.c )
   s.files += %w( src/core/lib/support/cpu_iphone.c )
   s.files += %w( src/core/lib/support/cpu_linux.c )
@@ -250,6 +248,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 )
@@ -404,6 +403,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.c )
+  s.files += %w( src/core/lib/backoff/backoff.c )
   s.files += %w( src/core/lib/channel/channel_args.c )
   s.files += %w( src/core/lib/channel/channel_stack.c )
   s.files += %w( src/core/lib/channel/channel_stack_builder.c )
diff --git a/grpc.gyp b/grpc.gyp
index 0295619..38d0304 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -163,7 +163,6 @@
         'src/core/lib/support/arena.c',
         'src/core/lib/support/atm.c',
         'src/core/lib/support/avl.c',
-        'src/core/lib/support/backoff.c',
         'src/core/lib/support/cmdline.c',
         'src/core/lib/support/cpu_iphone.c',
         'src/core/lib/support/cpu_linux.c',
@@ -223,6 +222,7 @@
       ],
       'sources': [
         'src/core/lib/surface/init.c',
+        'src/core/lib/backoff/backoff.c',
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
@@ -522,6 +522,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.c',
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
@@ -726,6 +727,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.c',
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
@@ -915,6 +917,7 @@
       'sources': [
         'src/core/lib/surface/init.c',
         'src/core/lib/surface/init_unsecure.c',
+        'src/core/lib/backoff/backoff.c',
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
diff --git a/package.xml b/package.xml
index 66a79ec..7c46f36 100644
--- a/package.xml
+++ b/package.xml
@@ -97,7 +97,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" />
@@ -115,7 +114,6 @@
     <file baseinstalldir="/" name="src/core/lib/support/arena.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atm.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/avl.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/backoff.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cmdline.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cpu_iphone.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/cpu_linux.c" role="src" />
@@ -260,6 +258,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" />
@@ -414,6 +413,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.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/backoff/backoff.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.c" role="src" />
diff --git a/src/core/ext/filters/client_channel/channel_connectivity.c b/src/core/ext/filters/client_channel/channel_connectivity.c
index b83c952..e98453f 100644
--- a/src/core/ext/filters/client_channel/channel_connectivity.c
+++ b/src/core/ext/filters/client_channel/channel_connectivity.c
@@ -186,8 +186,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.c b/src/core/ext/filters/client_channel/client_channel.c
index e6822ce..1920154 100644
--- a/src/core/ext/filters/client_channel/client_channel.c
+++ b/src/core/ext/filters/client_channel/client_channel.c
@@ -68,7 +68,7 @@
 
 typedef struct {
   gpr_refcount refs;
-  gpr_timespec timeout;
+  grpc_millis timeout;
   wait_for_ready_value wait_for_ready;
 } method_parameters;
 
@@ -98,17 +98,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;
     }
@@ -127,24 +128,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;
     }
   }
@@ -815,7 +817,7 @@
 
   grpc_slice path;  // Request path.
   gpr_timespec call_start_time;
-  gpr_timespec deadline;
+  grpc_millis deadline;
   gpr_arena *arena;
   grpc_call_combiner *call_combiner;
 
@@ -967,11 +969,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);
         }
@@ -1415,7 +1417,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->call_combiner = args->call_combiner;
   if (chand->deadline_checking_enabled) {
diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
index 7f3d4a1..bf79f26 100644
--- a/src/core/ext/filters/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -34,7 +34,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.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
index 087b407..3c7f0e7 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
@@ -101,6 +101,7 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #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/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"
@@ -110,7 +111,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"
@@ -384,7 +384,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;
@@ -396,7 +396,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;
@@ -1155,7 +1155,7 @@
 static void start_picking_locked(grpc_exec_ctx *exec_ctx,
                                  glb_lb_policy *glb_policy) {
   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);
 }
 
@@ -1260,15 +1260,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,
@@ -1367,12 +1366,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,
@@ -1406,12 +1403,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->initial_request_sent = false;
   glb_policy->seen_initial_response = false;
@@ -1538,7 +1535,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;
@@ -1552,16 +1549,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
@@ -1689,17 +1684,16 @@
     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) {
+      grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
+      if (timeout > 0) {
         gpr_log(GPR_DEBUG,
-                "... retry_timer_active in %" PRId64 ".%09d seconds.",
-                timeout.tv_sec, timeout.tv_nsec);
+                "... retry_timer_active in %" PRIdPTR " milliseconds.",
+                timeout);
       } else {
         gpr_log(GPR_DEBUG, "... retry_timer_active immediately.");
       }
@@ -1710,7 +1704,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");
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
index 6fa29f3..050ebc1 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
@@ -288,13 +288,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 (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.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
index f1480bb..c75cba0 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
@@ -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);
@@ -380,11 +378,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.c b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
index 5ea75f0..7287a5d 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
@@ -24,11 +24,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"
 
@@ -67,7 +67,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;
@@ -110,7 +110,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);
   }
 }
@@ -123,7 +123,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);
@@ -164,23 +164,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);
@@ -251,11 +249,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.c b/src/core/ext/filters/client_channel/subchannel.c
index 5cc8be7..48e790b 100644
--- a/src/core/ext/filters/client_channel/subchannel.c
+++ b/src/core/ext/filters/client_channel/subchannel.c
@@ -30,13 +30,13 @@
 #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/iomgr/sockaddr_utils.h"
 #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"
@@ -116,9 +116,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 */
@@ -363,7 +363,7 @@
       }
     }
   }
-  gpr_backoff_init(
+  grpc_backoff_init(
       &c->backoff_state, initial_backoff_ms,
       fixed_reconnect_backoff ? 1.0
                               : GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
@@ -427,8 +427,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 {
@@ -463,24 +462,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 51d712f..73702d5 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -103,7 +103,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.c b/src/core/ext/filters/deadline/deadline_filter.c
index 565b067..023378a 100644
--- a/src/core/ext/filters/deadline/deadline_filter.c
+++ b/src/core/ext/filters/deadline/deadline_filter.c
@@ -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,
@@ -180,14 +178,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
@@ -211,7 +208,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 3eb102a..8d835d0 100644
--- a/src/core/ext/filters/deadline/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -52,7 +52,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);
 
@@ -66,7 +67,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.c b/src/core/ext/filters/max_age/max_age_filter.c
index 16c85a7..a0f15e4 100644
--- a/src/core/ext/filters/max_age/max_age_filter.c
+++ b/src/core/ext/filters/max_age/max_age_filter.c
@@ -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,30 +289,23 @@
   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(
@@ -318,15 +313,13 @@
           (grpc_integer_options){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,
@@ -349,8 +342,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
@@ -367,8 +359,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.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
index f207155..feb9579 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.c
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -132,8 +132,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.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 2f0ac85..2ed5562 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -363,36 +363,27 @@
 
   t->ping_policy = (grpc_chttp2_repeated_ping_policy){
       .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA,
-      .min_time_between_pings =
-          gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN),
+      .min_time_between_pings = DEFAULT_MIN_TIME_BETWEEN_PINGS_MS,
       .max_ping_strikes = DEFAULT_MAX_PING_STRIKES,
-      .min_ping_interval_without_data = gpr_time_from_millis(
-          DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, GPR_TIMESPAN),
+      .min_ping_interval_without_data =
+          DEFAULT_MIN_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;
 
@@ -435,21 +426,18 @@
             (grpc_integer_options){DEFAULT_MAX_PING_STRIKES, 0, INT_MAX});
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) {
-        t->ping_policy.min_time_between_pings = gpr_time_from_millis(
-            grpc_channel_arg_get_integer(
-                &channel_args->args[i],
-                (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0,
-                                       INT_MAX}),
-            GPR_TIMESPAN);
+        t->ping_policy.min_time_between_pings = grpc_channel_arg_get_integer(
+            &channel_args->args[i],
+            (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0,
+                                   INT_MAX});
       } else if (0 ==
                  strcmp(channel_args->args[i].key,
                         GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS)) {
-        t->ping_policy.min_ping_interval_without_data = gpr_time_from_millis(
+        t->ping_policy.min_ping_interval_without_data =
             grpc_channel_arg_get_integer(
                 &channel_args->args[i],
                 (grpc_integer_options){
-                    DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, 0, INT_MAX}),
-            GPR_TIMESPAN);
+                    DEFAULT_MIN_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(
@@ -467,9 +455,7 @@
                                        ? 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);
+        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(
@@ -478,9 +464,8 @@
                                        ? 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);
+        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 =
@@ -565,17 +550,16 @@
       t->ping_policy.max_pings_without_data;
   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 = 0;
   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 */
@@ -688,7 +672,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);
@@ -1009,14 +993,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
@@ -1316,8 +1298,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(
@@ -1530,16 +1511,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);
     }
   }
 
@@ -1613,8 +1592,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, "goaway_sent");
@@ -1623,16 +1602,20 @@
 
 void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
                                  grpc_chttp2_transport *t) {
-  gpr_log(GPR_DEBUG, "PING strike");
-  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,
-                grpc_error_set_int(
-                    GRPC_ERROR_CREATE_FROM_STATIC_STRING("too_many_pings"),
-                    GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
-    /*The transport will be closed after the write is done */
-    close_transport_locked(
-        exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"));
+  t->ping_recv_state.ping_strikes++;
+  if (t->ping_policy.max_ping_strikes != 0) {
+    gpr_log(GPR_DEBUG, "%s: PING strike %d/%d", t->peer_string,
+            t->ping_recv_state.ping_strikes, t->ping_policy.max_ping_strikes);
+    if (t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes) {
+      send_goaway(
+          exec_ctx, t,
+          grpc_error_set_int(
+              GRPC_ERROR_CREATE_FROM_STATIC_STRING("too_many_pings"),
+              GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
+      /*The transport will be closed after the write is done */
+      close_transport_locked(
+          exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"));
+    }
   }
 }
 
@@ -1903,7 +1886,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));
@@ -1920,7 +1904,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;
@@ -2077,7 +2061,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);
 
@@ -2494,18 +2479,16 @@
                        &t->finish_keepalive_ping_locked);
     } 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");
 }
@@ -2514,10 +2497,9 @@
                                         grpc_error *error) {
   grpc_chttp2_transport *t = 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,
@@ -2528,10 +2510,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");
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 3d7c6fb..31673e6 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -89,10 +89,9 @@
       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_ping_interval_without_data);
+        grpc_millis next_allowed_ping =
+            t->ping_recv_state.last_ping_recv_time +
+            t->ping_policy.min_ping_interval_without_data;
 
         if (t->keepalive_permit_without_calls == 0 &&
             grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
@@ -100,15 +99,14 @@
              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 > grpc_exec_ctx_now(exec_ctx)) {
           grpc_chttp2_add_ping_strike(exec_ctx, t);
         }
 
-        t->ping_recv_state.last_ping_recv_time = now;
+        t->ping_recv_state.last_ping_recv_time = grpc_exec_ctx_now(exec_ctx);
       }
       if (!g_disable_ping_ack) {
         if (t->ping_ack_count == t->ping_ack_capacity) {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index a0e748e..207ef6c 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -515,12 +515,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);
@@ -639,8 +639,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.c b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
index cf0a9ca..089b360 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.c
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
@@ -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(
@@ -61,7 +61,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 a951d87..0fc90b2 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -43,6 +43,6 @@
     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);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 9fff30d..901be65 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -85,21 +85,21 @@
 } grpc_chttp2_ping_queue;
 
 typedef struct {
-  gpr_timespec min_time_between_pings;
+  grpc_millis min_time_between_pings;
   int max_pings_without_data;
   int max_ping_strikes;
-  gpr_timespec min_ping_interval_without_data;
+  grpc_millis min_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;
 
@@ -424,9 +424,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 */
@@ -534,7 +534,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;
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 19bd86f..bc1e773 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -426,16 +426,16 @@
   }
 
   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
-    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
-    gpr_timespec timeout;
+    grpc_millis *cached_timeout = 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_malloc(sizeof(gpr_timespec));
+      cached_timeout = 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);
@@ -443,8 +443,7 @@
       timeout = *cached_timeout;
     }
     grpc_chttp2_incoming_metadata_buffer_set_deadline(
-        &s->metadata_buffer[0],
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout));
+        &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);
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 80eb51f..d85caf0 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -76,12 +76,12 @@
     }
     return;
   }
-  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  gpr_timespec elapsed = gpr_time_sub(now, t->ping_state.last_ping_sent_time);
+  grpc_millis elapsed =
+      grpc_exec_ctx_now(exec_ctx) - t->ping_state.last_ping_sent_time;
   /*gpr_log(GPR_DEBUG, "elapsed:%d.%09d min:%d.%09d", (int)elapsed.tv_sec,
           elapsed.tv_nsec, (int)t->ping_policy.min_time_between_pings.tv_sec,
           (int)t->ping_policy.min_time_between_pings.tv_nsec);*/
-  if (gpr_time_cmp(elapsed, t->ping_policy.min_time_between_pings) < 0) {
+  if (elapsed < t->ping_policy.min_time_between_pings) {
     /* not enough elapsed time between successive pings */
     if (GRPC_TRACER_ON(grpc_http_trace) ||
         GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
@@ -92,10 +92,9 @@
     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,
-                      gpr_time_add(t->ping_state.last_ping_sent_time,
-                                   t->ping_policy.min_time_between_pings),
-                      &t->retry_initiate_ping_locked,
-                      gpr_now(GPR_CLOCK_MONOTONIC));
+                      t->ping_state.last_ping_sent_time +
+                          t->ping_policy.min_time_between_pings,
+                      &t->retry_initiate_ping_locked);
     }
     return;
   }
@@ -116,7 +115,7 @@
                          &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]);
   grpc_slice_buffer_add(&t->outbuf,
                         grpc_chttp2_ping_create(false, pq->inflight_id));
-  t->ping_state.last_ping_sent_time = now;
+  t->ping_state.last_ping_sent_time = grpc_exec_ctx_now(exec_ctx);
   t->ping_state.pings_before_data_required -=
       (t->ping_state.pings_before_data_required != 0);
 }
@@ -255,8 +254,7 @@
         t->ping_state.pings_before_data_required =
             t->ping_policy.max_pings_without_data;
         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;
         }
       } else {
@@ -279,6 +277,7 @@
       s->sent_initial_metadata = true;
       sent_initial_metadata = true;
     }
+
     /* send any window updates */
     uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update(
         &t->flow_control, &s->flow_control);
@@ -289,8 +288,7 @@
       t->ping_state.pings_before_data_required =
           t->ping_policy.max_pings_without_data;
       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;
       }
     }
@@ -365,8 +363,7 @@
           t->ping_state.pings_before_data_required =
               t->ping_policy.max_pings_without_data;
           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) {
@@ -454,8 +451,7 @@
     t->ping_state.pings_before_data_required =
         t->ping_policy.max_pings_without_data;
     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;
     }
   }
diff --git a/src/core/ext/transport/inproc/inproc_transport.c b/src/core/ext/transport/inproc/inproc_transport.c
index b2d6f2d..be50db8 100644
--- a/src/core/ext/transport/inproc/inproc_transport.c
+++ b/src/core/ext/transport/inproc/inproc_transport.c
@@ -151,7 +151,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;
@@ -181,7 +181,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;
     }
@@ -954,10 +954,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.c b/src/core/lib/backoff/backoff.c
similarity index 69%
rename from src/core/lib/support/backoff.c
rename to src/core/lib/backoff/backoff.c
index 6dc0df4..e964af8 100644
--- a/src/core/lib/support/backoff.c
+++ b/src/core/lib/backoff/backoff.c
@@ -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 =
       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,7 +45,7 @@
   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 =
@@ -58,15 +59,15 @@
   backoff->current_timeout_millis =
       (int64_t)((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 6e0cc3a..c0798bb 100644
--- a/src/core/lib/support/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -16,41 +16,43 @@
  *
  */
 
-#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"
 
 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_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);
 
-#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 ae1cac3..e616a51 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.c b/src/core/lib/channel/handshaker.c
index 2cb83f4..c4f57a5 100644
--- a/src/core/lib/channel/handshaker.c
+++ b/src/core/lib/channel/handshaker.c
@@ -231,7 +231,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);
@@ -253,9 +253,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 eb9a59b..09b4a27 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -145,7 +145,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/compression/stream_compression.h b/src/core/lib/compression/stream_compression.h
index 844dff8..0daaa9e 100644
--- a/src/core/lib/compression/stream_compression.h
+++ b/src/core/lib/compression/stream_compression.h
@@ -87,4 +87,4 @@
 void grpc_stream_compression_context_destroy(
     grpc_stream_compression_context *ctx);
 
-#endif
+#endif /* GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H */
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index 77af7b7..97db3a3 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -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 = gpr_malloc(sizeof(internal_request));
@@ -277,9 +277,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)) {
@@ -297,7 +296,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 8096186..a3baf51 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -42,7 +42,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;
@@ -83,8 +83,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.
@@ -106,18 +106,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.c b/src/core/lib/http/httpcli_security_connector.c
index 97c2886..37ee087 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -155,7 +155,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 = gpr_malloc(sizeof(*c));
diff --git a/src/core/lib/support/block_annotate.h b/src/core/lib/iomgr/block_annotate.h
similarity index 75%
rename from src/core/lib/support/block_annotate.h
rename to src/core/lib/iomgr/block_annotate.h
index 8e3ef7d..cbcb5d9 100644
--- a/src/core/lib/support/block_annotate.h
+++ b/src/core/lib/iomgr/block_annotate.h
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
-#define GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
+#ifndef GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
+#define GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,9 +47,13 @@
 #define GRPC_SCHEDULING_START_BLOCKING_REGION \
   do {                                        \
   } while (0)
-#define GRPC_SCHEDULING_END_BLOCKING_REGION \
-  do {                                      \
+#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_SUPPORT_BLOCK_ANNOTATE_H */
+#endif /* GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H */
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c
index b940d48..f8f8b18 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.c
+++ b/src/core/lib/iomgr/ev_epoll1_linux.c
@@ -25,6 +25,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/tls.h>
 #include <grpc/support/useful.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;
@@ -554,22 +555,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 = {
-      .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1};
-  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.
@@ -626,11 +622,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;
   }
@@ -639,7 +635,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");
@@ -655,9 +651,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;
@@ -734,14 +731,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->kick_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)) {
@@ -917,7 +915,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";
@@ -928,7 +926,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);
@@ -951,8 +949,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_epoll_limited_pollers_linux.c b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c
index f2f3e15..d56b9a9 100644
--- a/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c
@@ -41,13 +41,13 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/trace.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"
 #include "src/core/lib/support/env.h"
 
 #define GRPC_POLLING_TRACE(fmt, ...)        \
@@ -1194,30 +1194,16 @@
   return linux_ts;
 }
 
-/* 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,
@@ -1285,10 +1271,9 @@
   gpr_mu_destroy(&pollset->po.mu);
 }
 
-/* NOTE: This function may modify 'now' */
-static bool acquire_polling_lease(grpc_pollset_worker *worker,
-                                  polling_island *pi, gpr_timespec deadline,
-                                  gpr_timespec *now) {
+static bool acquire_polling_lease(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset_worker *worker,
+                                  polling_island *pi, grpc_millis *deadline) {
   bool is_lease_acquired = false;
 
   gpr_mu_lock(&pi->worker_list_mu);  //  LOCK
@@ -1300,14 +1285,14 @@
 
     bool is_timeout = false;
     int ret;
-    int timeout_ms = poll_deadline_to_millis_timeout(deadline, *now);
+    int timeout_ms = poll_deadline_to_millis_timeout(exec_ctx, *deadline);
     if (timeout_ms == -1) {
       ret = sigwaitinfo(&g_wakeup_sig_set, NULL);
     } else {
       struct timespec sigwait_timeout = millis_to_timespec(timeout_ms);
       GRPC_SCHEDULING_START_BLOCKING_REGION;
       ret = sigtimedwait(&g_wakeup_sig_set, NULL, &sigwait_timeout);
-      GRPC_SCHEDULING_END_BLOCKING_REGION;
+      GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
     }
 
     if (ret == -1) {
@@ -1323,18 +1308,13 @@
       }
     }
 
-    /* Did the worker come out of sigtimedwait due to a thread that just
-       exited epoll and kicking it (in release_polling_lease function). */
-    bool is_polling_turn = gpr_atm_acq_load(&worker->is_polling_turn);
-
     /* Did the worker come out of sigtimedwait due to a thread alerting it that
        some completion event was (likely) available in the completion queue */
     bool is_kicked = gpr_atm_no_barrier_load(&worker->is_kicked);
 
     if (is_kicked || is_timeout) {
-      *now = deadline; /* Essentially make the epoll timeout = 0 */
-    } else if (is_polling_turn) {
-      *now = gpr_now(GPR_CLOCK_MONOTONIC); /* Reduce the epoll timeout */
+      *deadline = grpc_exec_ctx_now(
+          exec_ctx); /* Essentially make the epoll timeout = 0 */
     }
 
     gpr_mu_lock(&pi->worker_list_mu);  // LOCK
@@ -1374,11 +1354,11 @@
 static void pollset_do_epoll_pwait(grpc_exec_ctx *exec_ctx, int epoll_fd,
                                    grpc_pollset *pollset, polling_island *pi,
                                    grpc_pollset_worker *worker,
-                                   gpr_timespec now, gpr_timespec deadline,
-                                   sigset_t *sig_mask, grpc_error **error) {
+                                   grpc_millis deadline, sigset_t *sig_mask,
+                                   grpc_error **error) {
   /* Only g_max_pollers_per_pi threads can be doing polling in parallel.
      If we cannot get a lease, we cannot continue to do epoll_pwait() */
-  if (!acquire_polling_lease(worker, pi, deadline, &now)) {
+  if (!acquire_polling_lease(exec_ctx, worker, pi, &deadline)) {
     return;
   }
 
@@ -1388,12 +1368,12 @@
   const char *err_desc = "pollset_work_and_unlock";
 
   /* timeout_ms is the time between 'now' and 'deadline' */
-  int timeout_ms = poll_deadline_to_millis_timeout(deadline, now);
+  int timeout_ms = poll_deadline_to_millis_timeout(exec_ctx, deadline);
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   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);
 
   /* Give back the lease right away so that some other thread can enter */
   release_polling_lease(pi, error);
@@ -1448,8 +1428,8 @@
 static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
                                     grpc_pollset *pollset,
                                     grpc_pollset_worker *worker,
-                                    gpr_timespec now, gpr_timespec deadline,
-                                    sigset_t *sig_mask, grpc_error **error) {
+                                    grpc_millis deadline, sigset_t *sig_mask,
+                                    grpc_error **error) {
   int epoll_fd = -1;
   polling_island *pi = NULL;
   GPR_TIMER_BEGIN("pollset_work_and_unlock", 0);
@@ -1497,7 +1477,7 @@
   gpr_mu_unlock(&pollset->po.mu);
 
   g_current_thread_polling_island = pi;
-  pollset_do_epoll_pwait(exec_ctx, epoll_fd, pollset, pi, worker, now, deadline,
+  pollset_do_epoll_pwait(exec_ctx, epoll_fd, pollset, pi, worker, deadline,
                          sig_mask, error);
   g_current_thread_polling_island = NULL;
 
@@ -1519,7 +1499,7 @@
    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;
 
@@ -1575,7 +1555,7 @@
 
     push_front_worker(pollset, &worker); /* Add worker to pollset */
 
-    pollset_work_and_unlock(exec_ctx, pollset, &worker, now, deadline,
+    pollset_work_and_unlock(exec_ctx, pollset, &worker, deadline,
                             &g_orig_sigmask, &error);
     grpc_exec_ctx_flush(exec_ctx);
 
diff --git a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c
index 07c8ead..68e320f 100644
--- a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c
@@ -41,13 +41,13 @@
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.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"
 
 /* TODO: sreek - Move this to init.c and initialize this like other tracers. */
 #define GRPC_POLLING_TRACE(fmt, ...)        \
@@ -778,7 +778,7 @@
   acquire_epoll_lease(eps);
   ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms);
   release_epoll_lease(eps);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
 
   if (ep_rv < 0) {
     gpr_asprintf(&err_msg,
@@ -838,7 +838,7 @@
    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;
 
@@ -861,7 +861,7 @@
     push_front_worker(pollset, &worker);
 
     gpr_cv_wait(&worker.kick_cv, &pollset->mu,
-                gpr_convert_clock_type(deadline, GPR_CLOCK_REALTIME));
+                grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME));
     /* pollset->mu locked here */
 
     remove_worker(pollset, &worker);
diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c
index 1f4adea..b7961e7 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.c
+++ b/src/core/lib/iomgr/ev_epollex_linux.c
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <pthread.h>
 #include <string.h>
@@ -37,6 +38,7 @@
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.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/is_epollexclusive_available.h"
@@ -45,7 +47,6 @@
 #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"
 
 /*******************************************************************************
@@ -683,29 +684,16 @@
   *mu = &pollset->pollable.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 = {
-      .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1};
-  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,
@@ -799,9 +787,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);
@@ -817,7 +804,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");
@@ -872,9 +859,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;
@@ -897,10 +885,11 @@
         worker->pollable->root_worker != worker) {
       gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset,
               worker->pollable, worker,
-              poll_deadline_to_millis_timeout(deadline, *now));
+              poll_deadline_to_millis_timeout(exec_ctx, deadline));
     }
     while (do_poll && worker->pollable->root_worker != worker) {
-      if (gpr_cv_wait(&worker->cv, &worker->pollable->po.mu, deadline)) {
+      if (gpr_cv_wait(&worker->cv, &worker->pollable->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, worker);
@@ -923,7 +912,7 @@
       gpr_mu_lock(&pollset->pollable.po.mu);
       gpr_mu_lock(&worker->pollable->po.mu);
     }
-    *now = gpr_now(now->clock_type);
+    grpc_exec_ctx_invalidate_now(exec_ctx);
   }
 
   return do_poll && pollset->shutdown_closure == NULL &&
@@ -954,14 +943,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";
@@ -972,7 +960,7 @@
   if (pollset->current_pollable != &pollset->pollable) {
     gpr_mu_lock(&pollset->current_pollable->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);
@@ -982,8 +970,8 @@
     }
     gpr_mu_unlock(&pollset->pollable.po.mu);
     if (pollset->event_cursor == pollset->event_count) {
-      append_error(&error, pollset_epoll(exec_ctx, pollset, worker.pollable,
-                                         now, deadline),
+      append_error(&error,
+                   pollset_epoll(exec_ctx, pollset, worker.pollable, deadline),
                    err_desc);
     }
     append_error(&error, pollset_process_events(exec_ctx, pollset, false),
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c
index 070d75e..a27ecc8 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.c
+++ b/src/core/lib/iomgr/ev_epollsig_linux.c
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <pthread.h>
 #include <signal.h>
@@ -39,13 +40,13 @@
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.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)
 
@@ -1086,30 +1087,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,
@@ -1238,7 +1225,7 @@
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   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,
@@ -1305,10 +1292,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.c b/src/core/lib/iomgr/ev_poll_posix.c
index 9472a8e..c42059d 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <string.h>
 #include <sys/socket.h>
@@ -36,12 +37,12 @@
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.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)
@@ -199,8 +200,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
@@ -871,7 +872,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;
@@ -939,7 +940,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;
@@ -984,7 +985,7 @@
          even going into the blocking annotation if possible */
       GRPC_SCHEDULING_START_BLOCKING_REGION;
       r = grpc_poll_function(pfds, pfd_count, timeout);
-      GRPC_SCHEDULING_END_BLOCKING_REGION;
+      GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
 
       if (r < 0) {
         if (errno != EINTR) {
@@ -1049,13 +1050,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) {
@@ -1107,21 +1105,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.c b/src/core/lib/iomgr/ev_posix.c
index 91f8cd5..0bb4120 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -209,9 +209,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_pollset *pollset,
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 1108e46..dfc82fc 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -52,8 +52,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_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.c b/src/core/lib/iomgr/exec_ctx.c
index 41c69ad..05ab9f6 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -104,9 +104,61 @@
   grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
 }
 
-void grpc_exec_ctx_global_init(void) {}
+static gpr_timespec g_start_time;
+
+void grpc_exec_ctx_global_init(void) {
+  g_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
+}
+
 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);
+  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);
+  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) {
+  return gpr_time_add(gpr_convert_clock_type(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(
+      gpr_convert_clock_type(ts, g_start_time.clock_type));
+}
+
+grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec ts) {
+  return timespec_to_atm_round_up(
+      gpr_convert_clock_type(ts, g_start_time.clock_type));
+}
+
 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 a0d2a96..bb561ee 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -19,9 +19,13 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 #define GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 
+#include <grpc/support/atm.h>
+
 #include "src/core/lib/iomgr/closure.h"
 
-/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */
+typedef gpr_atm grpc_millis;
+
+#define GRPC_MILLIS_INF_FUTURE GPR_ATM_MAX
 
 /** A workqueue represents a list of work to be executed asynchronously.
     Forward declared here to avoid a circular dependency with workqueue.h. */
@@ -64,12 +68,18 @@
   uintptr_t flags;
   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:
    prefer to use GRPC_EXEC_CTX_INIT whenever possible */
-#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \
-  { GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, finish_check_arg, finish_check }
+#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg)       \
+  {                                                                            \
+    GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, finish_check_arg, finish_check, \
+        false, 0                                                               \
+  }
 
 /* initialize an execution context at the top level of an API call into grpc
    (this is safe to use elsewhere, though possibly not as efficient) */
@@ -101,4 +111,10 @@
 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);
+
 #endif /* GRPC_CORE_LIB_IOMGR_EXEC_CTX_H */
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 3d19953..55a9604 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -48,7 +48,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 = "root";
   grpc_network_status_init();
@@ -95,8 +95,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.c b/src/core/lib/iomgr/load_file.c
index ba77a52..aafcd79 100644
--- a/src/core/lib/iomgr/load_file.c
+++ b/src/core/lib/iomgr/load_file.c
@@ -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,
@@ -72,6 +72,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 a609a38..49d4251 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -71,8 +71,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/resolve_address_posix.c b/src/core/lib/iomgr/resolve_address_posix.c
index 35dedc2..8044f8c 100644
--- a/src/core/lib/iomgr/resolve_address_posix.c
+++ b/src/core/lib/iomgr/resolve_address_posix.c
@@ -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.c b/src/core/lib/iomgr/resolve_address_windows.c
index 45cfd72..3217bb4 100644
--- a/src/core/lib/iomgr/resolve_address_windows.c
+++ b/src/core/lib/iomgr/resolve_address_windows.c
@@ -33,10 +33,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 {
@@ -86,7 +86,7 @@
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   s = getaddrinfo(host, port, &hints, &result);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
   if (s != 0) {
     error = GRPC_WSA_ERROR(WSAGetLastError(), "getaddrinfo");
     goto done;
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 6c9e51a..c04fb8b 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -35,6 +35,6 @@
                              grpc_pollset_set *interested_parties,
                              const grpc_channel_args *channel_args,
                              const grpc_resolved_address *addr,
-                             gpr_timespec deadline);
+                             grpc_millis deadline);
 
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index a25fba4..f6e0227 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -243,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;
@@ -324,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);
 
@@ -340,14 +338,14 @@
     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,
                              grpc_endpoint **ep,
                              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/timer.h b/src/core/lib/iomgr/timer.h
index b92b8fb..89c997b 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -41,8 +41,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);
 
 /* Note that there is no timer destroy function. This is because the
    timer is a one-time occurrence with a guarantee that the callback will
@@ -88,8 +87,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.c b/src/core/lib/iomgr/timer_generic.c
index 12efce2..8ed0362 100644
--- a/src/core/lib/iomgr/timer_generic.c
+++ b/src/core/lib/iomgr/timer_generic.c
@@ -99,9 +99,6 @@
     .checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER, .initialized = false,
 };
 
-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;
@@ -114,51 +111,18 @@
                                                        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;
   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);
@@ -193,10 +157,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;
@@ -235,20 +195,16 @@
 }
 
 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;
 
   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) {
@@ -261,7 +217,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);
@@ -270,8 +227,8 @@
   }
 
   grpc_time_averaged_stats_add_sample(&shard->stats,
-                                      ts_to_dbl(gpr_time_sub(deadline, now)));
-  if (deadline_atm < shard->queue_deadline_cap) {
+                                      (double)(deadline - now) / 1000.0);
+  if (deadline < shard->queue_deadline_cap) {
     is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
   } else {
     timer->heap_index = INVALID_HEAP_INDEX;
@@ -302,12 +259,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();
       }
     }
@@ -406,8 +363,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);
@@ -428,6 +386,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;
 }
 
@@ -500,29 +462,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");
 
@@ -532,34 +492,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.c b/src/core/lib/iomgr/timer_manager.c
index 631f793..6232172 100644
--- a/src/core/lib/iomgr/timer_manager.c
+++ b/src/core/lib/iomgr/timer_manager.c
@@ -52,7 +52,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;
 
@@ -96,9 +96,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);
 }
 
@@ -121,6 +120,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
@@ -133,8 +135,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) {
@@ -168,30 +169,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",
@@ -203,7 +203,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;
     }
   }
 
@@ -219,12 +219,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;
@@ -241,10 +240,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;
@@ -300,7 +299,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();
 }
@@ -347,7 +346,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/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c
index a2a8e28..c83ecd0 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.c
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c
@@ -95,7 +95,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 = gpr_zalloc(grpc_pollset_size());
   grpc_pollset_init(pollset, &g_polling_mu);
@@ -114,7 +114,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);
@@ -131,8 +131,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.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index a27284b..7c24af8 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -380,7 +380,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;
@@ -707,7 +707,7 @@
       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);
@@ -833,10 +833,10 @@
      extreme memory pressure. */
   grpc_resource_quota *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 8fac452..3a3261a 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -81,7 +81,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.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
index 10b270c..5fe1f71 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
@@ -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 = {"Metadata-Flavor", "Google"};
   grpc_httpcli_request request;
   memset(&request, 0, sizeof(grpc_httpcli_request));
@@ -409,7 +404,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 = {"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 d9ad669..5d9f243 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -57,7 +57,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;
@@ -70,7 +70,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;
@@ -100,6 +100,6 @@
 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);
 
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H */
diff --git a/src/core/lib/support/time_posix.c b/src/core/lib/support/time_posix.c
index 3ead40d..ad7c503 100644
--- a/src/core/lib/support/time_posix.c
+++ b/src/core/lib/support/time_posix.c
@@ -30,7 +30,7 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 
 static struct timespec timespec_from_gpr(gpr_timespec gts) {
   struct timespec rv;
@@ -159,7 +159,7 @@
     delta_ts = timespec_from_gpr(delta);
     GRPC_SCHEDULING_START_BLOCKING_REGION;
     ns_result = nanosleep(&delta_ts, NULL);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
+    GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
     if (ns_result == 0) {
       break;
     }
diff --git a/src/core/lib/support/time_windows.c b/src/core/lib/support/time_windows.c
index 40df376..b8015c2 100644
--- a/src/core/lib/support/time_windows.c
+++ b/src/core/lib/support/time_windows.c
@@ -28,7 +28,7 @@
 #include <process.h>
 #include <sys/timeb.h>
 
-#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/support/time_precise.h"
 
 static LARGE_INTEGER g_start_time;
@@ -94,7 +94,7 @@
     GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX));
     GRPC_SCHEDULING_START_BLOCKING_REGION;
     Sleep((DWORD)sleep_millis);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
+    GRPC_SCHEDULING_END_BLOCKING_REGION_NO_EXEC_CTX;
   }
 }
 
diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c
index 7d60b1d..4a81d55 100644
--- a/src/core/lib/surface/alarm.c
+++ b/src/core/lib/surface/alarm.c
@@ -114,8 +114,7 @@
   GRPC_CLOSURE_INIT(&alarm->on_alarm, alarm_cb, alarm,
                     grpc_schedule_on_exec_ctx);
   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);
   return alarm;
 }
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index d1589da..f00772c 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -213,7 +213,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;
 
@@ -280,7 +280,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);
@@ -363,11 +363,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;
 
@@ -385,10 +384,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_call->send_deadline.clock_type),
-          args->parent_call->send_deadline);
+      send_deadline = GPR_MIN(send_deadline, args->parent_call->send_deadline);
     }
     /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
      * GRPC_PROPAGATE_STATS_CONTEXT */
@@ -543,8 +539,8 @@
     GRPC_CQ_INTERNAL_UNREF(exec_ctx, c->cq, "bind");
   }
 
-  get_final_status(call, set_status_value_directly, &c->final_info.final_status,
-                   NULL);
+  get_final_status(exec_ctx, call, 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);
 
@@ -724,13 +720,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;
   }
@@ -742,7 +741,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) {
@@ -767,8 +766,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;
         }
       }
@@ -776,8 +776,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;
         }
       }
@@ -1317,11 +1318,11 @@
     }
 
     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);
     }
 
@@ -1597,11 +1598,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 185bfcc..4c9652a 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.c b/src/core/lib/surface/channel.c
index 850fbe6..2cd9e94 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -259,7 +259,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;
 
@@ -305,7 +305,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;
 }
@@ -313,7 +313,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,
@@ -369,7 +369,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 528bb86..827dd99 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -43,7 +43,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.c b/src/core/lib/surface/completion_queue.c
index 10e4e5a..f72eeb5 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -57,8 +57,7 @@
   grpc_error *(*kick)(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);
@@ -96,8 +95,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;
@@ -111,7 +109,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;
@@ -759,7 +760,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;
@@ -788,8 +789,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
@@ -818,7 +818,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 = DATA_FROM_CQ(cq);
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@@ -835,23 +834,21 @@
 
   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 = {
       .last_seen_things_queued_ever =
           gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       .cq = cq,
-      .deadline = deadline,
+      .deadline = deadline_millis,
       .stolen_completion = NULL,
       .tag = NULL,
       .first_loop = 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;
@@ -878,7 +875,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;
       }
     }
 
@@ -899,8 +896,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);
@@ -911,7 +908,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) {
@@ -1045,8 +1042,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,
@@ -1055,7 +1051,6 @@
   grpc_cq_completion *c;
   grpc_cq_completion *prev;
   grpc_pollset_worker *worker = NULL;
-  gpr_timespec now;
   cq_pluck_data *cqd = DATA_FROM_CQ(cq);
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
@@ -1074,15 +1069,14 @@
 
   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 = {
       .last_seen_things_queued_ever =
           gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       .cq = cq,
-      .deadline = deadline,
+      .deadline = deadline_millis,
       .stolen_completion = NULL,
       .tag = tag,
       .first_loop = true};
@@ -1134,8 +1128,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));
@@ -1143,10 +1137,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.c b/src/core/lib/surface/server.c
index 8582d82..84cd1e4 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -136,7 +136,7 @@
   bool host_set;
   grpc_slice path;
   grpc_slice host;
-  gpr_timespec deadline;
+  grpc_millis deadline;
 
   grpc_completion_queue *cq_new;
 
@@ -489,11 +489,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_REALTIME);
       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_REALTIME);
       if (rc->data.registered.optional_payload) {
         *rc->data.registered.optional_payload = calld->payload;
         calld->payload = NULL;
@@ -734,7 +736,7 @@
                                             grpc_error *error) {
   grpc_call_element *elem = ptr;
   call_data *calld = 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);
@@ -754,7 +756,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) {
@@ -828,7 +830,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 =
@@ -876,7 +878,7 @@
   call_data *calld = elem->call_data;
   channel_data *chand = 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/error_utils.c b/src/core/lib/transport/error_utils.c
index 5e3920b..2e3b61b 100644
--- a/src/core/lib/transport/error_utils.c
+++ b/src/core/lib/transport/error_utils.c
@@ -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 e530884..6211031 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"
 
 /// A utility function to get the status code and message to be returned
@@ -28,8 +29,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.c b/src/core/lib/transport/metadata_batch.c
index 8f24b85..a5ff9c9 100644
--- a/src/core/lib/transport/metadata_batch.c
+++ b/src/core/lib/transport/metadata_batch.c
@@ -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,
@@ -268,9 +268,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 1b11a3e..3498cdd 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -50,9 +50,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.c b/src/core/lib/transport/status_conversion.c
index 9a76977..73d20a1 100644
--- a/src/core/lib/transport/status_conversion.c
+++ b/src/core/lib/transport/status_conversion.c
@@ -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 e93f3df..a05ed76 100644
--- a/src/core/lib/transport/status_conversion.h
+++ b/src/core/lib/transport/status_conversion.h
@@ -20,12 +20,14 @@
 #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"
 
 /* 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.c b/src/core/lib/transport/timeout_encoding.c
index 02f179d..779d016 100644
--- a/src/core/lib/transport/timeout_encoding.c
+++ b/src/core/lib/transport/timeout_encoding.c
@@ -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,7 +88,7 @@
   return p == end;
 }
 
-int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout) {
+int grpc_http2_decode_timeout(grpc_slice text, grpc_millis *timeout) {
   int32_t x = 0;
   const uint8_t *p = GRPC_SLICE_START_PTR(text);
   const uint8_t *end = GRPC_SLICE_END_PTR(text);
@@ -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 7ff35c4..c867771 100644
--- a/src/core/lib/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -22,13 +22,14 @@
 #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)
 
 /* 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);
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H */
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 409a6c4..2d0b1e7 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -48,10 +48,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/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 82b4055..a078518 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.c',
   'src/core/lib/support/atm.c',
   'src/core/lib/support/avl.c',
-  'src/core/lib/support/backoff.c',
   'src/core/lib/support/cmdline.c',
   'src/core/lib/support/cpu_iphone.c',
   'src/core/lib/support/cpu_linux.c',
@@ -62,6 +61,7 @@
   'src/core/lib/support/tmpfile_windows.c',
   'src/core/lib/support/wrap_memcpy.c',
   'src/core/lib/surface/init.c',
+  'src/core/lib/backoff/backoff.c',
   'src/core/lib/channel/channel_args.c',
   'src/core/lib/channel/channel_stack.c',
   'src/core/lib/channel/channel_stack_builder.c',
diff --git a/test/core/backoff/BUILD b/test/core/backoff/BUILD
new file mode 100644
index 0000000..6c2ceb4
--- /dev/null
+++ b/test/core/backoff/BUILD
@@ -0,0 +1,34 @@
+# 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 = [
+        "//: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..302ac7b
--- /dev/null
+++ b/test/core/backoff/backoff_test.c
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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;
+  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 2);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 6);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 14);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 30);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 62);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 126);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 254);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 510);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 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 - grpc_exec_ctx_now(&exec_ctx) == 1535);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 2048);
+  exec_ctx.now = next;
+  next = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 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, 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/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/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..46819d0 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -407,10 +407,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 +422,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 +483,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/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c
index 12aceda..4981056 100644
--- a/test/core/end2end/tests/bad_ping.c
+++ b/test/core/end2end/tests/bad_ping.c
@@ -154,14 +154,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);
   }
 
@@ -189,7 +191,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/http/httpcli_test.c b/test/core/http/httpcli_test.c
index b8b96d6..3634932 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 a9d7abd..d03dcdf 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 11b45e8..6848580 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -172,10 +172,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);
@@ -231,11 +232,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);
@@ -260,14 +260,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 c702065..d185653 100644
--- a/test/core/iomgr/ev_epollsig_linux_test.c
+++ b/test/core/iomgr/ev_epollsig_linux_test.c
@@ -237,10 +237,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 85d5d9c..0ed9f8d 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -251,10 +251,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);
@@ -370,10 +368,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);
@@ -476,10 +472,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);
@@ -502,10 +496,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 9cc09ed..0a18ec7 100644
--- a/test/core/iomgr/resolve_address_posix_test.c
+++ b/test/core/iomgr/resolve_address_posix_test.c
@@ -70,35 +70,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 cb156ee..d475b55 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -67,34 +67,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 00ea495..3cae13b 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() {
@@ -107,7 +107,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 {
@@ -125,8 +125,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);
@@ -157,25 +157,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_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index c45068e..03b707c 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -161,7 +161,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,
@@ -193,8 +194,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);
@@ -214,7 +214,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);
@@ -245,8 +246,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);
@@ -318,8 +318,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 {
@@ -352,7 +352,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,
@@ -389,8 +390,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);
@@ -418,7 +418,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;
@@ -456,8 +457,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);
@@ -475,8 +475,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 2371721..0cde2d0 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/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 aa34857..5977da3 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 441c431..fa8f108 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 fdbc6ea..950bcc5 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -103,8 +103,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 e1385a8..c50f16e 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -109,8 +109,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 259038f..e3d7d9d 100644
--- a/test/core/security/verify_jwt.c
+++ b/test/core/security/verify_jwt.c
@@ -101,11 +101,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/support/BUILD b/test/core/support/BUILD
index 7e142c1..7420f37 100644
--- a/test/core/support/BUILD
+++ b/test/core/support/BUILD
@@ -44,16 +44,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 08079b6..1778054 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -134,14 +134,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/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..fcd263f 100644
--- a/test/core/transport/timeout_encoding_test.c
+++ b/test/core/transport/timeout_encoding_test.c
@@ -30,7 +30,7 @@
 
 #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 +39,38 @@
 
 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;
+static void assert_decodes_as(const char *buffer, grpc_millis expected) {
+  grpc_millis got;
   gpr_log(GPR_INFO, "check decoding '%s'", buffer);
   GPR_ASSERT(1 == grpc_http2_decode_timeout(
                       grpc_slice_from_static_string(buffer), &got));
-  GPR_ASSERT(0 == gpr_time_cmp(got, expected));
+  GPR_ASSERT(got == expected);
 }
 
-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 +78,51 @@
   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 x / GPR_NS_PER_MS; }
+static grpc_millis millis_from_micros(int64_t x) { return x / GPR_US_PER_MS; }
+static grpc_millis millis_from_millis(int64_t x) { return x; }
+static grpc_millis millis_from_seconds(int64_t x) { return x * GPR_MS_PER_SEC; }
+static grpc_millis millis_from_minutes(int64_t x) {
+  return x * 60 * GPR_MS_PER_SEC;
+}
+static grpc_millis millis_from_hours(int64_t x) {
+  return 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/port_server_client.c b/test/core/util/port_server_client.c
index d5739ef..e3ef486 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -87,7 +87,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);
@@ -99,8 +99,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;
     }
   }
@@ -171,7 +171,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);
@@ -221,7 +221,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);
@@ -232,8 +232,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/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 518c65a..d4804f6 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 936681f..a08837f 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -297,7 +297,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++) {
@@ -380,7 +380,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());
@@ -502,7 +502,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 f109fe6..b263b80 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -70,9 +70,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_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/third_party/protobuf b/third_party/protobuf
index 80a37e0..a6189ac 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit 80a37e0782d2d702d52234b62dd4b9ec74fd2c95
+Subproject commit a6189acd18b00611c1dc7042299ad75486f08a1a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 3a2cb18..d8cf809 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -931,6 +931,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 \
@@ -1024,7 +1025,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 \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 6a3e268..538fd3b 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1055,6 +1055,8 @@
 src/core/ext/transport/inproc/inproc_transport.c \
 src/core/ext/transport/inproc/inproc_transport.h \
 src/core/lib/README.md \
+src/core/lib/backoff/backoff.c \
+src/core/lib/backoff/backoff.h \
 src/core/lib/channel/README.md \
 src/core/lib/channel/channel_args.c \
 src/core/lib/channel/channel_args.h \
@@ -1296,8 +1298,6 @@
 src/core/lib/support/atomic_with_atm.h \
 src/core/lib/support/atomic_with_std.h \
 src/core/lib/support/avl.c \
-src/core/lib/support/backoff.c \
-src/core/lib/support/backoff.h \
 src/core/lib/support/block_annotate.h \
 src/core/lib/support/cmdline.c \
 src/core/lib/support/cpu_iphone.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 7d708ce..6f74169 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"
     ], 
@@ -717,21 +734,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"
@@ -7588,7 +7590,6 @@
       "src/core/lib/support/arena.c", 
       "src/core/lib/support/atm.c", 
       "src/core/lib/support/avl.c", 
-      "src/core/lib/support/backoff.c", 
       "src/core/lib/support/cmdline.c", 
       "src/core/lib/support/cpu_iphone.c", 
       "src/core/lib/support/cpu_linux.c", 
@@ -7669,7 +7670,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", 
@@ -7718,7 +7718,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", 
@@ -7812,6 +7811,7 @@
     "language": "c", 
     "name": "grpc_base", 
     "src": [
+      "src/core/lib/backoff/backoff.c", 
       "src/core/lib/channel/channel_args.c", 
       "src/core/lib/channel/channel_stack.c", 
       "src/core/lib/channel/channel_stack_builder.c", 
@@ -7963,6 +7963,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", 
@@ -8094,6 +8095,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", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 118e5c6..374b3d5 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"
     ], 
@@ -785,28 +807,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/run_tests.py b/tools/run_tests/run_tests.py
index 4311e53..e7f0abf 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -1467,8 +1467,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