Merge branch 'bs2' into epexinf
diff --git a/BUILD b/BUILD
index 8ccc748..d8bb109 100644
--- a/BUILD
+++ b/BUILD
@@ -515,6 +515,7 @@
         "src/core/lib/support/atomic_with_std.h",
         "src/core/lib/support/env.h",
         "src/core/lib/support/memory.h",
+        "src/core/lib/support/manual_constructor.h",
         "src/core/lib/support/mpscq.h",
         "src/core/lib/support/murmur_hash.h",
         "src/core/lib/support/spinlock.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33e613c..e8137ea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -381,7 +381,6 @@
 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)
 add_dependencies(buildtests_c bin_encoder_test)
 add_dependencies(buildtests_c byte_stream_test)
@@ -636,6 +635,7 @@
 add_dependencies(buildtests_cxx alarm_cpp_test)
 add_dependencies(buildtests_cxx async_end2end_test)
 add_dependencies(buildtests_cxx auth_property_iterator_test)
+add_dependencies(buildtests_cxx bdp_estimator_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_arena)
 endif()
@@ -1616,7 +1616,7 @@
   test/core/end2end/fixtures/http_proxy_fixture.c
   test/core/end2end/fixtures/proxy.c
   test/core/iomgr/endpoint_tests.c
-  test/core/util/debugger_macros.c
+  test/core/util/debugger_macros.cc
   test/core/util/grpc_profiler.c
   test/core/util/memory_counters.c
   test/core/util/mock_endpoint.c
@@ -1880,7 +1880,7 @@
   test/core/end2end/fixtures/http_proxy_fixture.c
   test/core/end2end/fixtures/proxy.c
   test/core/iomgr/endpoint_tests.c
-  test/core/util/debugger_macros.c
+  test/core/util/debugger_macros.cc
   test/core/util/grpc_profiler.c
   test/core/util/memory_counters.c
   test/core/util/mock_endpoint.c
@@ -5259,35 +5259,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(bdp_estimator_test
-  test/core/transport/bdp_estimator_test.c
-)
-
-
-target_include_directories(bdp_estimator_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${BENCHMARK_ROOT_DIR}/include
-  PRIVATE ${ZLIB_ROOT_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-)
-
-target_link_libraries(bdp_estimator_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(bin_decoder_test
   test/core/transport/chttp2/bin_decoder_test.c
 )
@@ -9277,6 +9248,46 @@
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
+
+add_executable(bdp_estimator_test
+  test/core/transport/bdp_estimator_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(bdp_estimator_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(bdp_estimator_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc++
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_arena
diff --git a/Makefile b/Makefile
index 0357f7b..b42d710 100644
--- a/Makefile
+++ b/Makefile
@@ -952,7 +952,6 @@
 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
 bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
 byte_stream_test: $(BINDIR)/$(CONFIG)/byte_stream_test
@@ -1101,6 +1100,7 @@
 alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
 async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
 auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
+bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
 bm_arena: $(BINDIR)/$(CONFIG)/bm_arena
 bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create
 bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
@@ -1352,7 +1352,6 @@
   $(BINDIR)/$(CONFIG)/arena_test \
   $(BINDIR)/$(CONFIG)/backoff_test \
   $(BINDIR)/$(CONFIG)/bad_server_response_test \
-  $(BINDIR)/$(CONFIG)/bdp_estimator_test \
   $(BINDIR)/$(CONFIG)/bin_decoder_test \
   $(BINDIR)/$(CONFIG)/bin_encoder_test \
   $(BINDIR)/$(CONFIG)/byte_stream_test \
@@ -1545,6 +1544,7 @@
   $(BINDIR)/$(CONFIG)/alarm_cpp_test \
   $(BINDIR)/$(CONFIG)/async_end2end_test \
   $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
+  $(BINDIR)/$(CONFIG)/bdp_estimator_test \
   $(BINDIR)/$(CONFIG)/bm_arena \
   $(BINDIR)/$(CONFIG)/bm_call_create \
   $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
@@ -1666,6 +1666,7 @@
   $(BINDIR)/$(CONFIG)/alarm_cpp_test \
   $(BINDIR)/$(CONFIG)/async_end2end_test \
   $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
+  $(BINDIR)/$(CONFIG)/bdp_estimator_test \
   $(BINDIR)/$(CONFIG)/bm_arena \
   $(BINDIR)/$(CONFIG)/bm_call_create \
   $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
@@ -1766,8 +1767,6 @@
 	$(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"
-	$(Q) $(BINDIR)/$(CONFIG)/bdp_estimator_test || ( echo test bdp_estimator_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bin_decoder_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bin_decoder_test || ( echo test bin_decoder_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bin_encoder_test"
@@ -2040,6 +2039,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing auth_property_iterator_test"
 	$(Q) $(BINDIR)/$(CONFIG)/auth_property_iterator_test || ( echo test auth_property_iterator_test failed ; exit 1 )
+	$(E) "[RUN]     Testing bdp_estimator_test"
+	$(Q) $(BINDIR)/$(CONFIG)/bdp_estimator_test || ( echo test bdp_estimator_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_arena"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_arena || ( echo test bm_arena failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_call_create"
@@ -3609,7 +3610,7 @@
     test/core/end2end/fixtures/http_proxy_fixture.c \
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
-    test/core/util/debugger_macros.c \
+    test/core/util/debugger_macros.cc \
     test/core/util/grpc_profiler.c \
     test/core/util/memory_counters.c \
     test/core/util/mock_endpoint.c \
@@ -3864,7 +3865,7 @@
     test/core/end2end/fixtures/http_proxy_fixture.c \
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
-    test/core/util/debugger_macros.c \
+    test/core/util/debugger_macros.cc \
     test/core/util/grpc_profiler.c \
     test/core/util/memory_counters.c \
     test/core/util/mock_endpoint.c \
@@ -8423,7 +8424,7 @@
 
 LIBARES_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBARES_SRC))))
 
-$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
+$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares -fvisibility=hidden -D_GNU_SOURCE $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) $(if $(subst FreeBSD,,$(SYSTEM)),,-Ithird_party/cares/config_freebsd) $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst OpenBSD,,$(SYSTEM)),,-Ithird_party/cares/config_openbsd) -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
 $(LIBARES_OBJS): CFLAGS += -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32) $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
 
 $(LIBDIR)/$(CONFIG)/libares.a: $(ZLIB_DEP)  $(LIBARES_OBJS) 
@@ -8964,38 +8965,6 @@
 endif
 
 
-BDP_ESTIMATOR_TEST_SRC = \
-    test/core/transport/bdp_estimator_test.c \
-
-BDP_ESTIMATOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BDP_ESTIMATOR_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/bdp_estimator_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/bdp_estimator_test: $(BDP_ESTIMATOR_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) $(BDP_ESTIMATOR_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)/bdp_estimator_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/transport/bdp_estimator_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_bdp_estimator_test: $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 BIN_DECODER_TEST_SRC = \
     test/core/transport/chttp2/bin_decoder_test.c \
 
@@ -13771,6 +13740,49 @@
 endif
 
 
+BDP_ESTIMATOR_TEST_SRC = \
+    test/core/transport/bdp_estimator_test.cc \
+
+BDP_ESTIMATOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BDP_ESTIMATOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bdp_estimator_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/bdp_estimator_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bdp_estimator_test: $(PROTOBUF_DEP) $(BDP_ESTIMATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(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) $(LDXX) $(LDFLAGS) $(BDP_ESTIMATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bdp_estimator_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/transport/bdp_estimator_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_bdp_estimator_test: $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 BM_ARENA_SRC = \
     test/cpp/microbenchmarks/bm_arena.cc \
 
diff --git a/build.yaml b/build.yaml
index fac62d2..4cb1b68 100644
--- a/build.yaml
+++ b/build.yaml
@@ -143,6 +143,7 @@
   - src/core/lib/support/atomic_with_atm.h
   - src/core/lib/support/atomic_with_std.h
   - src/core/lib/support/env.h
+  - src/core/lib/support/manual_constructor.h
   - src/core/lib/support/memory.h
   - src/core/lib/support/mpscq.h
   - src/core/lib/support/murmur_hash.h
@@ -741,7 +742,7 @@
   - test/core/end2end/fixtures/http_proxy_fixture.c
   - test/core/end2end/fixtures/proxy.c
   - test/core/iomgr/endpoint_tests.c
-  - test/core/util/debugger_macros.c
+  - test/core/util/debugger_macros.cc
   - test/core/util/grpc_profiler.c
   - test/core/util/memory_counters.c
   - test/core/util/mock_endpoint.c
@@ -1735,6 +1736,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: alloc_test
   build: test
   language: c
@@ -1743,6 +1745,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: alpn_test
   build: test
   language: c
@@ -1775,6 +1778,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: backoff_test
   build: test
   language: c
@@ -1785,6 +1789,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: bad_server_response_test
   build: test
   language: c
@@ -1798,16 +1803,6 @@
   - gpr
   exclude_iomgrs:
   - uv
-- name: bdp_estimator_test
-  build: test
-  language: c
-  src:
-  - test/core/transport/bdp_estimator_test.c
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr_test_util
-  - gpr
 - name: bin_decoder_test
   build: test
   language: c
@@ -1816,6 +1811,7 @@
   deps:
   - grpc_test_util
   - grpc
+  uses_polling: false
 - name: bin_encoder_test
   build: test
   language: c
@@ -1824,6 +1820,7 @@
   deps:
   - grpc_test_util
   - grpc
+  uses_polling: false
 - name: byte_stream_test
   build: test
   language: c
@@ -1834,6 +1831,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: census_context_test
   build: test
   language: c
@@ -1844,6 +1842,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: census_intrusive_hash_map_test
   build: test
   language: c
@@ -1854,6 +1853,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: census_resource_test
   build: test
   language: c
@@ -1864,6 +1864,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: census_trace_context_test
   build: test
   language: c
@@ -1874,6 +1875,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: channel_create_test
   build: test
   language: c
@@ -1902,6 +1904,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: chttp2_stream_map_test
   build: test
   language: c
@@ -1912,6 +1915,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: chttp2_varint_test
   build: test
   language: c
@@ -1922,6 +1926,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: client_fuzzer
   build: fuzzer
   language: c
@@ -1957,6 +1962,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: concurrent_connectivity_test
   cpu_cost: 2.0
   build: test
@@ -2044,6 +2050,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: ev_epollsig_linux_test
   cpu_cost: 3
   build: test
@@ -2176,6 +2183,7 @@
   deps:
   - gpr
   - grpc
+  uses_polling: false
 - name: gen_legal_metadata_characters
   build: tool
   language: c
@@ -2188,6 +2196,7 @@
   src:
   - tools/codegen/core/gen_percent_encoding_tables.c
   deps: []
+  uses_polling: false
 - name: goaway_server_test
   cpu_cost: 0.1
   build: test
@@ -2213,6 +2222,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_cmdline_test
   build: test
   language: c
@@ -2221,6 +2231,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_cpu_test
   cpu_cost: 30
   build: test
@@ -2230,6 +2241,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_env_test
   build: test
   language: c
@@ -2238,6 +2250,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_histogram_test
   build: test
   language: c
@@ -2246,6 +2259,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_host_port_test
   build: test
   language: c
@@ -2254,6 +2268,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_log_test
   build: test
   language: c
@@ -2262,6 +2277,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_mpscq_test
   cpu_cost: 30
   build: test
@@ -2281,6 +2297,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_stack_lockfree_test
   cpu_cost: 7
   build: test
@@ -2290,6 +2307,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_string_test
   build: test
   language: c
@@ -2298,6 +2316,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_sync_test
   cpu_cost: 10
   build: test
@@ -2307,6 +2326,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_thd_test
   cpu_cost: 10
   build: test
@@ -2316,6 +2336,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_time_test
   build: test
   language: c
@@ -2324,6 +2345,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_tls_test
   build: test
   language: c
@@ -2332,6 +2354,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: gpr_useful_test
   build: test
   language: c
@@ -2340,6 +2363,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_auth_context_test
   build: test
   language: c
@@ -2350,6 +2374,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_b64_test
   build: test
   language: c
@@ -2360,6 +2385,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_byte_buffer_reader_test
   build: test
   language: c
@@ -2370,6 +2396,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_channel_args_test
   build: test
   language: c
@@ -2380,6 +2407,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_channel_stack_builder_test
   build: test
   language: c
@@ -2400,6 +2428,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_completion_queue_test
   build: test
   language: c
@@ -2431,6 +2460,7 @@
   - grpc
   - gpr
   secure: true
+  uses_polling: false
 - name: grpc_credentials_test
   build: test
   language: c
@@ -2462,6 +2492,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_json_token_test
   build: test
   language: c
@@ -2476,6 +2507,7 @@
   - linux
   - posix
   - mac
+  uses_polling: false
 - name: grpc_jwt_verifier_test
   build: test
   language: c
@@ -2486,6 +2518,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: grpc_print_google_default_creds_token
   build: tool
   language: c
@@ -2494,6 +2527,7 @@
   deps:
   - grpc
   - gpr
+  uses_polling: false
 - name: grpc_security_connector_test
   build: test
   language: c
@@ -2512,6 +2546,7 @@
   deps:
   - grpc
   - gpr
+  uses_polling: false
 - name: handshake_client
   build: test
   language: c
@@ -2566,6 +2601,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: hpack_table_test
   build: test
   language: c
@@ -2576,6 +2612,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: http_parser_test
   build: test
   language: c
@@ -2586,6 +2623,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: http_request_fuzzer_test
   build: fuzzer
   language: c
@@ -2660,6 +2698,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: invalid_call_argument_test
   cpu_cost: 0.1
   build: test
@@ -2693,6 +2732,7 @@
   deps:
   - grpc
   - gpr
+  uses_polling: false
 - name: json_rewrite_test
   build: test
   language: c
@@ -2703,6 +2743,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: json_stream_error_test
   build: test
   language: c
@@ -2713,6 +2754,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: json_test
   build: test
   language: c
@@ -2723,6 +2765,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: lame_client_test
   build: test
   language: c
@@ -2745,6 +2788,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: load_file_test
   build: test
   language: c
@@ -2755,6 +2799,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: low_level_ping_pong_benchmark
   build: benchmark
   language: c
@@ -2780,6 +2825,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: memory_profile_server
   build: test
   run: false
@@ -2816,6 +2862,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: minimal_stack_is_minimal_test
   build: test
   language: c
@@ -2826,6 +2873,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: mlog_test
   flaky: true
   build: test
@@ -2837,6 +2885,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: multiple_server_queues_test
   build: test
   language: c
@@ -2855,6 +2904,7 @@
   deps:
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: nanopb_fuzzer_response_test
   build: fuzzer
   language: c
@@ -2914,6 +2964,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: percent_decode_fuzzer
   build: fuzzer
   language: c
@@ -2950,6 +3001,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: pollset_set_test
   build: test
   language: c
@@ -3079,6 +3131,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: slice_hash_table_test
   build: test
   language: c
@@ -3089,6 +3142,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: slice_string_helpers_test
   build: test
   language: c
@@ -3099,6 +3153,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: slice_test
   build: test
   language: c
@@ -3109,6 +3164,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: sockaddr_resolver_test
   build: test
   language: c
@@ -3183,6 +3239,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: stream_compression_test
   build: test
   language: c
@@ -3193,6 +3250,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: stream_owned_slice_test
   build: test
   language: c
@@ -3203,6 +3261,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: tcp_client_posix_test
   cpu_cost: 0.5
   build: test
@@ -3288,6 +3347,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: timeout_encoding_test
   build: test
   language: c
@@ -3298,6 +3358,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: timer_heap_test
   build: test
   language: c
@@ -3310,6 +3371,7 @@
   - gpr
   exclude_iomgrs:
   - uv
+  uses_polling: false
 - name: timer_list_test
   build: test
   language: c
@@ -3322,6 +3384,7 @@
   - gpr
   exclude_iomgrs:
   - uv
+  uses_polling: false
 - name: transport_connectivity_state_test
   build: test
   language: c
@@ -3342,6 +3405,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: transport_pid_controller_test
   build: test
   language: c
@@ -3352,6 +3416,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: transport_security_test
   build: test
   language: c
@@ -3460,6 +3525,20 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
+- name: bdp_estimator_test
+  build: test
+  language: c++
+  src:
+  - test/core/transport/bdp_estimator_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc++
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses_polling: false
 - name: bm_arena
   build: test
   language: c++
@@ -3481,6 +3560,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: bm_call_create
   build: test
   language: c++
@@ -3502,6 +3582,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: bm_chttp2_hpack
   build: test
   language: c++
@@ -3523,6 +3604,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: bm_chttp2_transport
   build: test
   language: c++
@@ -3628,6 +3710,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: bm_fullstack_streaming_ping_pong
   build: test
   language: c++
@@ -3756,6 +3839,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: bm_pollset
   build: test
   language: c++
@@ -3787,6 +3871,7 @@
   - grpc++
   - grpc
   - gpr
+  uses_polling: false
 - name: channel_filter_test
   gtest: true
   build: test
@@ -3797,6 +3882,7 @@
   - grpc++
   - grpc
   - gpr
+  uses_polling: false
 - name: cli_call_test
   gtest: true
   build: test
@@ -3876,6 +3962,7 @@
   - gpr
   filegroups:
   - grpc++_codegen_base
+  uses_polling: false
 - name: codegen_test_minimal
   gtest: true
   build: test
@@ -3894,6 +3981,7 @@
   filegroups:
   - grpc++_codegen_base
   - grpc++_codegen_base_src
+  uses_polling: false
 - name: credentials_test
   gtest: true
   build: test
@@ -3916,6 +4004,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: cxx_slice_test
   gtest: true
   build: test
@@ -3928,6 +4017,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: cxx_string_ref_test
   gtest: true
   build: test
@@ -3937,6 +4027,7 @@
   deps:
   - grpc++
   - grpc
+  uses_polling: false
 - name: cxx_time_test
   gtest: true
   build: test
@@ -3949,6 +4040,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: end2end_test
   gtest: true
   cpu_cost: 0.5
@@ -4012,6 +4104,7 @@
   - gpr
   args:
   - --generated_file_path=gens/src/proto/grpc/testing/
+  uses_polling: false
 - name: grpc_cli
   build: test
   run: false
@@ -4304,6 +4397,7 @@
   - gpr
   uses:
   - grpc++_test
+  uses_polling: false
 - name: metrics_client
   build: test
   run: false
@@ -4368,6 +4462,7 @@
   filegroups:
   - grpc++_codegen_base
   - grpc++_codegen_proto
+  uses_polling: false
 - name: qps_interarrival_test
   build: test
   run: false
@@ -4387,6 +4482,7 @@
   - mac
   - linux
   - posix
+  uses_polling: false
 - name: qps_json_driver
   build: test
   run: false
@@ -4623,6 +4719,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: status_test
   build: test
   language: c++
@@ -4634,6 +4731,7 @@
   - grpc
   - gpr_test_util
   - gpr
+  uses_polling: false
 - name: streaming_throughput_test
   gtest: true
   build: test
@@ -4870,10 +4968,11 @@
   ares:
     CFLAGS: -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32)
       $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
-    CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
-      $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden
-      -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst
-      MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
+    CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares -fvisibility=hidden -D_GNU_SOURCE
+      $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) $(if $(subst
+      FreeBSD,,$(SYSTEM)),,-Ithird_party/cares/config_freebsd) $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
+      $(if $(subst OpenBSD,,$(SYSTEM)),,-Ithird_party/cares/config_openbsd) -DWIN32_LEAN_AND_MEAN
+      -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
   benchmark:
     CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
   boringssl:
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index f19b672..ce1425a 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -191,6 +191,7 @@
                       'src/core/lib/support/atomic_with_atm.h',
                       'src/core/lib/support/atomic_with_std.h',
                       'src/core/lib/support/env.h',
+                      'src/core/lib/support/manual_constructor.h',
                       'src/core/lib/support/memory.h',
                       'src/core/lib/support/mpscq.h',
                       'src/core/lib/support/murmur_hash.h',
@@ -736,6 +737,7 @@
                               'src/core/lib/support/atomic_with_atm.h',
                               'src/core/lib/support/atomic_with_std.h',
                               'src/core/lib/support/env.h',
+                              'src/core/lib/support/manual_constructor.h',
                               'src/core/lib/support/memory.h',
                               'src/core/lib/support/mpscq.h',
                               'src/core/lib/support/murmur_hash.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index ce23e6f..ab51cc8 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -89,6 +89,7 @@
   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/env.h )
+  s.files += %w( src/core/lib/support/manual_constructor.h )
   s.files += %w( src/core/lib/support/memory.h )
   s.files += %w( src/core/lib/support/mpscq.h )
   s.files += %w( src/core/lib/support/murmur_hash.h )
@@ -1123,8 +1124,10 @@
   s.files += %w( third_party/cares/cares/config-win32.h )
   s.files += %w( third_party/cares/cares/setup_once.h )
   s.files += %w( third_party/cares/ares_build.h )
-  s.files += %w( third_party/cares/config_linux/ares_config.h )
   s.files += %w( third_party/cares/config_darwin/ares_config.h )
+  s.files += %w( third_party/cares/config_freebsd/ares_config.h )
+  s.files += %w( third_party/cares/config_linux/ares_config.h )
+  s.files += %w( third_party/cares/config_openbsd/ares_config.h )
   s.files += %w( third_party/cares/cares/ares__close_sockets.c )
   s.files += %w( third_party/cares/cares/ares__get_hostent.c )
   s.files += %w( third_party/cares/cares/ares__read_line.c )
diff --git a/grpc.gyp b/grpc.gyp
index 53e3885..d5a20fa 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -515,7 +515,7 @@
         'test/core/end2end/fixtures/http_proxy_fixture.c',
         'test/core/end2end/fixtures/proxy.c',
         'test/core/iomgr/endpoint_tests.c',
-        'test/core/util/debugger_macros.c',
+        'test/core/util/debugger_macros.cc',
         'test/core/util/grpc_profiler.c',
         'test/core/util/memory_counters.c',
         'test/core/util/mock_endpoint.c',
@@ -722,7 +722,7 @@
         'test/core/end2end/fixtures/http_proxy_fixture.c',
         'test/core/end2end/fixtures/proxy.c',
         'test/core/iomgr/endpoint_tests.c',
-        'test/core/util/debugger_macros.c',
+        'test/core/util/debugger_macros.cc',
         'test/core/util/grpc_profiler.c',
         'test/core/util/memory_counters.c',
         'test/core/util/mock_endpoint.c',
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index d9988e5..00521a5 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -318,7 +318,11 @@
 Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
   write_options_ = options;
   bool own_buf;
-  Status result = SerializationTraits<M>::Serialize(
+  // TODO(vjpai): Remove the void below when possible
+  // The void in the template parameter below should not be needed
+  // (since it should be implicit) but is needed due to an observed
+  // difference in behavior between clang and gcc for certain internal users
+  Status result = SerializationTraits<M, void>::Serialize(
       message, send_buf_.bbuf_ptr(), &own_buf);
   if (!own_buf) {
     send_buf_.Duplicate();
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index baea4bc..fb4bfc3 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -241,6 +241,29 @@
 #else /* _LP64 */
 #define GPR_ARCH_32 1
 #endif /* _LP64 */
+#elif defined(__OpenBSD__)
+#define GPR_PLATFORM_STRING "openbsd"
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#define GPR_OPENBSD 1
+#define GPR_CPU_POSIX 1
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_TMPFILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_SUPPORT_CHANNELS_FROM_FD 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
 #elif defined(__native_client__)
 #define GPR_PLATFORM_STRING "nacl"
 #ifndef _BSD_SOURCE
diff --git a/package.xml b/package.xml
index df01421..e590745 100644
--- a/package.xml
+++ b/package.xml
@@ -101,6 +101,7 @@
     <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/env.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/manual_constructor.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/memory.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/mpscq.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
diff --git a/setup.py b/setup.py
index 90c9316..bf8aea6 100644
--- a/setup.py
+++ b/setup.py
@@ -40,10 +40,14 @@
 CARES_INCLUDE = (
     os.path.join('third_party', 'cares'),
     os.path.join('third_party', 'cares', 'cares'),)
-if 'linux' in sys.platform:
-  CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
 if 'darwin' in sys.platform:
   CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_darwin'),)
+if 'freebsd' in sys.platform:
+  CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_freebsd'),)
+if 'linux' in sys.platform:
+  CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
+if 'openbsd' in sys.platform:
+  CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),)
 README = os.path.join(PYTHON_STEM, 'README.rst')
 
 # Ensure we're in the proper directory whether or not we're being used by pip.
diff --git a/src/c-ares/gen_build_yaml.py b/src/c-ares/gen_build_yaml.py
index 6f8b748..4600d8d 100755
--- a/src/c-ares/gen_build_yaml.py
+++ b/src/c-ares/gen_build_yaml.py
@@ -29,10 +29,14 @@
     subprocess.call("third_party/cares/cares/configure", shell=True)
 
   def config_platform(x):
-    if 'linux' in sys.platform:
-      return 'src/cares/cares/config_linux/ares_config.h'
     if 'darwin' in sys.platform:
       return 'src/cares/cares/config_darwin/ares_config.h'
+    if 'freebsd' in sys.platform:
+      return 'src/cares/cares/config_freebsd/ares_config.h'
+    if 'linux' in sys.platform:
+      return 'src/cares/cares/config_linux/ares_config.h'
+    if 'openbsd' in sys.platform:
+      return 'src/cares/cares/config_openbsd/ares_config.h'
     if not os.path.isfile('third_party/cares/cares/ares_config.h'):
       gen_ares_build(x)
     return 'third_party/cares/cares/ares_config.h'
@@ -124,8 +128,10 @@
         "third_party/cares/cares/config-win32.h",
         "third_party/cares/cares/setup_once.h",
         "third_party/cares/ares_build.h",
+        "third_party/cares/config_darwin/ares_config.h",
+        "third_party/cares/config_freebsd/ares_config.h",
         "third_party/cares/config_linux/ares_config.h",
-        "third_party/cares/config_darwin/ares_config.h"
+        "third_party/cares/config_openbsd/ares_config.h"
     ],
   }]
 except:
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index e4b19a2..0ef06ae 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -218,6 +218,8 @@
     t->write_cb_pool = next;
   }
 
+  t->flow_control.bdp_estimator.Destroy();
+
   gpr_free(t->ping_acks);
   gpr_free(t->peer_string);
   gpr_free(t);
@@ -315,7 +317,7 @@
                     keepalive_watchdog_fired_locked, t,
                     grpc_combiner_scheduler(t->combiner));
 
-  grpc_bdp_estimator_init(&t->flow_control.bdp_estimator, t->peer_string);
+  t->flow_control.bdp_estimator.Init(t->peer_string);
 
   grpc_chttp2_goaway_parser_init(&t->goaway_parser);
   grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
@@ -2434,7 +2436,7 @@
   }
   if (action.need_ping) {
     GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
-    grpc_bdp_estimator_schedule_ping(&t->flow_control.bdp_estimator);
+    t->flow_control.bdp_estimator->SchedulePing();
     send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
                      &t->finish_bdp_ping_locked);
   }
@@ -2493,8 +2495,7 @@
     grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
                              GRPC_ERROR_NONE};
     for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
-      grpc_bdp_estimator_add_incoming_bytes(
-          &t->flow_control.bdp_estimator,
+      t->flow_control.bdp_estimator->AddIncomingBytes(
           (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]));
       errors[1] =
           grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]);
@@ -2569,7 +2570,7 @@
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
     grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
   }
-  grpc_bdp_estimator_start_ping(&t->flow_control.bdp_estimator);
+  t->flow_control.bdp_estimator->StartPing();
 }
 
 static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
@@ -2578,7 +2579,7 @@
   if (GRPC_TRACER_ON(grpc_http_trace)) {
     gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string);
   }
-  grpc_bdp_estimator_complete_ping(exec_ctx, &t->flow_control.bdp_estimator);
+  t->flow_control.bdp_estimator->CompletePing(exec_ctx);
 
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 }
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 2428e25..60c43d8 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -459,12 +459,11 @@
     }
   }
   if (tfc->enable_bdp_probe) {
-    action.need_ping =
-        grpc_bdp_estimator_need_ping(exec_ctx, &tfc->bdp_estimator);
+    action.need_ping = tfc->bdp_estimator->NeedPing(exec_ctx);
 
     // get bdp estimate and update initial_window accordingly.
     int64_t estimate = -1;
-    if (grpc_bdp_estimator_get_estimate(&tfc->bdp_estimator, &estimate)) {
+    if (tfc->bdp_estimator->EstimateBdp(&estimate)) {
       double target = 1 + log2((double)estimate);
 
       // target might change based on how much memory pressure we are under
@@ -491,7 +490,7 @@
 
     // get bandwidth estimate and update max_frame accordingly.
     double bw_dbl = -1;
-    if (grpc_bdp_estimator_get_bw(&tfc->bdp_estimator, &bw_dbl)) {
+    if (tfc->bdp_estimator->EstimateBandwidth(&bw_dbl)) {
       // we target the max of BDP or bandwidth in microseconds.
       int32_t frame_size = (int32_t)GPR_CLAMP(
           GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 5d27bb8..f7a57a6 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -37,6 +37,7 @@
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/support/manual_constructor.h"
 #include "src/core/lib/transport/bdp_estimator.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/pid_controller.h"
@@ -268,7 +269,7 @@
   bool enable_bdp_probe;
 
   /* bdp estimation */
-  grpc_bdp_estimator bdp_estimator;
+  grpc_core::ManualConstructor<grpc_core::BdpEstimator> bdp_estimator;
 
   /* pid controller */
   bool pid_controller_initialized;
diff --git a/src/core/lib/debug/stats_data.cc b/src/core/lib/debug/stats_data.cc
index b4ae8f3..5d737c5 100644
--- a/src/core/lib/debug/stats_data.cc
+++ b/src/core/lib/debug/stats_data.cc
@@ -104,6 +104,10 @@
     "combiner_locks_scheduled_items",
     "combiner_locks_scheduled_final_items",
     "combiner_locks_offloaded",
+    "call_combiner_locks_initiated",
+    "call_combiner_locks_scheduled_items",
+    "call_combiner_set_notify_on_cancel",
+    "call_combiner_cancelled",
     "executor_scheduled_short_items",
     "executor_scheduled_long_items",
     "executor_scheduled_to_self",
@@ -213,6 +217,11 @@
     "Number of items scheduled against combiner locks",
     "Number of final items scheduled against combiner locks",
     "Number of combiner locks offloaded to different threads",
+    "Number of call combiner lock entries by process (first items queued to a "
+    "call combiner)",
+    "Number of items scheduled against call combiner locks",
+    "Number of times a cancellation callback was set on a call combiner",
+    "Number of times a call combiner was cancelled",
     "Number of finite runtime closures scheduled against the executor (gRPC "
     "thread pool)",
     "Number of potentially infinite runtime closures scheduled against the "
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
index d4c4437..031942d 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -110,6 +110,10 @@
   GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_ITEMS,
   GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS,
   GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED,
+  GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_INITIATED,
+  GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS,
+  GRPC_STATS_COUNTER_CALL_COMBINER_SET_NOTIFY_ON_CANCEL,
+  GRPC_STATS_COUNTER_CALL_COMBINER_CANCELLED,
   GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_SHORT_ITEMS,
   GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_LONG_ITEMS,
   GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_TO_SELF,
@@ -407,6 +411,17 @@
 #define GRPC_STATS_INC_COMBINER_LOCKS_OFFLOADED(exec_ctx) \
   GRPC_STATS_INC_COUNTER((exec_ctx),                      \
                          GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED)
+#define GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(exec_ctx) \
+  GRPC_STATS_INC_COUNTER((exec_ctx),                           \
+                         GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_INITIATED)
+#define GRPC_STATS_INC_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx) \
+  GRPC_STATS_INC_COUNTER(                                            \
+      (exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS)
+#define GRPC_STATS_INC_CALL_COMBINER_SET_NOTIFY_ON_CANCEL(exec_ctx) \
+  GRPC_STATS_INC_COUNTER(                                           \
+      (exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_SET_NOTIFY_ON_CANCEL)
+#define GRPC_STATS_INC_CALL_COMBINER_CANCELLED(exec_ctx) \
+  GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_CANCELLED)
 #define GRPC_STATS_INC_EXECUTOR_SCHEDULED_SHORT_ITEMS(exec_ctx) \
   GRPC_STATS_INC_COUNTER((exec_ctx),                            \
                          GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_SHORT_ITEMS)
diff --git a/src/core/lib/debug/stats_data.yaml b/src/core/lib/debug/stats_data.yaml
index 00e81e7..af45530 100644
--- a/src/core/lib/debug/stats_data.yaml
+++ b/src/core/lib/debug/stats_data.yaml
@@ -245,6 +245,16 @@
   doc: Number of final items scheduled against combiner locks
 - counter: combiner_locks_offloaded
   doc: Number of combiner locks offloaded to different threads
+# call combiner locks
+- counter: call_combiner_locks_initiated
+  doc: Number of call combiner lock entries by process
+       (first items queued to a call combiner)
+- counter: call_combiner_locks_scheduled_items
+  doc: Number of items scheduled against call combiner locks
+- counter: call_combiner_set_notify_on_cancel
+  doc: Number of times a cancellation callback was set on a call combiner
+- counter: call_combiner_cancelled
+  doc: Number of times a call combiner was cancelled
 # executor
 - counter: executor_scheduled_short_items
   doc: Number of finite runtime closures scheduled against the executor
@@ -282,4 +292,3 @@
 - counter: cq_ev_queue_transient_pop_failures
   doc: Number of times NULL was popped out of completion queue's event queue
        even though the event queue was not empty
-
diff --git a/src/core/lib/debug/stats_data_bq_schema.sql b/src/core/lib/debug/stats_data_bq_schema.sql
index f34b0c2..04b6d47 100644
--- a/src/core/lib/debug/stats_data_bq_schema.sql
+++ b/src/core/lib/debug/stats_data_bq_schema.sql
@@ -79,6 +79,10 @@
 combiner_locks_scheduled_items_per_iteration:FLOAT,
 combiner_locks_scheduled_final_items_per_iteration:FLOAT,
 combiner_locks_offloaded_per_iteration:FLOAT,
+call_combiner_locks_initiated_per_iteration:FLOAT,
+call_combiner_locks_scheduled_items_per_iteration:FLOAT,
+call_combiner_set_notify_on_cancel_per_iteration:FLOAT,
+call_combiner_cancelled_per_iteration:FLOAT,
 executor_scheduled_short_items_per_iteration:FLOAT,
 executor_scheduled_long_items_per_iteration:FLOAT,
 executor_scheduled_to_self_per_iteration:FLOAT,
diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc
index bab3df0..d457196 100644
--- a/src/core/lib/iomgr/call_combiner.cc
+++ b/src/core/lib/iomgr/call_combiner.cc
@@ -21,6 +21,8 @@
 #include <inttypes.h>
 
 #include <grpc/support/log.h>
+#include "src/core/lib/debug/stats.h"
+#include "src/core/lib/profiling/timers.h"
 
 grpc_tracer_flag grpc_call_combiner_trace =
     GRPC_TRACER_INITIALIZER(false, "call_combiner");
@@ -60,6 +62,7 @@
                               grpc_closure* closure,
                               grpc_error* error DEBUG_ARGS,
                               const char* reason) {
+  GPR_TIMER_BEGIN("call_combiner_start", 0);
   if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
     gpr_log(GPR_DEBUG,
             "==> grpc_call_combiner_start() [%p] closure=%p [" DEBUG_FMT_STR
@@ -73,7 +76,10 @@
     gpr_log(GPR_DEBUG, "  size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
             prev_size + 1);
   }
+  GRPC_STATS_INC_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx);
   if (prev_size == 0) {
+    GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(exec_ctx);
+    GPR_TIMER_MARK("call_combiner_initiate", 0);
     if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
       gpr_log(GPR_DEBUG, "  EXECUTING IMMEDIATELY");
     }
@@ -87,11 +93,13 @@
     closure->error_data.error = error;
     gpr_mpscq_push(&call_combiner->queue, (gpr_mpscq_node*)closure);
   }
+  GPR_TIMER_END("call_combiner_start", 0);
 }
 
 void grpc_call_combiner_stop(grpc_exec_ctx* exec_ctx,
                              grpc_call_combiner* call_combiner DEBUG_ARGS,
                              const char* reason) {
+  GPR_TIMER_BEGIN("call_combiner_stop", 0);
   if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
     gpr_log(GPR_DEBUG,
             "==> grpc_call_combiner_stop() [%p] [" DEBUG_FMT_STR "%s]",
@@ -130,11 +138,13 @@
   } else if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
     gpr_log(GPR_DEBUG, "  queue empty");
   }
+  GPR_TIMER_END("call_combiner_stop", 0);
 }
 
 void grpc_call_combiner_set_notify_on_cancel(grpc_exec_ctx* exec_ctx,
                                              grpc_call_combiner* call_combiner,
                                              grpc_closure* closure) {
+  GRPC_STATS_INC_CALL_COMBINER_SET_NOTIFY_ON_CANCEL(exec_ctx);
   while (true) {
     // Decode original state.
     gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state);
@@ -179,6 +189,7 @@
 void grpc_call_combiner_cancel(grpc_exec_ctx* exec_ctx,
                                grpc_call_combiner* call_combiner,
                                grpc_error* error) {
+  GRPC_STATS_INC_CALL_COMBINER_CANCELLED(exec_ctx);
   while (true) {
     gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state);
     grpc_error* original_error = decode_cancel_state_error(original_state);
diff --git a/src/core/lib/iomgr/combiner.cc b/src/core/lib/iomgr/combiner.cc
index 0e707ef..53f4b7e 100644
--- a/src/core/lib/iomgr/combiner.cc
+++ b/src/core/lib/iomgr/combiner.cc
@@ -165,6 +165,7 @@
                               lock, cl, last));
   if (last == 1) {
     GRPC_STATS_INC_COMBINER_LOCKS_INITIATED(exec_ctx);
+    GPR_TIMER_MARK("combiner.initiated", 0);
     gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null,
                              (gpr_atm)exec_ctx);
     // first element on this list: add it to the list of combiner locks
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 42033d0..1cc6d98 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -109,6 +109,16 @@
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
 #define GRPC_TIMER_USE_GENERIC 1
+#elif defined(GPR_OPENBSD)
+#define GRPC_HAVE_IFADDRS 1
+#define GRPC_HAVE_IPV6_RECVPKTINFO 1
+#define GRPC_HAVE_UNIX_SOCKET 1
+#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#define GRPC_POSIX_SOCKET 1
+#define GRPC_POSIX_SOCKETADDR 1
+#define GRPC_POSIX_SOCKETUTILS 1
+#define GRPC_POSIX_WAKEUP_FD 1
+#define GRPC_TIMER_USE_GENERIC 1
 #elif defined(GPR_NACL)
 #define GRPC_HAVE_ARPA_NAMESER 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
diff --git a/src/core/lib/support/manual_constructor.h b/src/core/lib/support/manual_constructor.h
new file mode 100644
index 0000000..d753cf9
--- /dev/null
+++ b/src/core/lib/support/manual_constructor.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H
+#define GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H
+
+// manually construct a region of memory with some type
+
+#include <stddef.h>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace grpc_core {
+
+template <typename Type>
+class ManualConstructor {
+ public:
+  // No constructor or destructor because one of the most useful uses of
+  // this class is as part of a union, and members of a union could not have
+  // constructors or destructors till C++11.  And, anyway, the whole point of
+  // this class is to bypass constructor and destructor.
+
+  Type* get() { return reinterpret_cast<Type*>(&space_); }
+  const Type* get() const { return reinterpret_cast<const Type*>(&space_); }
+
+  Type* operator->() { return get(); }
+  const Type* operator->() const { return get(); }
+
+  Type& operator*() { return *get(); }
+  const Type& operator*() const { return *get(); }
+
+  void Init() { new (&space_) Type; }
+
+  // Init() constructs the Type instance using the given arguments
+  // (which are forwarded to Type's constructor).
+  //
+  // Note that Init() with no arguments performs default-initialization,
+  // not zero-initialization (i.e it behaves the same as "new Type;", not
+  // "new Type();"), so it will leave non-class types uninitialized.
+  template <typename... Ts>
+  void Init(Ts&&... args) {
+    new (&space_) Type(std::forward<Ts>(args)...);
+  }
+
+  // Init() that is equivalent to copy and move construction.
+  // Enables usage like this:
+  //   ManualConstructor<std::vector<int>> v;
+  //   v.Init({1, 2, 3});
+  void Init(const Type& x) { new (&space_) Type(x); }
+  void Init(Type&& x) { new (&space_) Type(std::move(x)); }
+
+  void Destroy() { get()->~Type(); }
+
+ private:
+  typename std::aligned_storage<sizeof(Type), alignof(Type)>::type space_;
+};
+
+}  // namespace grpc_core
+
+#endif
diff --git a/src/core/lib/support/time_posix.cc b/src/core/lib/support/time_posix.cc
index 3267ea6..3f8a909 100644
--- a/src/core/lib/support/time_posix.cc
+++ b/src/core/lib/support/time_posix.cc
@@ -42,7 +42,7 @@
   return rv;
 }
 
-#if _POSIX_TIMERS > 0
+#if _POSIX_TIMERS > 0 || defined(__OpenBSD__)
 static gpr_timespec gpr_from_timespec(struct timespec ts,
                                       gpr_clock_type clock_type) {
   /*
diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc
index 6ed427c..2a1c97c 100644
--- a/src/core/lib/transport/bdp_estimator.cc
+++ b/src/core/lib/transport/bdp_estimator.cc
@@ -21,117 +21,65 @@
 #include <inttypes.h>
 #include <stdlib.h>
 
-#include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
 grpc_tracer_flag grpc_bdp_estimator_trace =
     GRPC_TRACER_INITIALIZER(false, "bdp_estimator");
 
-void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) {
-  estimator->estimate = 65536;
-  estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
-  estimator->ping_start_time = gpr_time_0(GPR_CLOCK_MONOTONIC);
-  estimator->next_ping_scheduled = 0;
-  estimator->name = name;
-  estimator->bw_est = 0;
-  estimator->inter_ping_delay = 100.0;  // start at 100ms
-  estimator->stable_estimate_count = 0;
-}
+namespace grpc_core {
 
-bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator,
-                                     int64_t *estimate) {
-  *estimate = estimator->estimate;
-  return true;
-}
+BdpEstimator::BdpEstimator(const char *name)
+    : ping_state_(PingState::UNSCHEDULED),
+      accumulator_(0),
+      estimate_(65536),
+      ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)),
+      next_ping_scheduled_(0),
+      inter_ping_delay_(100.0),  // start at 100ms
+      stable_estimate_count_(0),
+      bw_est_(0),
+      name_(name) {}
 
-bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator,
-                               double *bw) {
-  *bw = estimator->bw_est;
-  return true;
-}
-
-void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
-                                           int64_t num_bytes) {
-  estimator->accumulator += num_bytes;
-}
-
-bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
-                                  const grpc_bdp_estimator *estimator) {
-  switch (estimator->ping_state) {
-    case GRPC_BDP_PING_UNSCHEDULED:
-      return grpc_exec_ctx_now(exec_ctx) >= estimator->next_ping_scheduled;
-    case GRPC_BDP_PING_SCHEDULED:
-      return false;
-    case GRPC_BDP_PING_STARTED:
-      return false;
-  }
-  GPR_UNREACHABLE_CODE(return false);
-}
-
-void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator) {
-  if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-    gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64,
-            estimator->name, estimator->accumulator, estimator->estimate);
-  }
-  GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_UNSCHEDULED);
-  estimator->ping_state = GRPC_BDP_PING_SCHEDULED;
-  estimator->accumulator = 0;
-}
-
-void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator) {
-  if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-    gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64,
-            estimator->name, estimator->accumulator, estimator->estimate);
-  }
-  GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_SCHEDULED);
-  estimator->ping_state = GRPC_BDP_PING_STARTED;
-  estimator->accumulator = 0;
-  estimator->ping_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
-}
-
-void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
-                                      grpc_bdp_estimator *estimator) {
+void BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) {
   gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-  gpr_timespec dt_ts = gpr_time_sub(now, estimator->ping_start_time);
+  gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_);
   double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec;
-  double bw = dt > 0 ? ((double)estimator->accumulator / dt) : 0;
-  int start_inter_ping_delay = estimator->inter_ping_delay;
+  double bw = dt > 0 ? ((double)accumulator_ / dt) : 0;
+  int start_inter_ping_delay = inter_ping_delay_;
   if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
     gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64
                        " dt=%lf bw=%lfMbs bw_est=%lfMbs",
-            estimator->name, estimator->accumulator, estimator->estimate, dt,
-            bw / 125000.0, estimator->bw_est / 125000.0);
+            name_, accumulator_, estimate_, dt, bw / 125000.0,
+            bw_est_ / 125000.0);
   }
-  GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_STARTED);
-  if (estimator->accumulator > 2 * estimator->estimate / 3 &&
-      bw > estimator->bw_est) {
-    estimator->estimate =
-        GPR_MAX(estimator->accumulator, estimator->estimate * 2);
-    estimator->bw_est = bw;
+  GPR_ASSERT(ping_state_ == PingState::STARTED);
+  if (accumulator_ > 2 * estimate_ / 3 && bw > bw_est_) {
+    estimate_ = GPR_MAX(accumulator_, estimate_ * 2);
+    bw_est_ = bw;
     if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-      gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64,
-              estimator->name, estimator->estimate);
+      gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64, name_,
+              estimate_);
     }
-    estimator->inter_ping_delay /= 2;  // if the ping estimate changes,
-                                       // exponentially get faster at probing
-  } else if (estimator->inter_ping_delay < 10000) {
-    estimator->stable_estimate_count++;
-    if (estimator->stable_estimate_count >= 2) {
-      estimator->inter_ping_delay +=
+    inter_ping_delay_ /= 2;  // if the ping estimate changes,
+                             // exponentially get faster at probing
+  } else if (inter_ping_delay_ < 10000) {
+    stable_estimate_count_++;
+    if (stable_estimate_count_ >= 2) {
+      inter_ping_delay_ +=
           100 +
           (int)(rand() * 100.0 / RAND_MAX);  // if the ping estimate is steady,
                                              // slowly ramp down the probe time
     }
   }
-  if (start_inter_ping_delay != estimator->inter_ping_delay) {
-    estimator->stable_estimate_count = 0;
+  if (start_inter_ping_delay != inter_ping_delay_) {
+    stable_estimate_count_ = 0;
     if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
-      gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", estimator->name,
-              estimator->inter_ping_delay);
+      gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", name_,
+              inter_ping_delay_);
     }
   }
-  estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
-  estimator->accumulator = 0;
-  estimator->next_ping_scheduled =
-      grpc_exec_ctx_now(exec_ctx) + estimator->inter_ping_delay;
+  ping_state_ = PingState::UNSCHEDULED;
+  accumulator_ = 0;
+  next_ping_scheduled_ = grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_;
 }
+
+}  // namespace grpc_core
diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h
index a9d9867..6447f2d 100644
--- a/src/core/lib/transport/bdp_estimator.h
+++ b/src/core/lib/transport/bdp_estimator.h
@@ -19,67 +19,97 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
 #define GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
 
-#include <grpc/support/time.h>
+#include <grpc/support/port_platform.h>
+
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stdint.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#define GRPC_BDP_SAMPLES 16
-#define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern grpc_tracer_flag grpc_bdp_estimator_trace;
 
-typedef enum {
-  GRPC_BDP_PING_UNSCHEDULED,
-  GRPC_BDP_PING_SCHEDULED,
-  GRPC_BDP_PING_STARTED
-} grpc_bdp_estimator_ping_state;
+namespace grpc_core {
 
-typedef struct grpc_bdp_estimator {
-  grpc_bdp_estimator_ping_state ping_state;
-  int64_t accumulator;
-  int64_t estimate;
+class BdpEstimator {
+ public:
+  explicit BdpEstimator(const char *name);
+  ~BdpEstimator() {}
+
+  // Returns true if a reasonable estimate could be obtained
+  bool EstimateBdp(int64_t *estimate_out) const {
+    *estimate_out = estimate_;
+    return true;
+  }
+  bool EstimateBandwidth(double *bw_out) const {
+    *bw_out = bw_est_;
+    return true;
+  }
+
+  void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; }
+
+  // Returns true if the user should schedule a ping
+  bool NeedPing(grpc_exec_ctx *exec_ctx) const {
+    switch (ping_state_) {
+      case PingState::UNSCHEDULED:
+        return grpc_exec_ctx_now(exec_ctx) >= next_ping_scheduled_;
+      case PingState::SCHEDULED:
+      case PingState::STARTED:
+        return false;
+    }
+    GPR_UNREACHABLE_CODE(return false);
+  }
+
+  // Schedule a ping: call in response to receiving a true from
+  // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
+  // transport (but not necessarily started)
+  void SchedulePing() {
+    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+      gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64, name_,
+              accumulator_, estimate_);
+    }
+    GPR_ASSERT(ping_state_ == PingState::UNSCHEDULED);
+    ping_state_ = PingState::SCHEDULED;
+    accumulator_ = 0;
+  }
+
+  // Start a ping: call after calling grpc_bdp_estimator_schedule_ping and
+  // once
+  // the ping is on the wire
+  void StartPing() {
+    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+      gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64, name_,
+              accumulator_, estimate_);
+    }
+    GPR_ASSERT(ping_state_ == PingState::SCHEDULED);
+    ping_state_ = PingState::STARTED;
+    accumulator_ = 0;
+    ping_start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
+  }
+
+  // Completes a previously started ping
+  void CompletePing(grpc_exec_ctx *exec_ctx);
+
+ private:
+  enum class PingState { UNSCHEDULED, SCHEDULED, STARTED };
+
+  PingState ping_state_;
+  int64_t accumulator_;
+  int64_t estimate_;
   // when was the current ping started?
-  gpr_timespec ping_start_time;
+  gpr_timespec ping_start_time_;
   // when should the next ping start?
-  grpc_millis next_ping_scheduled;
-  int inter_ping_delay;
-  int stable_estimate_count;
-  double bw_est;
-  const char *name;
-} grpc_bdp_estimator;
+  grpc_millis next_ping_scheduled_;
+  int inter_ping_delay_;
+  int stable_estimate_count_;
+  double bw_est_;
+  const char *name_;
+};
 
-void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name);
-
-// Returns true if a reasonable estimate could be obtained
-bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator,
-                                     int64_t *estimate);
-// Tracks new bytes read.
-bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator, double *bw);
-// Returns true if the user should schedule a ping
-void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
-                                           int64_t num_bytes);
-// Returns true if the user should schedule a ping
-bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
-                                  const grpc_bdp_estimator *estimator);
-// Schedule a ping: call in response to receiving a true from
-// grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
-// transport (but not necessarily started)
-void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator);
-// Start a ping: call after calling grpc_bdp_estimator_schedule_ping and once
-// the ping is on the wire
-void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator);
-// Completes a previously started ping
-void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
-                                      grpc_bdp_estimator *estimator);
-
-#ifdef __cplusplus
-}
-#endif
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H */
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 6bd3ecd..d982a3d 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -266,8 +266,11 @@
 
   WorkStatus PollForWork(void** tag, bool* ok) override {
     *tag = nullptr;
+    // TODO(ctiller): workaround for GPR_TIMESPAN based deadlines not working
+    // right now
     gpr_timespec deadline =
-        gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN);
+        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                     gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN));
 
     switch (server_cq_->AsyncNext(tag, ok, deadline)) {
       case CompletionQueue::TIMEOUT:
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 82ac260..4d887fe 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -18,6 +18,7 @@
 
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
+#import <grpc/grpc.h>
 
 #import <GRPCClient/GRPCCall.h>
 #import <GRPCClient/GRPCCall+ChannelArg.h>
@@ -30,6 +31,8 @@
 #import <RxLibrary/GRXWriter+Immediate.h>
 #import <RxLibrary/GRXBufferedPipe.h>
 
+#import "version.h"
+
 #define TEST_TIMEOUT 16
 
 static NSString * const kHostAddress = @"localhost:5050";
@@ -266,12 +269,38 @@
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
     XCTAssertNotNil(value, @"nil value received as response.");
     XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
-    /* This test needs to be more clever in regards to changing the version of the core.
-    XCTAssertEqualObjects(call.responseHeaders[@"x-grpc-test-echo-useragent"],
-                          @"Foo grpc-objc/0.13.0 grpc-c/0.14.0-dev (ios)",
-                          @"Did not receive expected user agent %@",
-                          call.responseHeaders[@"x-grpc-test-echo-useragent"]);
-    */
+
+    NSString *userAgent = call.responseHeaders[@"x-grpc-test-echo-useragent"];
+    NSError *error = nil;
+
+    // Test the regex is correct
+    NSString *expectedUserAgent = @"Foo grpc-objc/";
+    expectedUserAgent =
+        [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
+    expectedUserAgent =
+        [expectedUserAgent stringByAppendingString:@" grpc-c/"];
+    expectedUserAgent =
+        [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING];
+    expectedUserAgent =
+        [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "];
+    expectedUserAgent =
+        [expectedUserAgent stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]];
+    expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"];
+    XCTAssertEqualObjects(userAgent, expectedUserAgent);
+
+    // Change in format of user-agent field in a direction that does not match the regex will likely
+    // cause problem for certain gRPC users. @muxi for details.
+    NSRegularExpression *regex =
+        [NSRegularExpression regularExpressionWithPattern:@" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?"
+                                                  options:0
+                                                    error:&error];
+    NSString *customUserAgent =
+        [regex stringByReplacingMatchesInString:userAgent
+                                        options:0
+                                          range:NSMakeRange(0, [userAgent length])
+                                   withTemplate:@""];
+    XCTAssertEqualObjects(customUserAgent, @"Foo");
+
     [response fulfill];
   } completionHandler:^(NSError *errorOrNil) {
     XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index b01d5ff..2f0c8cf 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -144,6 +144,7 @@
 		5EAD6D241E27047400002378 /* CronetUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = "<group>"; };
 		5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		5EAFE8271F8EFB87007F2189 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
 		5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteWithCronet.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemoteWithCronet.m; sourceTree = "<group>"; };
 		5EE84BF51D4717E40050C6CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -398,6 +399,7 @@
 		635697C91B14FC11007A7283 /* Tests */ = {
 			isa = PBXGroup;
 			children = (
+				5EAFE8271F8EFB87007F2189 /* version.h */,
 				6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */,
 				63E240CC1B6C4D3A005F3B0E /* InteropTests.h */,
 				635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */,
@@ -740,9 +742,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -755,9 +760,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-frameworks.sh",
+				"${PODS_ROOT}/CronetFramework/Cronet.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -770,13 +778,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-InteropTestsRemote-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		4F5690DC0E6AD6663FE78B8B /* [CP] Embed Pods Frameworks */ = {
@@ -800,13 +811,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalSSL-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		5F14F59509E10C2852014F9E /* [CP] Embed Pods Frameworks */ = {
@@ -830,9 +844,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -845,9 +862,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -860,13 +880,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalCleartext-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		796680C7599CB4ED736DD62A /* [CP] Check Pods Manifest.lock */ = {
@@ -875,13 +898,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		80E2DDD2EC04A4009F45E933 /* [CP] Check Pods Manifest.lock */ = {
@@ -890,13 +916,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-CronetUnitTests-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		8AD3130D3C58A0FB32FF2A36 /* [CP] Copy Pods Resources */ = {
@@ -905,9 +934,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -935,13 +967,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-AllTests-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		A441F71824DCB9D0CA297748 /* [CP] Copy Pods Resources */ = {
@@ -950,9 +985,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -965,9 +1003,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-frameworks.sh",
+				"${PODS_ROOT}/CronetFramework/Cronet.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -995,9 +1036,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1010,13 +1054,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-RxLibraryUnitTests-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */ = {
@@ -1025,13 +1072,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-InteropTestsRemoteWithCronet-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = {
@@ -1040,9 +1090,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1070,9 +1123,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1085,9 +1141,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh",
+				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1100,9 +1159,12 @@
 			files = (
 			);
 			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh",
+				"${PODS_ROOT}/CronetFramework/Cronet.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1115,13 +1177,16 @@
 			files = (
 			);
 			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-CoreCronetEnd2EndTests-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
new file mode 100644
index 0000000..0251506
--- /dev/null
+++ b/src/objective-c/tests/version.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// This file is autogenerated from a template file. Please make
+// modifications to
+// `templates/src/objective-c/GRPCClient/private/version.h.template`
+// instead. This file can be regenerated from the template by running
+// `tools/buildgen/generate_projects.sh`.
+
+
+#define GRPC_OBJC_VERSION_STRING @"1.8.0-dev"
+#define GRPC_C_VERSION_STRING @"5.0.0-dev"
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index e5ab02b..9d2cf2a 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -41,6 +41,7 @@
 ]
 
 windows = RUBY_PLATFORM =~ /mingw|mswin/
+bsd = RUBY_PLATFORM =~ /bsd/
 
 grpc_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
 
@@ -70,7 +71,8 @@
   puts 'Building internal gRPC into ' + grpc_lib_dir
   nproc = 4
   nproc = Etc.nprocessors * 2 if Etc.respond_to? :nprocessors
-  system("make -j#{nproc} -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config} Q=")
+  make = bsd ? 'gmake' : 'make'
+  system("#{make} -j#{nproc} -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config} Q=")
   exit 1 unless $? == 0
 end
 
diff --git a/templates/src/objective-c/tests/version.h.template b/templates/src/objective-c/tests/version.h.template
new file mode 100644
index 0000000..72774ab
--- /dev/null
+++ b/templates/src/objective-c/tests/version.h.template
@@ -0,0 +1,29 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2015 gRPC authors.
+   *
+   * Licensed under the Apache License, Version 2.0 (the "License");
+   * you may not use this file except in compliance with the License.
+   * You may obtain a copy of the License at
+   *
+   *     http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   *
+   */
+
+  // This file is autogenerated from a template file. Please make
+  // modifications to
+  // `templates/src/objective-c/GRPCClient/private/version.h.template`
+  // instead. This file can be regenerated from the template by running
+  // `tools/buildgen/generate_projects.sh`.
+
+
+  #define GRPC_OBJC_VERSION_STRING @"${settings.version}"
+  #define GRPC_C_VERSION_STRING @"${settings.core_version}"
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
index 12e3613..ea5e577 100644
--- a/test/core/transport/BUILD
+++ b/test/core/transport/BUILD
@@ -20,14 +20,17 @@
 
 grpc_cc_test(
     name = "bdp_estimator_test",
-    srcs = ["bdp_estimator_test.c"],
-    language = "C",
+    srcs = ["bdp_estimator_test.cc"],
+    language = "C++",
     deps = [
         "//:gpr",
         "//:grpc",
         "//test/core/util:gpr_test_util",
         "//test/core/util:grpc_test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
 grpc_cc_test(
diff --git a/test/core/transport/bdp_estimator_test.c b/test/core/transport/bdp_estimator_test.c
deleted file mode 100644
index 4912ad5..0000000
--- a/test/core/transport/bdp_estimator_test.c
+++ /dev/null
@@ -1,162 +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/transport/bdp_estimator.h"
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-#include <limits.h>
-#include "src/core/lib/iomgr/timer_manager.h"
-#include "src/core/lib/support/string.h"
-#include "test/core/util/test_config.h"
-
-extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
-
-static int g_clock = 0;
-
-static gpr_timespec fake_gpr_now(gpr_clock_type clock_type) {
-  return (gpr_timespec){
-      .tv_sec = g_clock, .tv_nsec = 0, .clock_type = clock_type,
-  };
-}
-
-static void inc_time(void) { g_clock += 30; }
-
-static void test_noop(void) {
-  gpr_log(GPR_INFO, "test_noop");
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-}
-
-static void test_get_estimate_no_samples(void) {
-  gpr_log(GPR_INFO, "test_get_estimate_no_samples");
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-  int64_t estimate;
-  grpc_bdp_estimator_get_estimate(&est, &estimate);
-}
-
-static void add_samples(grpc_bdp_estimator *estimator, int64_t *samples,
-                        size_t n) {
-  grpc_bdp_estimator_add_incoming_bytes(estimator, 1234567);
-  inc_time();
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == true);
-  grpc_bdp_estimator_schedule_ping(estimator);
-  grpc_bdp_estimator_start_ping(estimator);
-  for (size_t i = 0; i < n; i++) {
-    grpc_bdp_estimator_add_incoming_bytes(estimator, samples[i]);
-    GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == false);
-  }
-  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                               gpr_time_from_millis(1, GPR_TIMESPAN)));
-  grpc_bdp_estimator_complete_ping(&exec_ctx, estimator);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void add_sample(grpc_bdp_estimator *estimator, int64_t sample) {
-  add_samples(estimator, &sample, 1);
-}
-
-static void test_get_estimate_1_sample(void) {
-  gpr_log(GPR_INFO, "test_get_estimate_1_sample");
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-  add_sample(&est, 100);
-  int64_t estimate;
-  grpc_bdp_estimator_get_estimate(&est, &estimate);
-}
-
-static void test_get_estimate_2_samples(void) {
-  gpr_log(GPR_INFO, "test_get_estimate_2_samples");
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-  add_sample(&est, 100);
-  add_sample(&est, 100);
-  int64_t estimate;
-  grpc_bdp_estimator_get_estimate(&est, &estimate);
-}
-
-static int64_t get_estimate(grpc_bdp_estimator *estimator) {
-  int64_t out;
-  GPR_ASSERT(grpc_bdp_estimator_get_estimate(estimator, &out));
-  return out;
-}
-
-static void test_get_estimate_3_samples(void) {
-  gpr_log(GPR_INFO, "test_get_estimate_3_samples");
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-  add_sample(&est, 100);
-  add_sample(&est, 100);
-  add_sample(&est, 100);
-  int64_t estimate;
-  grpc_bdp_estimator_get_estimate(&est, &estimate);
-}
-
-static int64_t next_pow_2(int64_t v) {
-  v--;
-  v |= v >> 1;
-  v |= v >> 2;
-  v |= v >> 4;
-  v |= v >> 8;
-  v |= v >> 16;
-  v |= v >> 32;
-  v++;
-  return v;
-}
-
-static void test_get_estimate_random_values(size_t n) {
-  gpr_log(GPR_INFO, "test_get_estimate_random_values(%" PRIdPTR ")", n);
-  grpc_bdp_estimator est;
-  grpc_bdp_estimator_init(&est, "test");
-  const int kMaxSample = 65535;
-  int min = kMaxSample;
-  int max = 0;
-  for (size_t i = 0; i < n; i++) {
-    int sample = rand() % (kMaxSample + 1);
-    if (sample < min) min = sample;
-    if (sample > max) max = sample;
-    add_sample(&est, sample);
-    if (i >= 3) {
-      gpr_log(GPR_DEBUG, "est:%" PRId64 " min:%d max:%d", get_estimate(&est),
-              min, max);
-      GPR_ASSERT(get_estimate(&est) <= GPR_MAX(65536, 2 * next_pow_2(max)));
-    }
-  }
-}
-
-int main(int argc, char **argv) {
-  grpc_test_init(argc, argv);
-  gpr_now_impl = fake_gpr_now;
-  grpc_init();
-  grpc_timer_manager_set_threading(false);
-  test_noop();
-  test_get_estimate_no_samples();
-  test_get_estimate_1_sample();
-  test_get_estimate_2_samples();
-  test_get_estimate_3_samples();
-  for (size_t i = 3; i < 1000; i = i * 3 / 2) {
-    test_get_estimate_random_values(i);
-  }
-  grpc_shutdown();
-  return 0;
-}
diff --git a/test/core/transport/bdp_estimator_test.cc b/test/core/transport/bdp_estimator_test.cc
new file mode 100644
index 0000000..80cc174
--- /dev/null
+++ b/test/core/transport/bdp_estimator_test.cc
@@ -0,0 +1,160 @@
+/*
+ *
+ * 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/transport/bdp_estimator.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+#include <gtest/gtest.h>
+#include <limits.h>
+#include "src/core/lib/iomgr/timer_manager.h"
+#include "src/core/lib/support/string.h"
+#include "test/core/util/test_config.h"
+
+extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+
+namespace grpc_core {
+namespace testing {
+namespace {
+int g_clock = 0;
+
+gpr_timespec fake_gpr_now(gpr_clock_type clock_type) {
+  gpr_timespec ts;
+  ts.tv_sec = g_clock;
+  ts.tv_nsec = 0;
+  ts.clock_type = clock_type;
+  return ts;
+}
+
+void inc_time(void) { g_clock += 30; }
+}  // namespace
+
+TEST(BdpEstimatorTest, NoOp) { BdpEstimator est("test"); }
+
+TEST(BdpEstimatorTest, EstimateBdpNoSamples) {
+  BdpEstimator est("test");
+  int64_t estimate;
+  est.EstimateBdp(&estimate);
+}
+
+namespace {
+void AddSamples(BdpEstimator *estimator, int64_t *samples, size_t n) {
+  estimator->AddIncomingBytes(1234567);
+  inc_time();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  EXPECT_TRUE(estimator->NeedPing(&exec_ctx));
+  estimator->SchedulePing();
+  estimator->StartPing();
+  for (size_t i = 0; i < n; i++) {
+    estimator->AddIncomingBytes(samples[i]);
+    EXPECT_FALSE(estimator->NeedPing(&exec_ctx));
+  }
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_millis(1, GPR_TIMESPAN)));
+  grpc_exec_ctx_invalidate_now(&exec_ctx);
+  estimator->CompletePing(&exec_ctx);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void AddSample(BdpEstimator *estimator, int64_t sample) {
+  AddSamples(estimator, &sample, 1);
+}
+}  // namespace
+
+TEST(BdpEstimatorTest, GetEstimate1Sample) {
+  BdpEstimator est("test");
+  AddSample(&est, 100);
+  int64_t estimate;
+  est.EstimateBdp(&estimate);
+}
+
+TEST(BdpEstimatorTest, GetEstimate2Samples) {
+  BdpEstimator est("test");
+  AddSample(&est, 100);
+  AddSample(&est, 100);
+  int64_t estimate;
+  est.EstimateBdp(&estimate);
+}
+
+TEST(BdpEstimatorTest, GetEstimate3Samples) {
+  BdpEstimator est("test");
+  AddSample(&est, 100);
+  AddSample(&est, 100);
+  AddSample(&est, 100);
+  int64_t estimate;
+  est.EstimateBdp(&estimate);
+}
+
+namespace {
+static int64_t GetEstimate(const BdpEstimator &estimator) {
+  int64_t out;
+  EXPECT_TRUE(estimator.EstimateBdp(&out));
+  return out;
+}
+
+int64_t NextPow2(int64_t v) {
+  v--;
+  v |= v >> 1;
+  v |= v >> 2;
+  v |= v >> 4;
+  v |= v >> 8;
+  v |= v >> 16;
+  v |= v >> 32;
+  v++;
+  return v;
+}
+}  // namespace
+
+class BdpEstimatorRandomTest : public ::testing::TestWithParam<size_t> {};
+
+TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) {
+  BdpEstimator est("test");
+  const int kMaxSample = 65535;
+  int min = kMaxSample;
+  int max = 0;
+  for (size_t i = 0; i < GetParam(); i++) {
+    int sample = rand() % (kMaxSample + 1);
+    if (sample < min) min = sample;
+    if (sample > max) max = sample;
+    AddSample(&est, sample);
+    if (i >= 3) {
+      EXPECT_LE(GetEstimate(est), GPR_MAX(65536, 2 * NextPow2(max)))
+          << " min:" << min << " max:" << max << " sample:" << sample;
+    }
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest,
+                        ::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94,
+                                          141, 211, 316, 474, 711));
+}  // namespace testing
+}  // namespace grpc_core
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  gpr_now_impl = grpc_core::testing::fake_gpr_now;
+  grpc_init();
+  grpc_timer_manager_set_threading(false);
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index abb50a0..5844a17 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -32,9 +32,22 @@
 )
 
 grpc_cc_library(
+    name = "grpc_debugger_macros",
+    srcs = [
+        "debugger_macros.cc",
+    ],
+    hdrs = [
+        "debugger_macros.h",
+    ],
+    deps = [
+        ":gpr_test_util",
+        "//:grpc_common",
+    ],
+)
+
+grpc_cc_library(
     name = "grpc_test_util_base",
     srcs = [
-        "debugger_macros.c",
         "grpc_profiler.c",
         "mock_endpoint.c",
         "parse_hexstring.c",
@@ -47,7 +60,6 @@
         "trickle_endpoint.c",
     ],
     hdrs = [
-        "debugger_macros.h",
         "grpc_profiler.h",
         "mock_endpoint.h",
         "parse_hexstring.h",
@@ -63,6 +75,7 @@
     deps = [
         ":gpr_test_util",
         "//:grpc_common",
+        ":grpc_debugger_macros"
     ],
 )
 
diff --git a/test/core/util/debugger_macros.c b/test/core/util/debugger_macros.cc
similarity index 96%
rename from test/core/util/debugger_macros.c
rename to test/core/util/debugger_macros.cc
index ebe74f1..72384f2 100644
--- a/test/core/util/debugger_macros.c
+++ b/test/core/util/debugger_macros.cc
@@ -29,7 +29,7 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/surface/call.h"
 
-void grpc_summon_debugger_macros() {}
+extern "C" void grpc_summon_debugger_macros() {}
 
 grpc_stream *grpc_transport_stream_from_call(grpc_call *call) {
   grpc_call_stack *cs = grpc_call_get_call_stack(call);
diff --git a/test/core/util/debugger_macros.h b/test/core/util/debugger_macros.h
index c6b3720..24718d9 100644
--- a/test/core/util/debugger_macros.h
+++ b/test/core/util/debugger_macros.h
@@ -19,6 +19,14 @@
 #ifndef GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
 #define GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif /*  __cplusplus */
+
 void grpc_summon_debugger_macros();
 
+#ifdef __cplusplus
+}
+#endif /*  __cplusplus */
+
 #endif /* GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H */
diff --git a/test/core/util/trickle_endpoint.h b/test/core/util/trickle_endpoint.h
index 78f1eee..ca39638 100644
--- a/test/core/util/trickle_endpoint.h
+++ b/test/core/util/trickle_endpoint.h
@@ -21,6 +21,10 @@
 
 #include "src/core/lib/iomgr/endpoint.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
 grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap,
                                             double bytes_per_second);
 
@@ -30,4 +34,8 @@
 
 size_t grpc_trickle_get_backlog(grpc_endpoint *endpoint);
 
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
 #endif
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index 6f9dee7..8ee3ae7 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -26,14 +26,12 @@
 #include <memory>
 #include <queue>
 #include <sstream>
-extern "C" {
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/resource_quota.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/static_metadata.h"
-}
 #include "test/cpp/microbenchmarks/helpers.h"
 #include "third_party/benchmark/include/benchmark/benchmark.h"
 
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
index adb5e66..06ae342 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -21,17 +21,15 @@
 #include <benchmark/benchmark.h>
 #include <gflags/gflags.h>
 #include <fstream>
-#include "src/core/lib/profiling/timers.h"
-#include "src/proto/grpc/testing/echo.grpc.pb.h"
-#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
-#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
-#include "test/cpp/util/test_config.h"
-extern "C" {
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/iomgr/timer_manager.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/trickle_endpoint.h"
-}
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+#include "test/cpp/util/test_config.h"
 
 DEFINE_bool(log, false, "Log state to CSV files");
 DEFINE_int32(
diff --git a/third_party/cares/config_openbsd/ares_config.h b/third_party/cares/config_openbsd/ares_config.h
new file mode 100644
index 0000000..3b3320d
--- /dev/null
+++ b/third_party/cares/config_openbsd/ares_config.h
@@ -0,0 +1,502 @@
+/* ares_config.h.  Generated from ares_config.h.in by configure.  */
+/* ares_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* define this if ares is built for a big endian system */
+/* #undef ARES_BIG_ENDIAN */
+
+/* when building as static part of libcurl */
+/* #undef BUILDING_LIBCURL */
+
+/* Defined for build that exposes internal static functions for testing. */
+/* #undef CARES_EXPOSE_STATICS */
+
+/* Defined for build with symbol hiding. */
+#define CARES_SYMBOL_HIDING 1
+
+/* Definition to make a library symbol externally visible. */
+#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((__visibility__ ("default")))
+
+/* the signed version of size_t */
+#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
+
+/* Use resolver library to configure cares */
+/* #undef CARES_USE_LIBRESOLV */
+
+/* if a /etc/inet dir is being used */
+/* #undef ETC_INET */
+
+/* Define to the type of arg 2 for gethostname. */
+#define GETHOSTNAME_TYPE_ARG2 size_t
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 4
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE sizeof(struct servent_data)
+
+/* Define to 1 if you have AF_INET6. */
+#define HAVE_AF_INET6 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/nameser_compat.h> header file. */
+/* #undef HAVE_ARPA_NAMESER_COMPAT_H */
+
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#define HAVE_ARPA_NAMESER_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `bitncmp' function. */
+/* #undef HAVE_BITNCMP */
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the closesocket function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+/* #undef HAVE_CLOSESOCKET_CAMEL */
+
+/* Define to 1 if you have the connect function. */
+#define HAVE_CONNECT 1
+
+/* define if the compiler supports basic C++11 syntax */
+/* #undef HAVE_CXX11 */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+/* #undef HAVE_GETADDRINFO_THREADSAFE */
+
+/* Define to 1 if you have the getenv function. */
+#define HAVE_GETENV 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#define HAVE_IF_INDEXTONAME 1
+
+/* Define to 1 if you have a IPv6 capable working inet_net_pton function. */
+/* #undef HAVE_INET_NET_PTON */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the memory.h header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have PF_INET6. */
+#define HAVE_PF_INET6 1
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <socket.h> header file. */
+/* #undef HAVE_SOCKET_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have struct addrinfo. */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if you have struct in6_addr. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have struct sockaddr_in6. */
+#define HAVE_STRUCT_SOCKADDR_IN6 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+/* #undef NEED_MEMORY_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* cpu-machine-OS */
+#define OS "x86_64-unknown-openbsd6.2"
+
+/* Name of package */
+#define PACKAGE "c-ares"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "c-ares mailing list: http://cool.haxx.se/mailman/listinfo/c-ares"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "c-ares"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "c-ares 1.13.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "c-ares"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.13.0"
+
+/* a suitable file/device to read random data from */
+#define RANDOM_FILE "/dev/urandom"
+
+/* Define to the type qualifier pointed by arg 5 for recvfrom. */
+#define RECVFROM_QUAL_ARG5 
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* Version number of package */
+#define VERSION "1.13.0"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 0f7e8cd..bcf91e7 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1031,6 +1031,7 @@
 src/core/lib/support/atomic_with_atm.h \
 src/core/lib/support/atomic_with_std.h \
 src/core/lib/support/env.h \
+src/core/lib/support/manual_constructor.h \
 src/core/lib/support/memory.h \
 src/core/lib/support/mpscq.h \
 src/core/lib/support/murmur_hash.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index f89cbf0..8435178 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1321,6 +1321,7 @@
 src/core/lib/support/log_linux.cc \
 src/core/lib/support/log_posix.cc \
 src/core/lib/support/log_windows.cc \
+src/core/lib/support/manual_constructor.h \
 src/core/lib/support/memory.h \
 src/core/lib/support/mpscq.cc \
 src/core/lib/support/mpscq.h \
diff --git a/tools/internal_ci/linux/grpc_interop_matrix.sh b/tools/internal_ci/linux/grpc_interop_matrix.sh
index e199d48..6a9c387 100755
--- a/tools/internal_ci/linux/grpc_interop_matrix.sh
+++ b/tools/internal_ci/linux/grpc_interop_matrix.sh
@@ -22,4 +22,4 @@
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
-tools/interop_matrix/run_interop_matrix_tests.py --language=all --release=all --report_file=sponge_log.xml $@
+tools/interop_matrix/run_interop_matrix_tests.py --language=all --release=all --report_file=sponge_log.xml --bq_result_table interop_results $@
diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py
index 48c918d..d037e13 100755
--- a/tools/interop_matrix/run_interop_matrix_tests.py
+++ b/tools/interop_matrix/run_interop_matrix_tests.py
@@ -36,6 +36,7 @@
 import dockerjob
 import jobset
 import report_utils
+import upload_test_results
 
 _LANGUAGES = client_matrix.LANG_RUNTIME_MATRIX.keys()
 # All gRPC release tags, flattened, deduped and sorted.
@@ -74,6 +75,11 @@
                   const=True,
                   help=('Allow flaky tests to show as passing (re-runs failed '
                         'tests up to five times)'))
+argp.add_argument('--bq_result_table',
+                  default='',
+                  type=str,
+                  nargs='?',
+                  help='Upload test results to a specified BQ table.')
 
 args = argp.parse_args()
 
@@ -117,7 +123,7 @@
 
 # caches test cases (list of JobSpec) loaded from file.  Keyed by lang and runtime.
 _loaded_testcases = {}
-def find_test_cases(lang, release):
+def find_test_cases(lang, release, suite_name):
   """Returns the list of test cases from testcase files per lang/release."""
   file_tmpl = os.path.join(os.path.dirname(__file__), 'testcases/%s__%s')
   if not os.path.exists(file_tmpl % (lang, release)):
@@ -134,8 +140,12 @@
         if line.startswith('docker run'):
           m = re.search('--test_case=(.*)"', line)
           shortname = m.group(1) if m else 'unknown_test'
+          m = re.search('--server_host_override=(.*).sandbox.googleapis.com', 
+                        line)
+          server = m.group(1) if m else 'unknown_server'
           spec = jobset.JobSpec(cmdline=line,
-                                shortname=shortname,
+                                shortname='%s:%s:%s:%s' % (suite_name, lang, 
+                                                           server, shortname),
                                 timeout_seconds=_TEST_TIMEOUT,
                                 shell=True,
                                 flake_retries=5 if args.allow_flakes else 0)
@@ -163,11 +173,15 @@
     # Download the docker image before running each test case.
     subprocess.check_call(['gcloud', 'docker', '--', 'pull', image])
     _docker_images_cleanup.append(image)
-    job_spec_list = find_test_cases(lang,release)
+    suite_name = '%s__%s_%s' % (lang, runtime, release)
+    job_spec_list = find_test_cases(lang, release, suite_name)
     num_failures, resultset = jobset.run(job_spec_list,
                                          newline_on_success=True,
                                          add_env={'docker_image':image},
                                          maxjobs=args.jobs)
+    if args.bq_result_table and resultset:
+      upload_test_results.upload_interop_results_to_bq(
+          resultset, args.bq_result_table, args)
     if num_failures:
       jobset.message('FAILED', 'Some tests failed', do_newline=True)
       total_num_failures += num_failures
@@ -178,7 +192,7 @@
         _xml_report_tree,
         resultset,
         'grpc_interop_matrix',
-        '%s__%s %s'%(lang,runtime,release),
+        suite_name,
         str(uuid.uuid4()))
   
   return total_num_failures
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 21b3bef..2e18ed2 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -136,23 +136,6 @@
   }, 
   {
     "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
-    "name": "bdp_estimator_test", 
-    "src": [
-      "test/core/transport/bdp_estimator_test.c"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
       "grpc", 
       "grpc_test_util"
     ], 
@@ -2615,6 +2598,25 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "bdp_estimator_test", 
+    "src": [
+      "test/core/transport/bdp_estimator_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "benchmark", 
       "gpr", 
       "gpr_test_util", 
@@ -7483,7 +7485,9 @@
       "third_party/cares/cares/config-win32.h", 
       "third_party/cares/cares/setup_once.h", 
       "third_party/cares/config_darwin/ares_config.h", 
-      "third_party/cares/config_linux/ares_config.h"
+      "third_party/cares/config_freebsd/ares_config.h", 
+      "third_party/cares/config_linux/ares_config.h", 
+      "third_party/cares/config_openbsd/ares_config.h"
     ], 
     "is_filegroup": false, 
     "language": "c", 
@@ -7860,6 +7864,7 @@
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
       "src/core/lib/support/env.h", 
+      "src/core/lib/support/manual_constructor.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.h", 
@@ -7907,6 +7912,7 @@
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
       "src/core/lib/support/env.h", 
+      "src/core/lib/support/manual_constructor.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.h", 
@@ -8932,7 +8938,7 @@
       "test/core/end2end/fixtures/proxy.h", 
       "test/core/iomgr/endpoint_tests.c", 
       "test/core/iomgr/endpoint_tests.h", 
-      "test/core/util/debugger_macros.c", 
+      "test/core/util/debugger_macros.cc", 
       "test/core/util/debugger_macros.h", 
       "test/core/util/grpc_profiler.c", 
       "test/core/util/grpc_profiler.h", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index a1644df..8cd3f90 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -45,7 +45,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -68,7 +68,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -114,7 +114,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -137,7 +137,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -178,29 +178,6 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "bdp_estimator_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": true
-  }, 
-  {
-    "args": [], 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
     "name": "bin_decoder_test", 
     "platforms": [
       "linux", 
@@ -208,7 +185,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -231,7 +208,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -254,7 +231,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -277,7 +254,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -300,7 +277,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -323,7 +300,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -346,7 +323,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -392,7 +369,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -415,7 +392,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -438,7 +415,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -484,7 +461,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -651,7 +628,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -848,7 +825,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -871,7 +848,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -894,7 +871,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -917,7 +894,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -940,7 +917,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -963,7 +940,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -986,7 +963,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1032,7 +1009,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1055,7 +1032,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1078,7 +1055,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1101,7 +1078,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1124,7 +1101,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1147,7 +1124,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1170,7 +1147,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1193,7 +1170,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1216,7 +1193,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1239,7 +1216,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1262,7 +1239,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1285,7 +1262,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1331,7 +1308,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1425,7 +1402,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1446,7 +1423,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1469,7 +1446,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1553,7 +1530,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1576,7 +1553,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1599,7 +1576,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1683,7 +1660,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1729,7 +1706,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1752,7 +1729,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1775,7 +1752,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1821,7 +1798,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1865,7 +1842,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1888,7 +1865,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1911,7 +1888,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -1957,7 +1934,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2028,7 +2005,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2051,7 +2028,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2281,7 +2258,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2304,7 +2281,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2327,7 +2304,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2350,7 +2327,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2463,7 +2440,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2486,7 +2463,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2509,7 +2486,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2651,7 +2628,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2674,7 +2651,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2699,7 +2676,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2724,7 +2701,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2770,7 +2747,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2793,7 +2770,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -2952,7 +2929,30 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "bdp_estimator_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -2975,7 +2975,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -2998,7 +2998,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -3021,7 +3021,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -3136,7 +3136,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -3271,7 +3271,7 @@
       "mac", 
       "posix"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [
@@ -3317,7 +3317,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3340,7 +3340,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3434,7 +3434,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3457,7 +3457,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3503,7 +3503,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3526,7 +3526,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3549,7 +3549,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3572,7 +3572,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3689,7 +3689,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3902,7 +3902,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -3994,7 +3994,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -4218,7 +4218,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -4241,7 +4241,7 @@
       "posix", 
       "windows"
     ], 
-    "uses_polling": true
+    "uses_polling": false
   }, 
   {
     "args": [], 
@@ -48366,6 +48366,31 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 16, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 16, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 50, \"req_size\": 300}}, \"client_channels\": 300, \"threads_per_cq\": 0, \"load_params\": {\"poisson\": {\"offered_load\": 37500}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp", 
+    "timeout_seconds": 120
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -50150,6 +50175,44 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 16, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 16, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 50, \"req_size\": 300}}, \"client_channels\": 300, \"threads_per_cq\": 0, \"load_params\": {\"poisson\": {\"offered_load\": 37500}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp_low_thread_count", 
+    "timeout_seconds": 120
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
diff --git a/tools/run_tests/performance/massage_qps_stats.py b/tools/run_tests/performance/massage_qps_stats.py
index e0b6ce6..48c5758 100644
--- a/tools/run_tests/performance/massage_qps_stats.py
+++ b/tools/run_tests/performance/massage_qps_stats.py
@@ -101,6 +101,10 @@
     stats["core_combiner_locks_scheduled_items"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_scheduled_items")
     stats["core_combiner_locks_scheduled_final_items"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_scheduled_final_items")
     stats["core_combiner_locks_offloaded"] = massage_qps_stats_helpers.counter(core_stats, "combiner_locks_offloaded")
+    stats["core_call_combiner_locks_initiated"] = massage_qps_stats_helpers.counter(core_stats, "call_combiner_locks_initiated")
+    stats["core_call_combiner_locks_scheduled_items"] = massage_qps_stats_helpers.counter(core_stats, "call_combiner_locks_scheduled_items")
+    stats["core_call_combiner_set_notify_on_cancel"] = massage_qps_stats_helpers.counter(core_stats, "call_combiner_set_notify_on_cancel")
+    stats["core_call_combiner_cancelled"] = massage_qps_stats_helpers.counter(core_stats, "call_combiner_cancelled")
     stats["core_executor_scheduled_short_items"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_short_items")
     stats["core_executor_scheduled_long_items"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_long_items")
     stats["core_executor_scheduled_to_self"] = massage_qps_stats_helpers.counter(core_stats, "executor_scheduled_to_self")
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 8f01eb4..64af6a6 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -82,6 +82,16 @@
         r['simple_params'] = sizes
     return r
 
+def _load_params(offered_load):
+    r = {}
+    if offered_load is None:
+        r['closed_loop'] = {}
+    else:
+        load = {}
+        load['offered_load'] = offered_load
+        r['poisson'] = load
+    return r
+
 def _add_channel_arg(config, key, value):
   if 'channel_args' in config:
     channel_args = config['channel_args']
@@ -115,7 +125,8 @@
                         resource_quota_size=None,
                         messages_per_stream=None,
                         excluded_poll_engines=[],
-                        minimal_stack=False):
+                        minimal_stack=False,
+                        offered_load=None):
   """Creates a basic ping pong scenario."""
   scenario = {
     'name': name,
@@ -129,9 +140,6 @@
       'async_client_threads': 1,
       'threads_per_cq': client_threads_per_cq,
       'rpc_type': rpc_type,
-      'load_params': {
-        'closed_loop': {}
-      },
       'histogram_params': HISTOGRAM_PARAMS,
       'channel_args': [],
     },
@@ -171,12 +179,16 @@
     scenario['client_config']['outstanding_rpcs_per_channel'] = deep
     scenario['client_config']['client_channels'] = wide
     scenario['client_config']['async_client_threads'] = 0
+    if offered_load is not None:
+        optimization_target = 'latency'
   else:
     scenario['client_config']['outstanding_rpcs_per_channel'] = 1
     scenario['client_config']['client_channels'] = 1
     scenario['client_config']['async_client_threads'] = 1
     optimization_target = 'latency'
 
+  scenario['client_config']['load_params'] = _load_params(offered_load)
+
   optimization_channel_arg = {
     'name': 'grpc.optimization_target',
     'str_value': optimization_target
@@ -235,6 +247,15 @@
       secure=False,
       categories=[SMOKETEST] + [SCALABLE])
 
+    yield _ping_pong_scenario(
+       'cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp',
+       rpc_type='UNARY', client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+       req_size=300, resp_size=50,
+       unconstrained_client='async', outstanding=30000, channels=300,
+       offered_load=37500, secure=False,
+       async_server_threads=16, server_threads_per_cq=16,
+       categories=[SMOKETEST] + [SCALABLE])
+
     for secure in [True, False]:
       secstr = 'secure' if secure else 'insecure'
       smoketest_categories = ([SMOKETEST] if secure else []) + [SCALABLE]
@@ -809,7 +830,7 @@
 
   def worker_cmdline(self):
     if self.php7_protobuf_c:
-        return ['tools/run_tests/performance/run_worker_php.sh --use_protobuf_c_extension']
+        return ['tools/run_tests/performance/run_worker_php.sh', '--use_protobuf_c_extension']
     return ['tools/run_tests/performance/run_worker_php.sh']
 
   def worker_port_offset(self):
@@ -821,7 +842,7 @@
     php7_extension_mode='php7_protobuf_php_extension'
     if self.php7_protobuf_c:
         php7_extension_mode='php7_protobuf_c_extension'
-    
+
     yield _ping_pong_scenario(
         '%s_to_cpp_protobuf_sync_unary_ping_pong' % php7_extension_mode,
         rpc_type='UNARY', client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
diff --git a/tools/run_tests/performance/scenario_result_schema.json b/tools/run_tests/performance/scenario_result_schema.json
index f11e635..b00c2ee 100644
--- a/tools/run_tests/performance/scenario_result_schema.json
+++ b/tools/run_tests/performance/scenario_result_schema.json
@@ -517,6 +517,26 @@
       }, 
       {
         "mode": "NULLABLE", 
+        "name": "core_call_combiner_locks_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_locks_scheduled_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_set_notify_on_cancel", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_cancelled", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
         "name": "core_executor_scheduled_short_items", 
         "type": "INTEGER"
       }, 
@@ -1329,6 +1349,26 @@
       }, 
       {
         "mode": "NULLABLE", 
+        "name": "core_call_combiner_locks_initiated", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_locks_scheduled_items", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_set_notify_on_cancel", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
+        "name": "core_call_combiner_cancelled", 
+        "type": "INTEGER"
+      }, 
+      {
+        "mode": "NULLABLE", 
         "name": "core_executor_scheduled_short_items", 
         "type": "INTEGER"
       }, 
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 192f8e7..4dd9827 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -677,7 +677,7 @@
           cmdline=cmdline,
           cwd=cwd,
           environ=environ,
-          shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
+          shortname='%s:%s:%s:%s' % (suite_name, language, server_host_name,
                                      test_case),
           timeout_seconds=_TEST_TIMEOUT,
           flake_retries=5 if args.allow_flakes else 0,