diff options
author | Craig Tiller <ctiller@google.com> | 2017-02-04 19:46:06 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-04 19:46:06 -0800 |
commit | 7ed3c932c968a77114691550e750b91d7231a385 (patch) | |
tree | 6b6437307696afd38b2d0a04a755db729125b7ba | |
parent | cf7587e066fe777ee87dad40faee5d211931932f (diff) | |
parent | 1bb53718bf2f831585f87483c359ac039f1d1f84 (diff) |
Merge pull request #9511 from ctiller/assert_writes
Add a test verifying number of writes per RPC is reasonable
53 files changed, 1855 insertions, 279 deletions
@@ -526,6 +526,7 @@ grpc_cc_library( "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/pid_controller.c", + "src/core/lib/transport/bdp_estimator.c", "src/core/lib/transport/service_config.c", "src/core/lib/transport/static_metadata.c", "src/core/lib/transport/status_conversion.c", @@ -633,6 +634,7 @@ grpc_cc_library( "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/pid_controller.h", + "src/core/lib/transport/bdp_estimator.h", "src/core/lib/transport/service_config.h", "src/core/lib/transport/static_metadata.h", "src/core/lib/transport/status_conversion.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b320db1b3..d52e199842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -333,6 +333,7 @@ add_dependencies(buildtests_c algorithm_test) add_dependencies(buildtests_c alloc_test) add_dependencies(buildtests_c alpn_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 census_context_test) @@ -639,6 +640,9 @@ endif() add_dependencies(buildtests_cxx stress_test) add_dependencies(buildtests_cxx thread_manager_test) add_dependencies(buildtests_cxx thread_stress_test) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) +add_dependencies(buildtests_cxx writes_per_rpc_test) +endif() add_custom_target(buildtests DEPENDS buildtests_c buildtests_cxx) @@ -897,6 +901,7 @@ add_library(grpc src/core/lib/surface/server.c src/core/lib/surface/validate_metadata.c src/core/lib/surface/version.c + src/core/lib/transport/bdp_estimator.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c src/core/lib/transport/error_utils.c @@ -1191,6 +1196,7 @@ add_library(grpc_cronet src/core/lib/surface/server.c src/core/lib/surface/validate_metadata.c src/core/lib/surface/version.c + src/core/lib/transport/bdp_estimator.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c src/core/lib/transport/error_utils.c @@ -1476,6 +1482,7 @@ add_library(grpc_test_util src/core/lib/surface/server.c src/core/lib/surface/validate_metadata.c src/core/lib/surface/version.c + src/core/lib/transport/bdp_estimator.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c src/core/lib/transport/error_utils.c @@ -1699,6 +1706,7 @@ add_library(grpc_unsecure src/core/lib/surface/server.c src/core/lib/surface/validate_metadata.c src/core/lib/surface/version.c + src/core/lib/transport/bdp_estimator.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c src/core/lib/transport/error_utils.c @@ -2244,6 +2252,7 @@ add_library(grpc++_cronet src/core/lib/surface/server.c src/core/lib/surface/validate_metadata.c src/core/lib/surface/version.c + src/core/lib/transport/bdp_estimator.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c src/core/lib/transport/error_utils.c @@ -3705,6 +3714,33 @@ target_link_libraries(bad_server_response_test 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 ${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 ) @@ -9209,6 +9245,43 @@ target_link_libraries(thread_stress_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + +add_executable(writes_per_rpc_test + test/cpp/performance/writes_per_rpc_test.cc + third_party/googletest/src/gtest-all.cc +) + + +target_include_directories(writes_per_rpc_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 ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include + PRIVATE third_party/googletest/include + PRIVATE third_party/googletest + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(writes_per_rpc_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_util + grpc_test_util + grpc++ + grpc + gpr_test_util + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + +endif() +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) add_executable(public_headers_must_be_c89 test/core/surface/public_headers_must_be_c89.c @@ -899,6 +899,7 @@ alloc_test: $(BINDIR)/$(CONFIG)/alloc_test alpn_test: $(BINDIR)/$(CONFIG)/alpn_test api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer 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 census_context_test: $(BINDIR)/$(CONFIG)/census_context_test @@ -1090,6 +1091,7 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test stress_test: $(BINDIR)/$(CONFIG)/stress_test thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test +writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test boringssl_asn1_test: $(BINDIR)/$(CONFIG)/boringssl_asn1_test @@ -1259,6 +1261,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/alloc_test \ $(BINDIR)/$(CONFIG)/alpn_test \ $(BINDIR)/$(CONFIG)/bad_server_response_test \ + $(BINDIR)/$(CONFIG)/bdp_estimator_test \ $(BINDIR)/$(CONFIG)/bin_decoder_test \ $(BINDIR)/$(CONFIG)/bin_encoder_test \ $(BINDIR)/$(CONFIG)/census_context_test \ @@ -1485,6 +1488,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/boringssl_aes_test \ $(BINDIR)/$(CONFIG)/boringssl_asn1_test \ $(BINDIR)/$(CONFIG)/boringssl_base64_test \ @@ -1587,6 +1591,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ endif @@ -1606,6 +1611,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_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" @@ -1918,6 +1925,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 ) $(E) "[RUN] Testing thread_stress_test" $(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 ) + $(E) "[RUN] Testing writes_per_rpc_test" + $(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 ) flaky_test_cxx: buildtests_cxx @@ -2729,6 +2738,7 @@ LIBGRPC_SRC = \ src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ @@ -3037,6 +3047,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ @@ -3336,6 +3347,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ @@ -3561,6 +3573,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ @@ -4152,6 +4165,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ @@ -7967,6 +7981,38 @@ endif 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 \ @@ -14727,6 +14773,49 @@ endif endif +WRITES_PER_RPC_TEST_SRC = \ + test/cpp/performance/writes_per_rpc_test.cc \ + +WRITES_PER_RPC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WRITES_PER_RPC_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/writes_per_rpc_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)/writes_per_rpc_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/writes_per_rpc_test: $(PROTOBUF_DEP) $(WRITES_PER_RPC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(WRITES_PER_RPC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/writes_per_rpc_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/performance/writes_per_rpc_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_writes_per_rpc_test: $(WRITES_PER_RPC_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(WRITES_PER_RPC_TEST_OBJS:.o=.dep) +endif +endif + + PUBLIC_HEADERS_MUST_BE_C89_SRC = \ test/core/surface/public_headers_must_be_c89.c \ diff --git a/binding.gyp b/binding.gyp index fe9c425bff..1815a5a476 100644 --- a/binding.gyp +++ b/binding.gyp @@ -707,6 +707,7 @@ 'src/core/lib/surface/server.c', 'src/core/lib/surface/validate_metadata.c', 'src/core/lib/surface/version.c', + 'src/core/lib/transport/bdp_estimator.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', 'src/core/lib/transport/error_utils.c', diff --git a/build.yaml b/build.yaml index 3cec9c5bd2..456db28cef 100644 --- a/build.yaml +++ b/build.yaml @@ -256,6 +256,7 @@ filegroups: - src/core/lib/surface/lame_client.h - src/core/lib/surface/server.h - src/core/lib/surface/validate_metadata.h + - src/core/lib/transport/bdp_estimator.h - src/core/lib/transport/byte_stream.h - src/core/lib/transport/connectivity_state.h - src/core/lib/transport/error_utils.h @@ -375,6 +376,7 @@ filegroups: - src/core/lib/surface/server.c - src/core/lib/surface/validate_metadata.c - src/core/lib/surface/version.c + - src/core/lib/transport/bdp_estimator.c - src/core/lib/transport/byte_stream.c - src/core/lib/transport/connectivity_state.c - src/core/lib/transport/error_utils.c @@ -1442,6 +1444,16 @@ targets: - 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 @@ -2945,6 +2957,8 @@ targets: - grpc - gpr_test_util - gpr + args: + - --benchmark_min_time=0 platforms: - mac - linux @@ -3727,6 +3741,24 @@ targets: - grpc - gpr_test_util - gpr +- name: writes_per_rpc_test + gtest: true + cpu_cost: 0.5 + build: test + language: c++ + src: + - test/cpp/performance/writes_per_rpc_test.cc + deps: + - grpc++_test_util + - grpc_test_util + - grpc++ + - grpc + - gpr_test_util + - gpr + platforms: + - mac + - linux + - posix - name: public_headers_must_be_c89 build: test language: c89 @@ -186,6 +186,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/surface/server.c \ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ + src/core/lib/transport/bdp_estimator.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ src/core/lib/transport/error_utils.c \ diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 2c83972aa1..a380673233 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -35,6 +35,7 @@ some configuration as environment variables that can be set. A comma separated list of tracers that provide additional insight into how gRPC C core is processing requests via debug logs. Available tracers include: - api - traces api calls to the C core + - bdp_estimator - traces behavior of bdp estimation logic - call_error - traces the possible errors contributing to final call status - channel - traces operations on the C core channel stack - combiner - traces combiner lock state diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 39e0c340ea..87471ab9d0 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -342,6 +342,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/server.h', 'src/core/lib/surface/validate_metadata.h', + 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', 'src/core/lib/transport/error_utils.h', @@ -544,6 +545,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/server.c', 'src/core/lib/surface/validate_metadata.c', 'src/core/lib/surface/version.c', + 'src/core/lib/transport/bdp_estimator.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', 'src/core/lib/transport/error_utils.c', @@ -765,6 +767,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/server.h', 'src/core/lib/surface/validate_metadata.h', + 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', 'src/core/lib/transport/error_utils.h', diff --git a/grpc.gemspec b/grpc.gemspec index 874af6be41..7b132686c8 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -259,6 +259,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/lame_client.h ) s.files += %w( src/core/lib/surface/server.h ) s.files += %w( src/core/lib/surface/validate_metadata.h ) + s.files += %w( src/core/lib/transport/bdp_estimator.h ) s.files += %w( src/core/lib/transport/byte_stream.h ) s.files += %w( src/core/lib/transport/connectivity_state.h ) s.files += %w( src/core/lib/transport/error_utils.h ) @@ -461,6 +462,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/server.c ) s.files += %w( src/core/lib/surface/validate_metadata.c ) s.files += %w( src/core/lib/surface/version.c ) + s.files += %w( src/core/lib/transport/bdp_estimator.c ) s.files += %w( src/core/lib/transport/byte_stream.c ) s.files += %w( src/core/lib/transport/connectivity_state.c ) s.files += %w( src/core/lib/transport/error_utils.c ) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 442c40069e..7fbaf56e75 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -179,6 +179,15 @@ typedef struct { Larger values give lower CPU usage for large messages, but more head of line blocking for small messages. */ #define GRPC_ARG_HTTP2_MAX_FRAME_SIZE "grpc.http2.max_frame_size" +/** Minimum time (in milliseconds) between successive ping frames being sent */ +#define GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS \ + "grpc.http2.min_time_between_pings_ms" +/** How many pings can we send before needing to send a data frame or header + frame? + (0 indicates that an infinite number of pings can be sent without sending + a data frame or header frame) */ +#define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \ + "grpc.http2.max_pings_without_data" /** How much data are we willing to queue up per stream if GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */ #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" diff --git a/package.xml b/package.xml index 68536c3de2..e4c0e83cc7 100644 --- a/package.xml +++ b/package.xml @@ -268,6 +268,7 @@ <file baseinstalldir="/" name="src/core/lib/surface/lame_client.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/server.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/validate_metadata.h" role="src" /> + <file baseinstalldir="/" name="src/core/lib/transport/bdp_estimator.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/byte_stream.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/error_utils.h" role="src" /> @@ -470,6 +471,7 @@ <file baseinstalldir="/" name="src/core/lib/surface/server.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/validate_metadata.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/version.c" role="src" /> + <file baseinstalldir="/" name="src/core/lib/transport/bdp_estimator.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/byte_stream.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/error_utils.c" role="src" /> diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 15f486d676..fa18f5a725 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -124,6 +124,21 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); +static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); +static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); + +static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error); +static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type, + grpc_closure *on_initiate, + grpc_closure *on_complete); + +#define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0 +#define DEFAULT_MAX_PINGS_BETWEEN_DATA 3 + /******************************************************************************* * CONSTRUCTION/DESTRUCTION/REFCOUNTING */ @@ -155,16 +170,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_combiner_destroy(exec_ctx, t->combiner); - /* callback remaining pings: they're not allowed to call into the transpot, - and maybe they hold resources that need to be freed */ - while (t->pings.next != &t->pings) { - grpc_chttp2_outstanding_ping *ping = t->pings.next; - grpc_closure_sched(exec_ctx, ping->on_recv, - GRPC_ERROR_CREATE("Transport closed")); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - } + cancel_pings(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed")); while (t->write_cb_pool) { grpc_chttp2_write_cb *next = t->write_cb_pool->next; @@ -172,6 +178,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, t->write_cb_pool = next; } + gpr_free(t->ping_acks); gpr_free(t->peer_string); gpr_free(t); } @@ -224,10 +231,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->is_client = is_client; t->outgoing_window = DEFAULT_WINDOW; t->incoming_window = DEFAULT_WINDOW; - t->stream_lookahead = DEFAULT_WINDOW; - t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; - t->ping_counter = 1; - t->pings.next = t->pings.prev = &t->pings; t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->is_first_frame = true; grpc_connectivity_state_init( @@ -248,6 +251,22 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_closure_init(&t->destructive_reclaimer_locked, destructive_reclaimer_locked, t, grpc_combiner_scheduler(t->combiner, false)); + grpc_closure_init(&t->start_bdp_ping_locked, start_bdp_ping_locked, t, + grpc_combiner_scheduler(t->combiner, false)); + grpc_closure_init(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, + grpc_combiner_scheduler(t->combiner, false)); + + grpc_bdp_estimator_init(&t->bdp_estimator, t->peer_string); + t->last_pid_update = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_pid_controller_init( + &t->pid_controller, + (grpc_pid_controller_args){.gain_p = 4, + .gain_i = 8, + .gain_d = 0, + .initial_control_value = log2(DEFAULT_WINDOW), + .min_control_value = -1, + .max_control_value = 22, + .integral_range = 10}); grpc_chttp2_goaway_parser_init(&t->goaway_parser); grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser); @@ -290,6 +309,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, DEFAULT_MAX_HEADER_LIST_SIZE); + t->ping_policy = (grpc_chttp2_repeated_ping_policy){ + .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA, + .min_time_between_pings = + gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN), + }; + if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, @@ -307,14 +332,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) { - const grpc_integer_options options = {-1, 5, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - t->stream_lookahead = (uint32_t)value; - } - } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { const grpc_integer_options options = {-1, 0, INT_MAX}; const int value = @@ -324,6 +341,19 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, (uint32_t)value); } } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) { + t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){DEFAULT_MAX_PINGS_BETWEEN_DATA, 0, INT_MAX}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) { + t->ping_policy.min_time_between_pings = gpr_time_from_millis( + grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0, + INT_MAX}), + GPR_TIMESPAN); + } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) { t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer( &channel_args->args[i], @@ -334,24 +364,26 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_setting_id setting_id; grpc_integer_options integer_options; bool availability[2] /* server, client */; - } settings_map[] = { - {GRPC_ARG_MAX_CONCURRENT_STREAMS, - GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, - {-1, 0, INT_MAX}, - {true, false}}, - {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, - GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, - {-1, 0, INT_MAX}, - {true, true}}, - {GRPC_ARG_MAX_METADATA_SIZE, - GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, - {-1, 0, INT_MAX}, - {true, true}}, - {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, - GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, - {-1, 16384, 16777215}, - {true, true}}, - }; + } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS, + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, + {-1, 0, INT32_MAX}, + {true, false}}, + {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, + GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, + {-1, 0, INT32_MAX}, + {true, true}}, + {GRPC_ARG_MAX_METADATA_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, + {-1, 0, INT32_MAX}, + {true, true}}, + {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, + {-1, 16384, 16777215}, + {true, true}}, + {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + {-1, 5, INT32_MAX}, + {true, true}}}; for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) { if (0 == strcmp(channel_args->args[i].key, settings_map[j].channel_arg_name)) { @@ -374,6 +406,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + grpc_chttp2_initiate_write(exec_ctx, t, false, "init"); post_benign_reclaimer(exec_ctx, t); } @@ -425,6 +460,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); } end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); + cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); } @@ -475,11 +511,6 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, if (server_data) { s->id = (uint32_t)(uintptr_t)server_data; - s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->incoming_window = s->max_recv_bytes = - t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); post_destructive_reclaimer(exec_ctx, t); @@ -508,6 +539,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, } grpc_chttp2_list_remove_stalled_by_transport(t, s); + grpc_chttp2_list_remove_stalled_by_stream(t, s); for (int i = 0; i < STREAM_LIST_COUNT; i++) { if (s->included[i]) { @@ -647,13 +679,21 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, GPR_TIMER_END("grpc_chttp2_initiate_write", 0); } -void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, bool covered_by_poller, - const char *reason) { +void grpc_chttp2_become_writable( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_chttp2_stream_write_type stream_write_type, const char *reason) { if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become"); - grpc_chttp2_initiate_write(exec_ctx, t, covered_by_poller, reason); + } + switch (stream_write_type) { + case GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK: + break; + case GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED: + grpc_chttp2_initiate_write(exec_ctx, t, true, reason); + break; + case GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED: + grpc_chttp2_initiate_write(exec_ctx, t, false, reason); + break; } } @@ -781,7 +821,6 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx, static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { grpc_chttp2_stream *s; - uint32_t stream_incoming_window; /* start streams where we have free grpc_chttp2_stream ids and free * concurrency */ while (t->next_stream_id <= MAX_CLIENT_STREAM_ID && @@ -804,15 +843,11 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, "no_more_stream_ids"); } - s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->incoming_window = stream_incoming_window = - t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes); grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); post_destructive_reclaimer(exec_ctx, t); - grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream"); + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + "new_stream"); } /* cancel out streams that will never be started */ while (t->next_stream_id >= MAX_CLIENT_STREAM_ID && @@ -907,7 +942,9 @@ static void maybe_become_writable_due_to_send_msg(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) { if (s->id != 0 && (!s->write_buffering || s->flow_controlled_buffer.length > t->write_buffer_size)) { - grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message"); + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + "op.send_message"); } } @@ -1069,7 +1106,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, } } else { GPR_ASSERT(s->id != 0); - grpc_chttp2_become_writable(exec_ctx, t, s, true, + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, "op.send_initial_metadata"); } } else { @@ -1160,7 +1198,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, } else if (s->id != 0) { /* TODO(ctiller): check if there's flow control for any outstanding bytes before going writable */ - grpc_chttp2_become_writable(exec_ctx, t, s, true, + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, "op.send_trailing_metadata"); } } @@ -1179,8 +1218,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, s->recv_message = op->recv_message; if (s->id != 0 && (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) { - incoming_byte_stream_update_flow_control(exec_ctx, t, s, - t->stream_lookahead, 0); + incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, 0); } grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); } @@ -1224,43 +1262,46 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, GPR_TIMER_END("perform_stream_op", 0); } +static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error) { + /* callback remaining pings: they're not allowed to call into the transpot, + and maybe they hold resources that need to be freed */ + for (size_t i = 0; i < GRPC_CHTTP2_PING_TYPE_COUNT; i++) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[i]; + for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) { + grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error)); + grpc_closure_list_sched(exec_ctx, &pq->lists[j]); + } + } + GRPC_ERROR_UNREF(error); +} + static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_closure *on_recv) { - grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); - p->next = &t->pings; - p->prev = p->next->prev; - p->prev->next = p->next->prev = p; - p->id[0] = (uint8_t)((t->ping_counter >> 56) & 0xff); - p->id[1] = (uint8_t)((t->ping_counter >> 48) & 0xff); - p->id[2] = (uint8_t)((t->ping_counter >> 40) & 0xff); - p->id[3] = (uint8_t)((t->ping_counter >> 32) & 0xff); - p->id[4] = (uint8_t)((t->ping_counter >> 24) & 0xff); - p->id[5] = (uint8_t)((t->ping_counter >> 16) & 0xff); - p->id[6] = (uint8_t)((t->ping_counter >> 8) & 0xff); - p->id[7] = (uint8_t)(t->ping_counter & 0xff); - t->ping_counter++; - p->on_recv = on_recv; - grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id)); - grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping"); + grpc_chttp2_ping_type ping_type, + grpc_closure *on_initiate, grpc_closure *on_ack) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type]; + grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate, + GRPC_ERROR_NONE); + if (grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT], on_ack, + GRPC_ERROR_NONE)) { + grpc_chttp2_initiate_write(exec_ctx, t, false, "send_ping"); + } } void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const uint8_t *opaque_8bytes) { - grpc_chttp2_outstanding_ping *ping; - for (ping = t->pings.next; ping != &t->pings; ping = ping->next) { - if (0 == memcmp(opaque_8bytes, ping->id, 8)) { - grpc_closure_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - return; - } + uint64_t id) { + grpc_chttp2_ping_queue *pq = + &t->ping_queues[id % GRPC_CHTTP2_PING_TYPE_COUNT]; + if (pq->inflight_id != id) { + char *from = grpc_endpoint_get_peer(t->ep); + gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, from, id); + gpr_free(from); + return; + } + grpc_closure_list_sched(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]); + if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) { + grpc_chttp2_initiate_write(exec_ctx, t, false, "continue_pings"); } - char *msg = gpr_dump((const char *)opaque_8bytes, 8, GPR_DUMP_HEX); - char *from = grpc_endpoint_get_peer(t->ep); - gpr_log(GPR_DEBUG, "Unknown ping response from %s: %s", from, msg); - gpr_free(from); - gpr_free(msg); } static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, @@ -1308,7 +1349,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, } if (op->send_ping) { - send_ping_locked(exec_ctx, t, op->send_ping); + send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, NULL, + op->send_ping); } if (close_transport != GRPC_ERROR_NONE) { @@ -1733,34 +1775,28 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GRPC_ERROR_UNREF(error); } -/** update window from a settings change */ -typedef struct { - grpc_chttp2_transport *t; - grpc_exec_ctx *exec_ctx; -} update_global_window_args; +/******************************************************************************* + * INPUT PROCESSING - PARSING + */ -static void update_global_window(void *args, uint32_t id, void *stream) { - update_global_window_args *a = args; - grpc_chttp2_transport *t = a->t; - grpc_chttp2_stream *s = stream; - int was_zero; - int is_zero; - int64_t initial_window_update = t->initial_window_update; - - if (initial_window_update > 0) { - was_zero = s->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", t, s, outgoing_window, - initial_window_update); - is_zero = s->outgoing_window <= 0; - - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(a->exec_ctx, t, s, true, - "update_global_window"); - } +static void update_bdp(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + double bdp_dbl) { + uint32_t bdp; + if (bdp_dbl <= 0) { + bdp = 0; + } else if (bdp_dbl > UINT32_MAX) { + bdp = UINT32_MAX; } else { - GRPC_CHTTP2_FLOW_DEBIT_STREAM("settings", t, s, outgoing_window, - -initial_window_update); + bdp = (uint32_t)(bdp_dbl); + } + int64_t delta = + (int64_t)bdp - + (int64_t)t->settings[GRPC_LOCAL_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + if (delta == 0 || (bdp != 0 && delta > -1024 && delta < 1024)) { + return; } + push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, bdp); } /******************************************************************************* @@ -1802,6 +1838,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_BEGIN("reading_action_locked", 0); grpc_chttp2_transport *t = tp; + bool need_bdp_ping = false; GRPC_ERROR_REF(error); @@ -1819,9 +1856,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, 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++) { + if (grpc_bdp_estimator_add_incoming_bytes( + &t->bdp_estimator, + (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]))) { + need_bdp_ping = true; + } errors[1] = grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]); - }; + } if (errors[1] != GRPC_ERROR_NONE) { errors[2] = try_http_parsing(exec_ctx, t); GRPC_ERROR_UNREF(error); @@ -1835,21 +1877,16 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_BEGIN("post_parse_locked", 0); if (t->initial_window_update != 0) { - update_global_window_args args = {t, exec_ctx}; - grpc_chttp2_stream_map_for_each(&t->stream_map, update_global_window, - &args); + if (t->initial_window_update > 0) { + grpc_chttp2_stream *s; + while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) { + grpc_chttp2_become_writable( + exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED, + "unstalled"); + } + } t->initial_window_update = 0; } - /* handle higher level things */ - if (t->incoming_window < t->connection_window_target * 3 / 4) { - int64_t announce_bytes = t->connection_window_target - t->incoming_window; - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, announce_incoming_window, - announce_bytes); - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, incoming_window, - announce_bytes); - grpc_chttp2_initiate_write(exec_ctx, t, false, "global incoming window"); - } - GPR_TIMER_END("post_parse_locked", 0); } @@ -1870,6 +1907,35 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, if (keep_reading) { grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_locked); + + if (need_bdp_ping) { + GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); + grpc_bdp_estimator_schedule_ping(&t->bdp_estimator); + send_ping_locked(exec_ctx, t, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE, + &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked); + } + + int64_t estimate = -1; + if (grpc_bdp_estimator_get_estimate(&t->bdp_estimator, &estimate)) { + double target = 1 + log2((double)estimate); + double memory_pressure = grpc_resource_quota_get_memory_pressure( + grpc_resource_user_quota(grpc_endpoint_get_resource_user(t->ep))); + if (memory_pressure > 0.8) { + target *= 1 - GPR_MIN(1, (memory_pressure - 0.8) / 0.1); + } + double bdp_error = target - grpc_pid_controller_last(&t->pid_controller); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec dt_timespec = gpr_time_sub(now, t->last_pid_update); + double dt = (double)dt_timespec.tv_sec + dt_timespec.tv_nsec * 1e-9; + if (dt > 0.1) { + dt = 0.1; + } + double log2_bdp_guess = + grpc_pid_controller_update(&t->pid_controller, bdp_error, dt); + update_bdp(exec_ctx, t, pow(2, log2_bdp_guess)); + t->last_pid_update = now; + } GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); @@ -1882,6 +1948,26 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action_locked", 0); } +static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + if (grpc_http_trace) { + gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string); + } + grpc_bdp_estimator_start_ping(&t->bdp_estimator); +} + +static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + if (grpc_http_trace) { + gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string); + } + grpc_bdp_estimator_complete_ping(&t->bdp_estimator); + + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); +} + /******************************************************************************* * CALLBACK LOOP */ @@ -1932,10 +2018,12 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, size_t max_size_hint, size_t have_already) { uint32_t max_recv_bytes; + uint32_t initial_window_size = + t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; /* clamp max recv hint to an allowable size */ - if (max_size_hint >= UINT32_MAX - t->stream_lookahead) { - max_recv_bytes = UINT32_MAX - t->stream_lookahead; + if (max_size_hint >= UINT32_MAX - initial_window_size) { + max_recv_bytes = UINT32_MAX - initial_window_size; } else { max_recv_bytes = (uint32_t)max_size_hint; } @@ -1948,20 +2036,26 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, } /* add some small lookahead to keep pipelines flowing */ - GPR_ASSERT(max_recv_bytes <= UINT32_MAX - t->stream_lookahead); - max_recv_bytes += t->stream_lookahead; - if (s->max_recv_bytes < max_recv_bytes) { - uint32_t add_max_recv_bytes = max_recv_bytes - s->max_recv_bytes; - bool new_window_write_is_covered_by_poller = - s->max_recv_bytes < have_already; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, max_recv_bytes, - add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window, + GPR_ASSERT(max_recv_bytes <= UINT32_MAX - initial_window_size); + if (s->incoming_window_delta < max_recv_bytes && !s->read_closed) { + uint32_t add_max_recv_bytes = + (uint32_t)(max_recv_bytes - s->incoming_window_delta); + grpc_chttp2_stream_write_type write_type = + GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED; + if (s->incoming_window_delta + initial_window_size < + (int64_t)have_already) { + write_type = GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED; + } + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window_delta, add_max_recv_bytes); GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, announce_window, add_max_recv_bytes); - grpc_chttp2_become_writable(exec_ctx, t, s, - new_window_write_is_covered_by_poller, + if ((int64_t)s->incoming_window_delta + (int64_t)initial_window_size - + (int64_t)s->announce_window > + (int64_t)initial_window_size / 2) { + write_type = GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK; + } + grpc_chttp2_become_writable(exec_ctx, t, s, write_type, "read_incoming_stream"); } } diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index 7de5f6362d..f487533c41 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -40,7 +40,7 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> -grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { +grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { grpc_slice slice = grpc_slice_malloc(9 + 8); uint8_t *p = GRPC_SLICE_START_PTR(slice); @@ -53,7 +53,14 @@ grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { *p++ = 0; *p++ = 0; *p++ = 0; - memcpy(p, opaque_8bytes, 8); + *p++ = (uint8_t)(opaque_8bytes >> 56); + *p++ = (uint8_t)(opaque_8bytes >> 48); + *p++ = (uint8_t)(opaque_8bytes >> 40); + *p++ = (uint8_t)(opaque_8bytes >> 32); + *p++ = (uint8_t)(opaque_8bytes >> 24); + *p++ = (uint8_t)(opaque_8bytes >> 16); + *p++ = (uint8_t)(opaque_8bytes >> 8); + *p++ = (uint8_t)(opaque_8bytes); return slice; } @@ -70,6 +77,7 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, } parser->byte = 0; parser->is_ack = flags; + parser->opaque_8bytes = 0; return GRPC_ERROR_NONE; } @@ -83,7 +91,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_ping_parser *p = parser; while (p->byte != 8 && cur != end) { - p->opaque_8bytes[p->byte] = *cur; + p->opaque_8bytes |= (((uint64_t)*cur) << (8 * p->byte)); cur++; p->byte++; } @@ -93,8 +101,12 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, if (p->is_ack) { grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); } else { - grpc_slice_buffer_add(&t->qbuf, - grpc_chttp2_ping_create(1, p->opaque_8bytes)); + if (t->ping_ack_count == t->ping_ack_capacity) { + t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); + t->ping_acks = gpr_realloc( + t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + } + t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } } diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h index b9889e2d11..ef642465d7 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.h +++ b/src/core/ext/transport/chttp2/transport/frame_ping.h @@ -41,10 +41,10 @@ typedef struct { uint8_t byte; uint8_t is_ack; - uint8_t opaque_8bytes[8]; + uint64_t opaque_8bytes; } grpc_chttp2_ping_parser; -grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); +grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes); grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c index be9b663ac1..82290e34cd 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.c +++ b/src/core/ext/transport/chttp2/transport/frame_settings.c @@ -236,7 +236,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, } if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && parser->incoming_settings[parser->id] != parser->value) { - t->initial_window_update = + t->initial_window_update += (int64_t)parser->value - parser->incoming_settings[parser->id]; if (grpc_http_trace) { gpr_log(GPR_DEBUG, "adding %d for initial_window change", @@ -245,8 +245,9 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, } parser->incoming_settings[parser->id] = parser->value; if (grpc_http_trace) { - gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", - t->is_client ? "CLI" : "SVR", parser->id, parser->value); + gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %d = %d", + t->is_client ? "CLI" : "SVR", t->peer_string, parser->id, + parser->value); } } else if (grpc_http_trace) { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c index 31a31c2871..8fa0bb471a 100644 --- a/src/core/ext/transport/chttp2/transport/frame_window_update.c +++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c @@ -110,13 +110,12 @@ grpc_error *grpc_chttp2_window_update_parser_parse( if (t->incoming_stream_id != 0) { if (s != NULL) { - bool was_zero = s->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window, + GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window_delta, received_update); - bool is_zero = s->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(exec_ctx, t, s, false, - "stream.read_flow_control"); + if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) { + grpc_chttp2_become_writable( + exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED, + "stream.read_flow_control"); } } } else { diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index ee5edc92df..1dabf9edba 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -50,7 +50,9 @@ #include "src/core/ext/transport/chttp2/transport/stream_map.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/endpoint.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" #include "src/core/lib/transport/transport_impl.h" /* streams are kept in various linked lists depending on what things need to @@ -59,6 +61,7 @@ typedef enum { GRPC_CHTTP2_LIST_WRITABLE, GRPC_CHTTP2_LIST_WRITING, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT, + GRPC_CHTTP2_LIST_STALLED_BY_STREAM, /** streams that are waiting to start because there are too many concurrent streams on the connection */ GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, @@ -72,6 +75,34 @@ typedef enum { GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER, } grpc_chttp2_write_state; +typedef enum { + GRPC_CHTTP2_PING_ON_NEXT_WRITE = 0, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE, + GRPC_CHTTP2_PING_TYPE_COUNT /* must be last */ +} grpc_chttp2_ping_type; + +typedef enum { + GRPC_CHTTP2_PCL_INITIATE = 0, + GRPC_CHTTP2_PCL_NEXT, + GRPC_CHTTP2_PCL_INFLIGHT, + GRPC_CHTTP2_PCL_COUNT /* must be last */ +} grpc_chttp2_ping_closure_list; + +typedef struct { + grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT]; + uint64_t inflight_id; +} grpc_chttp2_ping_queue; + +typedef struct { + gpr_timespec min_time_between_pings; + int max_pings_without_data; +} grpc_chttp2_repeated_ping_policy; + +typedef struct { + gpr_timespec last_ping_sent_time; + int pings_before_data_required; +} grpc_chttp2_repeated_ping_state; + /* deframer state for the overall http2 stream of bytes */ typedef enum { /* prefix: one entry per http2 connection prefix byte */ @@ -144,14 +175,6 @@ typedef enum { GRPC_CHTTP2_GOAWAY_SENT, } grpc_chttp2_sent_goaway_state; -/* Outstanding ping request data */ -typedef struct grpc_chttp2_outstanding_ping { - uint8_t id[8]; - grpc_closure *on_recv; - struct grpc_chttp2_outstanding_ping *next; - struct grpc_chttp2_outstanding_ping *prev; -} grpc_chttp2_outstanding_ping; - typedef struct grpc_chttp2_write_cb { int64_t call_at_byte; grpc_closure *closure; @@ -271,16 +294,19 @@ struct grpc_chttp2_transport { copied to next_stream_id in parsing when parsing commences */ uint32_t next_stream_id; - /** how far to lookahead in a stream? */ - uint32_t stream_lookahead; - /** last new stream id */ uint32_t last_new_stream_id; - /** pings awaiting responses */ - grpc_chttp2_outstanding_ping pings; - /** next payload for an outgoing ping */ - uint64_t ping_counter; + /** ping queues for various ping insertion points */ + grpc_chttp2_ping_queue ping_queues[GRPC_CHTTP2_PING_TYPE_COUNT]; + grpc_chttp2_repeated_ping_policy ping_policy; + grpc_chttp2_repeated_ping_state ping_state; + uint64_t ping_ctr; /* unique id for pings */ + + /** ping acks */ + size_t ping_ack_count; + size_t ping_ack_capacity; + uint64_t *ping_acks; /** parser for headers */ grpc_chttp2_hpack_parser hpack_parser; @@ -324,6 +350,13 @@ struct grpc_chttp2_transport { grpc_chttp2_write_cb *write_cb_pool; + /* bdp estimator */ + grpc_bdp_estimator bdp_estimator; + grpc_pid_controller pid_controller; + grpc_closure start_bdp_ping_locked; + grpc_closure finish_bdp_ping_locked; + gpr_timespec last_pid_update; + /* if non-NULL, close the transport with this error when writes are finished */ grpc_error *close_transport_on_writes_finished; @@ -362,12 +395,10 @@ struct grpc_chttp2_stream { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ uint32_t id; - /** window available for us to send to peer */ - int64_t outgoing_window; - /** The number of bytes the upper layers have offered to receive. - As the upper layer offers more bytes, this value increases. - As bytes are read, this value decreases. */ - uint32_t max_recv_bytes; + /** window available for us to send to peer, over or under the initial window + * size of the transport... ie: + * outgoing_window = outgoing_window_delta + transport.initial_window_size */ + int64_t outgoing_window_delta; /** things the upper layers would like to send */ grpc_metadata_batch *send_initial_metadata; grpc_closure *send_initial_metadata_finished; @@ -428,8 +459,10 @@ struct grpc_chttp2_stream { grpc_error *forced_close_error; /** how many header frames have we received? */ uint8_t header_frames_received; - /** window available for peer to send to us */ - int64_t incoming_window; + /** window available for peer to send to us (as a delta on + * transport.initial_window_size) + * incoming_window = incoming_window_delta + transport.initial_window_size */ + int64_t incoming_window_delta; /** parsing state for data frames */ grpc_chttp2_data_parser data_parser; /** number of bytes received - reset at end of parse thread execution */ @@ -478,36 +511,43 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); /** Get a writable stream returns non-zero if there was a stream available */ -int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); bool grpc_chttp2_list_remove_writable_stream( grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t); -int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t); +bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport *t, grpc_chttp2_stream *s); void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s); +void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); +bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); + grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t, uint32_t id); grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx, @@ -672,13 +712,23 @@ void grpc_chttp2_incoming_byte_stream_finished( grpc_error *error); void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const uint8_t *opaque_8bytes); + uint64_t id); + +typedef enum { + /* don't initiate a transport write, but piggyback on the next one */ + GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK, + /* initiate a covered write */ + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + /* initiate an uncovered write */ + GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED +} grpc_chttp2_stream_write_type; /** add a ref to the stream and add it to the writable list; ref will be dropped in writing.c */ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s, bool covered_by_poller, + grpc_chttp2_stream *s, + grpc_chttp2_stream_write_type type, const char *reason); void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c index f58cd696f9..24bd93067b 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.c +++ b/src/core/ext/transport/chttp2/transport/parsing.c @@ -376,25 +376,45 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx, return err; } + uint32_t target_incoming_window = GPR_MAX( + t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], + 1024); GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window, incoming_frame_size); + if (t->incoming_window <= target_incoming_window / 2) { + grpc_chttp2_initiate_write(exec_ctx, t, false, "flow_control"); + } if (s != NULL) { - if (incoming_frame_size > s->incoming_window) { + if (incoming_frame_size > + s->incoming_window_delta + + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]) { char *msg; gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, - t->incoming_frame_size, s->incoming_window); + t->incoming_frame_size, + s->incoming_window_delta + + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } - GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window, + GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window_delta, incoming_frame_size); + if ((int64_t)t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] + + (int64_t)s->incoming_window_delta - (int64_t)s->announce_window <= + (int64_t)t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] / + 2) { + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED, + "window-update-required"); + } s->received_bytes += incoming_frame_size; - s->max_recv_bytes -= - (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size); } return GRPC_ERROR_NONE; diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c index a60264cc51..078818fb18 100644 --- a/src/core/ext/transport/chttp2/transport/stream_lists.c +++ b/src/core/ext/transport/chttp2/transport/stream_lists.c @@ -37,14 +37,14 @@ /* core list management */ -static int stream_list_empty(grpc_chttp2_transport *t, - grpc_chttp2_stream_list_id id) { +static bool stream_list_empty(grpc_chttp2_transport *t, + grpc_chttp2_stream_list_id id) { return t->lists[id].head == NULL; } -static int stream_list_pop(grpc_chttp2_transport *t, - grpc_chttp2_stream **stream, - grpc_chttp2_stream_list_id id) { +static bool stream_list_pop(grpc_chttp2_transport *t, + grpc_chttp2_stream **stream, + grpc_chttp2_stream_list_id id) { grpc_chttp2_stream *s = t->lists[id].head; if (s) { grpc_chttp2_stream *new_head = s->links[id].next; @@ -124,8 +124,8 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE); } -int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE); } @@ -139,12 +139,12 @@ bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING); } -int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) { +bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) { return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING); } -int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING); } @@ -153,8 +153,8 @@ void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } -int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } @@ -168,8 +168,8 @@ void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } -int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } @@ -177,3 +177,18 @@ void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s) { stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } + +void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); +} + +bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); +} + +bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); +} diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 148e3844b5..05e6f59947 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -56,6 +56,75 @@ static void finish_write_cb(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->write_cb_pool = cb; } +static void collapse_pings_from_into(grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type, + grpc_chttp2_ping_queue *pq) { + for (size_t i = 0; i < GRPC_CHTTP2_PCL_COUNT; i++) { + grpc_closure_list_move(&t->ping_queues[ping_type].lists[i], &pq->lists[i]); + } +} + +static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type]; + if (grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) { + /* no ping needed: wait */ + return; + } + if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) { + /* ping already in-flight: wait */ + if (grpc_http_trace || grpc_bdp_estimator_trace) { + gpr_log(GPR_DEBUG, "Ping delayed [%p]: already pinging", t->peer_string); + } + return; + } + if (t->ping_state.pings_before_data_required == 0 && + t->ping_policy.max_pings_without_data != 0) { + /* need to send something of substance before sending a ping again */ + if (grpc_http_trace || grpc_bdp_estimator_trace) { + gpr_log(GPR_DEBUG, "Ping delayed [%p]: too many recent pings: %d/%d", + t->peer_string, t->ping_state.pings_before_data_required, + t->ping_policy.max_pings_without_data); + } + return; + } + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec elapsed = gpr_time_sub(now, t->ping_state.last_ping_sent_time); + /*gpr_log(GPR_DEBUG, "elapsed:%d.%09d min:%d.%09d", (int)elapsed.tv_sec, + elapsed.tv_nsec, (int)t->ping_policy.min_time_between_pings.tv_sec, + (int)t->ping_policy.min_time_between_pings.tv_nsec);*/ + if (gpr_time_cmp(elapsed, t->ping_policy.min_time_between_pings) < 0) { + /* not enough elapsed time between successive pings */ + if (grpc_http_trace || grpc_bdp_estimator_trace) { + gpr_log(GPR_DEBUG, + "Ping delayed [%p]: not enough time elapsed since last ping", + t->peer_string); + } + return; + } + /* coalesce equivalent pings into this one */ + switch (ping_type) { + case GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE: + collapse_pings_from_into(t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, pq); + break; + case GRPC_CHTTP2_PING_ON_NEXT_WRITE: + break; + case GRPC_CHTTP2_PING_TYPE_COUNT: + GPR_UNREACHABLE_CODE(break); + } + pq->inflight_id = t->ping_ctr * GRPC_CHTTP2_PING_TYPE_COUNT + ping_type; + t->ping_ctr++; + grpc_closure_list_sched(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INITIATE]); + grpc_closure_list_move(&pq->lists[GRPC_CHTTP2_PCL_NEXT], + &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]); + grpc_slice_buffer_add(&t->outbuf, + grpc_chttp2_ping_create(false, pq->inflight_id)); + t->ping_state.last_ping_sent_time = now; + t->ping_state.pings_before_data_required -= + (t->ping_state.pings_before_data_required != 0); +} + static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, int64_t send_bytes, grpc_chttp2_write_cb **list, grpc_error *error) { @@ -139,6 +208,8 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, s->sent_initial_metadata = true; sent_initial_metadata = true; now_writing = true; + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; } /* send any window updates */ if (s->announce_window > 0) { @@ -146,15 +217,22 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create( s->id, s->announce_window, &s->stats.outgoing)); + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce); } if (sent_initial_metadata) { /* send any body bytes, if allowed by flow control */ if (s->flow_controlled_buffer.length > 0) { - uint32_t max_outgoing = - (uint32_t)GPR_MIN(t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - GPR_MIN(s->outgoing_window, t->outgoing_window)); + uint32_t stream_outgoing_window = (uint32_t)GPR_MAX( + 0, + s->outgoing_window_delta + + (int64_t)t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); + uint32_t max_outgoing = (uint32_t)GPR_MIN( + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + GPR_MIN(stream_outgoing_window, t->outgoing_window)); if (max_outgoing > 0) { uint32_t send_bytes = (uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length); @@ -167,10 +245,12 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes, is_last_frame, &s->stats.outgoing, &t->outbuf); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window, + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta, send_bytes); GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, send_bytes); + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; if (is_last_frame) { s->send_trailing_metadata = NULL; s->sent_trailing_metadata = true; @@ -189,6 +269,9 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, } else if (t->outgoing_window == 0) { grpc_chttp2_list_add_stalled_by_transport(t, s); now_writing = true; + } else if (stream_outgoing_window == 0) { + grpc_chttp2_list_add_stalled_by_stream(t, s); + now_writing = true; } } if (s->send_trailing_metadata != NULL && @@ -227,15 +310,32 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, /* if the grpc_chttp2_transport is ready to send a window update, do so here also; 3/4 is a magic number that will likely get tuned soon */ - if (t->announce_incoming_window > 0) { - uint32_t announced = - (uint32_t)GPR_MIN(t->announce_incoming_window, UINT32_MAX); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window, - announced); + uint32_t target_incoming_window = GPR_MAX( + t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], + 1024); + uint32_t threshold_to_send_transport_window_update = + t->outbuf.count > 0 ? 3 * target_incoming_window / 4 + : target_incoming_window / 2; + if (t->incoming_window <= threshold_to_send_transport_window_update) { + maybe_initiate_ping(exec_ctx, t, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE); + uint32_t announced = (uint32_t)GPR_CLAMP( + target_incoming_window - t->incoming_window, 0, UINT32_MAX); + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("write", t, incoming_window, announced); grpc_transport_one_way_stats throwaway_stats; grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create( 0, announced, &throwaway_stats)); + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + } + + for (size_t i = 0; i < t->ping_ack_count; i++) { + grpc_slice_buffer_add(&t->outbuf, + grpc_chttp2_ping_create(1, t->ping_acks[i])); } + t->ping_ack_count = 0; + + maybe_initiate_ping(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE); GPR_TIMER_END("grpc_chttp2_begin_write", 0); diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c index 8e4efd3370..509c1ff95d 100644 --- a/src/core/lib/iomgr/closure.c +++ b/src/core/lib/iomgr/closure.c @@ -51,20 +51,22 @@ void grpc_closure_list_init(grpc_closure_list *closure_list) { closure_list->head = closure_list->tail = NULL; } -void grpc_closure_list_append(grpc_closure_list *closure_list, +bool grpc_closure_list_append(grpc_closure_list *closure_list, grpc_closure *closure, grpc_error *error) { if (closure == NULL) { GRPC_ERROR_UNREF(error); - return; + return false; } closure->error_data.error = error; closure->next_data.next = NULL; - if (closure_list->head == NULL) { + bool was_empty = (closure_list->head == NULL); + if (was_empty) { closure_list->head = closure; } else { closure_list->tail->next_data.next = closure; } closure_list->tail = closure; + return was_empty; } void grpc_closure_list_fail_all(grpc_closure_list *list, diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index 6748b21e59..2510d50b42 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -116,8 +116,9 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg, void grpc_closure_list_init(grpc_closure_list *list); /** add \a closure to the end of \a list - and set \a closure's result to \a error */ -void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure, + and set \a closure's result to \a error + Returns true if \a list becomes non-empty */ +bool grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure, grpc_error *error); /** force all success bits in \a list to false */ diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c index d5995a5ac6..2cc979467f 100644 --- a/src/core/lib/iomgr/resource_quota.c +++ b/src/core/lib/iomgr/resource_quota.c @@ -33,6 +33,8 @@ #include "src/core/lib/iomgr/resource_quota.h" +#include <limits.h> +#include <stdint.h> #include <string.h> #include <grpc/support/alloc.h> @@ -44,6 +46,8 @@ int grpc_resource_quota_trace = 0; +#define MEMORY_USAGE_ESTIMATION_MAX 65536 + /* Internal linked list pointers for a resource user */ typedef struct { grpc_resource_user *next; @@ -126,9 +130,12 @@ struct grpc_resource_quota { /* refcount */ gpr_refcount refs; + /* estimate of current memory usage + scaled to the range [0..RESOURCE_USAGE_ESTIMATION_MAX] */ + gpr_atm memory_usage_estimation; + /* Master combiner lock: all activity on a quota executes under this combiner - * (so no mutex is needed for this data structure) - */ + * (so no mutex is needed for this data structure) */ grpc_combiner *combiner; /* Size of the resource quota */ int64_t size; @@ -269,6 +276,16 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx, GRPC_ERROR_NONE); } +/* update the atomically available resource estimate - use no barriers since + timeliness of delivery really doesn't matter much */ +static void rq_update_estimate(grpc_resource_quota *resource_quota) { + gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, + (gpr_atm)((1.0 - + ((double)resource_quota->free_pool) / + ((double)resource_quota->size)) * + MEMORY_USAGE_ESTIMATION_MAX)); +} + /* returns true if all allocations are completed */ static bool rq_alloc(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) { @@ -281,6 +298,7 @@ static bool rq_alloc(grpc_exec_ctx *exec_ctx, int64_t amt = -resource_user->free_pool; resource_user->free_pool = 0; resource_quota->free_pool -= amt; + rq_update_estimate(resource_quota); if (grpc_resource_quota_trace) { gpr_log(GPR_DEBUG, "RQ %s %s: grant alloc %" PRId64 " bytes; rq_free_pool -> %" PRId64, @@ -315,6 +333,7 @@ static bool rq_reclaim_from_per_user_free_pool( int64_t amt = resource_user->free_pool; resource_user->free_pool = 0; resource_quota->free_pool += amt; + rq_update_estimate(resource_quota); if (grpc_resource_quota_trace) { gpr_log(GPR_DEBUG, "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64 " bytes; rq_free_pool -> %" PRId64, @@ -531,6 +550,7 @@ static void rq_resize(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) { int64_t delta = a->size - a->resource_quota->size; a->resource_quota->size += delta; a->resource_quota->free_pool += delta; + rq_update_estimate(a->resource_quota); rq_step_sched(exec_ctx, a->resource_quota); grpc_resource_quota_unref_internal(exec_ctx, a->resource_quota); gpr_free(a); @@ -557,6 +577,7 @@ grpc_resource_quota *grpc_resource_quota_create(const char *name) { resource_quota->size = INT64_MAX; resource_quota->step_scheduled = false; resource_quota->reclaiming = false; + gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0); if (name != NULL) { resource_quota->name = gpr_strdup(name); } else { @@ -602,6 +623,13 @@ void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) { grpc_resource_quota_ref_internal(resource_quota); } +double grpc_resource_quota_get_memory_pressure( + grpc_resource_quota *resource_quota) { + return ((double)(gpr_atm_no_barrier_load( + &resource_quota->memory_usage_estimation))) / + ((double)MEMORY_USAGE_ESTIMATION_MAX); +} + /* Public API */ void grpc_resource_quota_resize(grpc_resource_quota *resource_quota, size_t size) { diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h index d1127ce9ea..b9f62cbf83 100644 --- a/src/core/lib/iomgr/resource_quota.h +++ b/src/core/lib/iomgr/resource_quota.h @@ -84,6 +84,12 @@ void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx, grpc_resource_quota *grpc_resource_quota_from_channel_args( const grpc_channel_args *channel_args); +/* Return a number indicating current memory pressure: + 0.0 ==> no memory usage + 1.0 ==> maximum memory usage */ +double grpc_resource_quota_get_memory_pressure( + grpc_resource_quota *resource_quota); + typedef struct grpc_resource_user grpc_resource_user; grpc_resource_user *grpc_resource_user_create( diff --git a/src/core/lib/support/log_posix.c b/src/core/lib/support/log_posix.c index f972da0887..79458dd7a3 100644 --- a/src/core/lib/support/log_posix.c +++ b/src/core/lib/support/log_posix.c @@ -37,6 +37,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include <grpc/support/time.h> #include <pthread.h> #include <stdarg.h> @@ -93,10 +94,13 @@ void gpr_default_log(gpr_log_func_args *args) { strcpy(time_buffer, "error:strftime"); } - fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), gettid(), display_file, args->line, - args->message); + char *prefix; + gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), gettid(), display_file, args->line); + + fprintf(stderr, "%-70s %s\n", prefix, args->message); + gpr_free(prefix); } #endif /* defined(GPR_POSIX_LOG) */ diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c index 787e4d0dd2..b338ac4c48 100644 --- a/src/core/lib/surface/init.c +++ b/src/core/lib/surface/init.c @@ -63,6 +63,7 @@ #include "src/core/lib/surface/init.h" #include "src/core/lib/surface/lame_client.h" #include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/bdp_estimator.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/transport_impl.h" @@ -192,6 +193,7 @@ void grpc_init(void) { grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace); grpc_register_tracer("combiner", &grpc_combiner_trace); grpc_register_tracer("server_channel", &grpc_server_channel_trace); + grpc_register_tracer("bdp_estimator", &grpc_bdp_estimator_trace); // Default pluck trace to 1 grpc_cq_pluck_trace = 1; grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace); diff --git a/src/core/lib/transport/bdp_estimator.c b/src/core/lib/transport/bdp_estimator.c new file mode 100644 index 0000000000..e1483677fd --- /dev/null +++ b/src/core/lib/transport/bdp_estimator.c @@ -0,0 +1,104 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/transport/bdp_estimator.h" + +#include <stdlib.h> + +#include <grpc/support/log.h> +#include <grpc/support/useful.h> + +int grpc_bdp_estimator_trace = 0; + +void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) { + estimator->estimate = 65536; + estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED; + estimator->name = name; +} + +bool grpc_bdp_estimator_get_estimate(grpc_bdp_estimator *estimator, + int64_t *estimate) { + *estimate = estimator->estimate; + return true; +} + +bool grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator, + int64_t num_bytes) { + estimator->accumulator += num_bytes; + switch (estimator->ping_state) { + case GRPC_BDP_PING_UNSCHEDULED: + return true; + 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_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_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; +} + +void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator) { + if (grpc_bdp_estimator_trace) { + gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64, + estimator->name, estimator->accumulator, estimator->estimate); + } + GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_STARTED); + if (estimator->accumulator > 2 * estimator->estimate / 3) { + estimator->estimate *= 2; + if (grpc_bdp_estimator_trace) { + gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64, + estimator->name, estimator->estimate); + } + } + estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED; + estimator->accumulator = 0; +} diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h new file mode 100644 index 0000000000..bcaf899910 --- /dev/null +++ b/src/core/lib/transport/bdp_estimator.h @@ -0,0 +1,76 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H +#define GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H + +#include <stdbool.h> +#include <stdint.h> + +#define GRPC_BDP_SAMPLES 16 +#define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3 + +extern int grpc_bdp_estimator_trace; + +typedef enum { + GRPC_BDP_PING_UNSCHEDULED, + GRPC_BDP_PING_SCHEDULED, + GRPC_BDP_PING_STARTED +} grpc_bdp_estimator_ping_state; + +typedef struct grpc_bdp_estimator { + grpc_bdp_estimator_ping_state ping_state; + int64_t accumulator; + int64_t estimate; + const char *name; +} grpc_bdp_estimator; + +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(grpc_bdp_estimator *estimator, + int64_t *estimate); +// Returns true if the user should schedule a ping +bool grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator, + int64_t num_bytes); +// 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_bdp_estimator *estimator); + +#endif diff --git a/src/core/lib/transport/pid_controller.c b/src/core/lib/transport/pid_controller.c index 3cef225d4b..19cb1c0b36 100644 --- a/src/core/lib/transport/pid_controller.c +++ b/src/core/lib/transport/pid_controller.c @@ -32,26 +32,46 @@ */ #include "src/core/lib/transport/pid_controller.h" +#include <grpc/support/useful.h> void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - double gain_p, double gain_i, double gain_d) { - pid_controller->gain_p = gain_p; - pid_controller->gain_i = gain_i; - pid_controller->gain_d = gain_d; + grpc_pid_controller_args args) { + pid_controller->args = args; + pid_controller->last_control_value = args.initial_control_value; grpc_pid_controller_reset(pid_controller); } void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) { pid_controller->last_error = 0.0; + pid_controller->last_dc_dt = 0.0; pid_controller->error_integral = 0.0; } double grpc_pid_controller_update(grpc_pid_controller *pid_controller, double error, double dt) { - pid_controller->error_integral += error * dt; + /* integrate error using the trapezoid rule */ + pid_controller->error_integral += + dt * (pid_controller->last_error + error) * 0.5; + pid_controller->error_integral = GPR_CLAMP( + pid_controller->error_integral, -pid_controller->args.integral_range, + pid_controller->args.integral_range); double diff_error = (error - pid_controller->last_error) / dt; + /* calculate derivative of control value vs time */ + double dc_dt = pid_controller->args.gain_p * error + + pid_controller->args.gain_i * pid_controller->error_integral + + pid_controller->args.gain_d * diff_error; + /* and perform trapezoidal integration */ + double new_control_value = pid_controller->last_control_value + + dt * (pid_controller->last_dc_dt + dc_dt) * 0.5; + new_control_value = + GPR_CLAMP(new_control_value, pid_controller->args.min_control_value, + pid_controller->args.max_control_value); pid_controller->last_error = error; - return dt * (pid_controller->gain_p * error + - pid_controller->gain_i * pid_controller->error_integral + - pid_controller->gain_d * diff_error); + pid_controller->last_dc_dt = dc_dt; + pid_controller->last_control_value = new_control_value; + return new_control_value; +} + +double grpc_pid_controller_last(grpc_pid_controller *pid_controller) { + return pid_controller->last_control_value; } diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h index 83c82d6471..0a86521e90 100644 --- a/src/core/lib/transport/pid_controller.h +++ b/src/core/lib/transport/pid_controller.h @@ -45,20 +45,33 @@ typedef struct { double gain_p; double gain_i; double gain_d; + double initial_control_value; + double min_control_value; + double max_control_value; + double integral_range; +} grpc_pid_controller_args; + +typedef struct { double last_error; double error_integral; + double last_control_value; + double last_dc_dt; + grpc_pid_controller_args args; } grpc_pid_controller; /** Initialize the controller */ void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - double gain_p, double gain_i, double gain_d); + grpc_pid_controller_args args); /** Reset the controller: useful when things have changed significantly */ void grpc_pid_controller_reset(grpc_pid_controller *pid_controller); /** Update the controller: given a current error estimate, and the time since - the last update, returns a delta to the control value */ + the last update, returns a new control value */ double grpc_pid_controller_update(grpc_pid_controller *pid_controller, double error, double dt); +/** Returns the last control value calculated */ +double grpc_pid_controller_last(grpc_pid_controller *pid_controller); + #endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 68e40da4cf..6bca3ed1a5 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -180,6 +180,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/surface/server.c', 'src/core/lib/surface/validate_metadata.c', 'src/core/lib/surface/version.c', + 'src/core/lib/transport/bdp_estimator.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', 'src/core/lib/transport/error_utils.c', diff --git a/templates/tools/run_tests/generated/tests.json.template b/templates/tools/run_tests/generated/tests.json.template index 1e21465dd2..2815dbb9b3 100644 --- a/templates/tools/run_tests/generated/tests.json.template +++ b/templates/tools/run_tests/generated/tests.json.template @@ -11,7 +11,7 @@ "gtest": tgt.gtest, "exclude_configs": tgt.get("exclude_configs", []), "exclude_iomgrs": tgt.get("exclude_iomgrs", []), - "args": [], + "args": tgt.get("args", []), "flaky": tgt.flaky, "cpu_cost": tgt.get("cpu_cost", 1.0)} for tgt in targets diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c index efa4ad7ee6..057b90ec84 100644 --- a/test/core/client_channel/lb_policies_test.c +++ b/test/core/client_channel/lb_policies_test.c @@ -517,7 +517,7 @@ static grpc_channel *create_client(const servers_fixture *f) { grpc_channel *client; char *client_hostport; char *servers_hostports_str; - grpc_arg arg_array[2]; + grpc_arg arg_array[3]; grpc_channel_args args; servers_hostports_str = gpr_strjoin_sep((const char **)f->servers_hostports, @@ -530,7 +530,10 @@ static grpc_channel *create_client(const servers_fixture *f) { arg_array[1].type = GRPC_ARG_STRING; arg_array[1].key = GRPC_ARG_LB_POLICY_NAME; arg_array[1].value.string = "ROUND_ROBIN"; - args.num_args = 2; + arg_array[2].type = GRPC_ARG_INTEGER; + arg_array[2].key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS; + arg_array[2].value.integer = 0; + args.num_args = GPR_ARRAY_SIZE(arg_array); args.args = arg_array; client = grpc_insecure_channel_create(client_hostport, &args, NULL); diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c index d5f428eb82..42d960c428 100644 --- a/test/core/end2end/bad_server_response_test.c +++ b/test/core/end2end/bad_server_response_test.c @@ -135,7 +135,7 @@ static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { gpr_log(GPR_DEBUG, "got %" PRIuPTR " bytes, expected %" PRIuPTR " bytes", state.incoming_data_length, EXPECTED_INCOMING_DATA_LENGTH); - if (state.incoming_data_length > EXPECTED_INCOMING_DATA_LENGTH) { + if (state.incoming_data_length >= EXPECTED_INCOMING_DATA_LENGTH) { handle_write(exec_ctx); } else { grpc_endpoint_read(exec_ctx, state.tcp, &state.temp_incoming_buffer, diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c index 61f4337f2f..f5bfac2255 100644 --- a/test/core/end2end/tests/ping.c +++ b/test/core/end2end/tests/ping.c @@ -37,6 +37,7 @@ #include <grpc/support/sync.h> #include <grpc/support/thd.h> #include <grpc/support/time.h> +#include <grpc/support/useful.h> #include "test/core/end2end/cq_verifier.h" @@ -48,7 +49,15 @@ static void test_ping(grpc_end2end_test_config config) { grpc_connectivity_state state = GRPC_CHANNEL_IDLE; int i; - config.init_client(&f, NULL); + grpc_arg a[] = {{.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS, + .value.integer = 0}, + {.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, + .value.integer = 20}}; + grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(a), .args = a}; + + config.init_client(&f, &client_args); config.init_server(&f, NULL); grpc_channel_ping(f.client, f.cq, tag(0), NULL); diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c index 3fbe0aa0d0..4f9ed7a3a1 100644 --- a/test/core/end2end/tests/resource_quota_server.c +++ b/test/core/end2end/tests/resource_quota_server.c @@ -160,6 +160,7 @@ void resource_quota_server(grpc_end2end_test_config config) { int pending_server_end_calls = 0; int cancelled_calls_on_client = 0; int cancelled_calls_on_server = 0; + int deadline_exceeded = 0; grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); @@ -247,6 +248,9 @@ void resource_quota_server(grpc_end2end_test_config config) { case GRPC_STATUS_RESOURCE_EXHAUSTED: cancelled_calls_on_client++; break; + case GRPC_STATUS_DEADLINE_EXCEEDED: + deadline_exceeded++; + break; case GRPC_STATUS_OK: break; default: @@ -343,20 +347,19 @@ void resource_quota_server(grpc_end2end_test_config config) { } } - gpr_log( - GPR_INFO, - "Done. %d total calls: %d cancelled at server, %d cancelled at client.", - NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client); - - /* The call may be cancelled after the server has sent its status but before - * the client has received it. This means that we should see strictly more - * failures on the client than on the server. */ - GPR_ASSERT(cancelled_calls_on_client >= cancelled_calls_on_server); + gpr_log(GPR_INFO, + "Done. %d total calls: %d cancelled at server, %d cancelled at " + "client, %d timed out.", + NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client, + deadline_exceeded); grpc_byte_buffer_destroy(request_payload); grpc_slice_unref(request_payload_slice); grpc_resource_quota_unref(resource_quota); + end_test(&f); + config.tear_down_data(&f); + free(client_calls); free(server_calls); free(initial_metadata_recv); @@ -367,9 +370,6 @@ void resource_quota_server(grpc_end2end_test_config config) { free(details); free(request_payload_recv); free(was_cancelled); - - end_test(&f); - config.tear_down_data(&f); } void resource_quota_server_pre_init(void) {} diff --git a/test/core/transport/bdp_estimator_test.c b/test/core/transport/bdp_estimator_test.c new file mode 100644 index 0000000000..f55a3ca643 --- /dev/null +++ b/test/core/transport/bdp_estimator_test.c @@ -0,0 +1,153 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/transport/bdp_estimator.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/support/string.h" +#include "test/core/util/test_config.h" + +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) { + GPR_ASSERT(grpc_bdp_estimator_add_incoming_bytes(estimator, 1234567) == true); + grpc_bdp_estimator_schedule_ping(estimator); + grpc_bdp_estimator_start_ping(estimator); + for (size_t i = 0; i < n; i++) { + GPR_ASSERT(grpc_bdp_estimator_add_incoming_bytes(estimator, samples[i]) == + false); + } + grpc_bdp_estimator_complete_ping(estimator); +} + +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"); + int min = INT_MAX; + int max = 65535; // Windows rand() has limited range, make sure the ASSERT + // passes + for (size_t i = 0; i < n; i++) { + int sample = rand(); + 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) <= 2 * next_pow_2(max)); + } + } +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + 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); + } + return 0; +} diff --git a/test/core/transport/pid_controller_test.c b/test/core/transport/pid_controller_test.c index 9614983b00..831343c815 100644 --- a/test/core/transport/pid_controller_test.c +++ b/test/core/transport/pid_controller_test.c @@ -33,6 +33,7 @@ #include "src/core/lib/transport/pid_controller.h" +#include <float.h> #include <math.h> #include <grpc/support/alloc.h> @@ -45,7 +46,14 @@ static void test_noop(void) { gpr_log(GPR_INFO, "test_noop"); grpc_pid_controller pid; - grpc_pid_controller_init(&pid, 1, 1, 1); + grpc_pid_controller_init( + &pid, (grpc_pid_controller_args){.gain_p = 1, + .gain_i = 1, + .gain_d = 1, + .initial_control_value = 1, + .min_control_value = DBL_MIN, + .max_control_value = DBL_MAX, + .integral_range = DBL_MAX}); } static void test_simple_convergence(double gain_p, double gain_i, double gain_d, @@ -55,16 +63,24 @@ static void test_simple_convergence(double gain_p, double gain_i, double gain_d, "start=%lf", gain_p, gain_i, gain_d, dt, set_point, start); grpc_pid_controller pid; - grpc_pid_controller_init(&pid, 0.2, 0.1, 0.1); + grpc_pid_controller_init( + &pid, (grpc_pid_controller_args){.gain_p = gain_p, + .gain_i = gain_i, + .gain_d = gain_d, + .initial_control_value = start, + .min_control_value = DBL_MIN, + .max_control_value = DBL_MAX, + .integral_range = DBL_MAX}); - double current = start; - - for (int i = 0; i < 1000; i++) { - current += grpc_pid_controller_update(&pid, set_point - current, 1); + for (int i = 0; i < 100000; i++) { + grpc_pid_controller_update(&pid, set_point - grpc_pid_controller_last(&pid), + 1); } - GPR_ASSERT(fabs(set_point - current) < 0.1); - GPR_ASSERT(fabs(pid.error_integral) < 0.1); + GPR_ASSERT(fabs(set_point - grpc_pid_controller_last(&pid)) < 0.1); + if (gain_i > 0) { + GPR_ASSERT(fabs(pid.error_integral) < 0.1); + } } int main(int argc, char **argv) { diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c index 4ff93005d7..1e82c737c6 100644 --- a/test/core/util/passthru_endpoint.c +++ b/test/core/util/passthru_endpoint.c @@ -152,7 +152,9 @@ static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { } static char *me_get_peer(grpc_endpoint *ep) { - return gpr_strdup("fake:mock_endpoint"); + passthru_endpoint *p = ((half *)ep)->parent; + return ((half *)ep) == &p->client ? gpr_strdup("fake:mock_client_endpoint") + : gpr_strdup("fake:mock_server_endpoint"); } static int me_get_fd(grpc_endpoint *ep) { return -1; } diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc new file mode 100644 index 0000000000..7a914c1547 --- /dev/null +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -0,0 +1,268 @@ +/* + * + * Copyright 2017, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc++/channel.h> +#include <grpc++/create_channel.h> +#include <grpc++/impl/grpc_library.h> +#include <grpc++/security/credentials.h> +#include <grpc++/security/server_credentials.h> +#include <grpc++/server.h> +#include <grpc++/server_builder.h> +#include <grpc/support/log.h> +#include <gtest/gtest.h> + +extern "C" { +#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/endpoint_pair.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/tcp_posix.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/surface/server.h" +#include "test/core/util/passthru_endpoint.h" +#include "test/core/util/port.h" +} +#include "src/cpp/client/create_channel_internal.h" +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/test_config.h" + +namespace grpc { +namespace testing { + +static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); } + +static void ApplyCommonServerBuilderConfig(ServerBuilder* b) { + b->SetMaxReceiveMessageSize(INT_MAX); + b->SetMaxSendMessageSize(INT_MAX); +} + +static void ApplyCommonChannelArguments(ChannelArguments* c) { + c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX); + c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX); +} + +static class InitializeStuff { + public: + InitializeStuff() { + init_lib_.init(); + rq_ = grpc_resource_quota_create("bm"); + } + + ~InitializeStuff() { init_lib_.shutdown(); } + + grpc_resource_quota* rq() { return rq_; } + + private: + internal::GrpcLibrary init_lib_; + grpc_resource_quota* rq_; +} initialize_stuff; + +class EndpointPairFixture { + public: + EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints) { + ServerBuilder b; + cq_ = b.AddCompletionQueue(true); + b.RegisterService(service); + ApplyCommonServerBuilderConfig(&b); + server_ = b.BuildAndStart(); + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + /* add server endpoint to server_ */ + { + const grpc_channel_args* server_args = + grpc_server_get_channel_args(server_->c_server()); + grpc_transport* transport = grpc_create_chttp2_transport( + &exec_ctx, server_args, endpoints.server, 0 /* is_client */); + + grpc_pollset** pollsets; + size_t num_pollsets = 0; + grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets); + + for (size_t i = 0; i < num_pollsets; i++) { + grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]); + } + + grpc_server_setup_transport(&exec_ctx, server_->c_server(), transport, + NULL, server_args); + grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL); + } + + /* create channel */ + { + ChannelArguments args; + args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority"); + ApplyCommonChannelArguments(&args); + + grpc_channel_args c_args = args.c_channel_args(); + grpc_transport* transport = + grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1); + GPR_ASSERT(transport); + grpc_channel* channel = grpc_channel_create( + &exec_ctx, "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport); + grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL); + + channel_ = CreateChannelInternal("", channel); + } + + grpc_exec_ctx_finish(&exec_ctx); + } + + virtual ~EndpointPairFixture() { + server_->Shutdown(); + cq_->Shutdown(); + void* tag; + bool ok; + while (cq_->Next(&tag, &ok)) { + } + } + + ServerCompletionQueue* cq() { return cq_.get(); } + std::shared_ptr<Channel> channel() { return channel_; } + + private: + std::unique_ptr<Server> server_; + std::unique_ptr<ServerCompletionQueue> cq_; + std::shared_ptr<Channel> channel_; +}; + +class InProcessCHTTP2 : public EndpointPairFixture { + public: + InProcessCHTTP2(Service* service) + : EndpointPairFixture(service, MakeEndpoints()) {} + + int writes_performed() const { return stats_.num_writes; } + + private: + grpc_passthru_endpoint_stats stats_; + + grpc_endpoint_pair MakeEndpoints() { + grpc_endpoint_pair p; + grpc_passthru_endpoint_create(&p.client, &p.server, initialize_stuff.rq(), + &stats_); + return p; + } +}; + +static double UnaryPingPong(int request_size, int response_size) { + const int kIterations = 10000; + + EchoTestService::AsyncService service; + std::unique_ptr<InProcessCHTTP2> fixture(new InProcessCHTTP2(&service)); + EchoRequest send_request; + EchoResponse send_response; + EchoResponse recv_response; + if (request_size > 0) { + send_request.set_message(std::string(request_size, 'a')); + } + if (response_size > 0) { + send_response.set_message(std::string(response_size, 'a')); + } + Status recv_status; + struct ServerEnv { + ServerContext ctx; + EchoRequest recv_request; + grpc::ServerAsyncResponseWriter<EchoResponse> response_writer; + ServerEnv() : response_writer(&ctx) {} + }; + uint8_t server_env_buffer[2 * sizeof(ServerEnv)]; + ServerEnv* server_env[2] = { + reinterpret_cast<ServerEnv*>(server_env_buffer), + reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))}; + new (server_env[0]) ServerEnv; + new (server_env[1]) ServerEnv; + service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request, + &server_env[0]->response_writer, fixture->cq(), + fixture->cq(), tag(0)); + service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request, + &server_env[1]->response_writer, fixture->cq(), + fixture->cq(), tag(1)); + std::unique_ptr<EchoTestService::Stub> stub( + EchoTestService::NewStub(fixture->channel())); + for (int iteration = 0; iteration < kIterations; iteration++) { + recv_response.Clear(); + ClientContext cli_ctx; + std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( + stub->AsyncEcho(&cli_ctx, send_request, fixture->cq())); + void* t; + bool ok; + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + GPR_ASSERT(ok); + GPR_ASSERT(t == tag(0) || t == tag(1)); + intptr_t slot = reinterpret_cast<intptr_t>(t); + ServerEnv* senv = server_env[slot]; + senv->response_writer.Finish(send_response, Status::OK, tag(3)); + response_reader->Finish(&recv_response, &recv_status, tag(4)); + for (int i = (1 << 3) | (1 << 4); i != 0;) { + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + GPR_ASSERT(ok); + int tagnum = (int)reinterpret_cast<intptr_t>(t); + GPR_ASSERT(i & (1 << tagnum)); + i -= 1 << tagnum; + } + GPR_ASSERT(recv_status.ok()); + + senv->~ServerEnv(); + senv = new (senv) ServerEnv(); + service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer, + fixture->cq(), fixture->cq(), tag(slot)); + } + + double writes_per_iteration = + (double)fixture->writes_performed() / (double)kIterations; + + fixture.reset(); + server_env[0]->~ServerEnv(); + server_env[1]->~ServerEnv(); + + return writes_per_iteration; +} + +TEST(WritesPerRpcTest, UnaryPingPong) { + EXPECT_LT(UnaryPingPong(0, 0), 2.05); + EXPECT_LT(UnaryPingPong(1, 0), 2.05); + EXPECT_LT(UnaryPingPong(0, 1), 2.05); + EXPECT_LT(UnaryPingPong(4096, 0), 2.2); + EXPECT_LT(UnaryPingPong(0, 4096), 2.2); +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index b1e61865e7..498416c64a 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -153,7 +153,6 @@ class SynchronousStreamingClient final : public SynchronousClient { if (*stream) { (*stream)->WritesDone(); Status s = (*stream)->Finish(); - EXPECT_TRUE(s.ok()); if (!s.ok()) { gpr_log(GPR_ERROR, "Stream %zu received an error %s", i, s.error_message().c_str()); @@ -173,7 +172,11 @@ class SynchronousStreamingClient final : public SynchronousClient { entry->set_value((UsageTimer::Now() - start) * 1e9); return true; } - return false; + auto* stub = channels_[thread_idx % channels_.size()].get_stub(); + context_[thread_idx].~ClientContext(); + new (&context_[thread_idx]) ClientContext(); + stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]); + return true; } private: diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 8382695f66..285b7dd321 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1301,6 +1301,8 @@ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/validate_metadata.h \ src/core/lib/surface/version.c \ src/core/lib/transport/README.md \ +src/core/lib/transport/bdp_estimator.c \ +src/core/lib/transport/bdp_estimator.h \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/byte_stream.h \ src/core/lib/transport/connectivity_state.c \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 8a9bedc94f..52d8ae183b 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -104,6 +104,23 @@ }, { "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" ], @@ -3447,6 +3464,25 @@ { "deps": [ "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc++_test_util", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "writes_per_rpc_test", + "src": [ + "test/cpp/performance/writes_per_rpc_test.cc" + ], + "third_party": false, + "type": "target" + }, + { + "deps": [ + "gpr", "grpc" ], "headers": [], @@ -7096,6 +7132,7 @@ "src/core/lib/surface/lame_client.h", "src/core/lib/surface/server.h", "src/core/lib/surface/validate_metadata.h", + "src/core/lib/transport/bdp_estimator.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", "src/core/lib/transport/error_utils.h", @@ -7320,6 +7357,8 @@ "src/core/lib/surface/validate_metadata.c", "src/core/lib/surface/validate_metadata.h", "src/core/lib/surface/version.c", + "src/core/lib/transport/bdp_estimator.c", + "src/core/lib/transport/bdp_estimator.h", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.c", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 972f61561f..4cc543962e 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -127,6 +127,28 @@ "flaky": false, "gtest": false, "language": "c", + "name": "bdp_estimator_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", "name": "bin_decoder_test", "platforms": [ "linux", @@ -2430,7 +2452,9 @@ ] }, { - "args": [], + "args": [ + "--benchmark_min_time=0" + ], "ci_platforms": [ "linux", "mac", @@ -3212,6 +3236,26 @@ "ci_platforms": [ "linux", "mac", + "posix" + ], + "cpu_cost": 0.5, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "writes_per_rpc_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", "posix", "windows" ], diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index aa382154eb..ca7f969aa1 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -80,6 +80,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "badreq_bad_client_test", "v {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bdp_estimator_test", "vcxproj\test\bdp_estimator_test\bdp_estimator_test.vcxproj", "{56314C05-7748-B7FD-F9DE-F975A0275427}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin_decoder_test", "vcxproj\test\bin_decoder_test\bin_decoder_test.vcxproj", "{6BFAC6BA-3B9D-E8F5-BE35-91E8EFB9E25B}" ProjectSection(myProperties) = preProject lib = "False" @@ -1703,6 +1714,22 @@ Global {8A811C28-E04E-A444-E4C1-7588DF5B90AE}.Release-DLL|Win32.Build.0 = Release|Win32 {8A811C28-E04E-A444-E4C1-7588DF5B90AE}.Release-DLL|x64.ActiveCfg = Release|x64 {8A811C28-E04E-A444-E4C1-7588DF5B90AE}.Release-DLL|x64.Build.0 = Release|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug|Win32.ActiveCfg = Debug|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug|x64.ActiveCfg = Debug|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release|Win32.ActiveCfg = Release|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release|x64.ActiveCfg = Release|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug|Win32.Build.0 = Debug|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug|x64.Build.0 = Debug|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release|Win32.Build.0 = Release|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release|x64.Build.0 = Release|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Debug-DLL|x64.Build.0 = Debug|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release-DLL|Win32.Build.0 = Release|Win32 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release-DLL|x64.ActiveCfg = Release|x64 + {56314C05-7748-B7FD-F9DE-F975A0275427}.Release-DLL|x64.Build.0 = Release|x64 {6BFAC6BA-3B9D-E8F5-BE35-91E8EFB9E25B}.Debug|Win32.ActiveCfg = Debug|Win32 {6BFAC6BA-3B9D-E8F5-BE35-91E8EFB9E25B}.Debug|x64.ActiveCfg = Debug|x64 {6BFAC6BA-3B9D-E8F5-BE35-91E8EFB9E25B}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 13d825af68..c7aa771e5f 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -391,6 +391,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" /> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" /> @@ -701,6 +702,8 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c"> diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index de2e82173f..00aa8b2781 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -319,6 +319,9 @@ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> <Filter>src\core\lib\surface</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + <Filter>src\core\lib\transport</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> <Filter>src\core\lib\transport</Filter> </ClCompile> @@ -1037,6 +1040,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h"> <Filter>src\core\lib\surface</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h"> + <Filter>src\core\lib\transport</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h"> <Filter>src\core\lib\transport</Filter> </ClInclude> diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj index 98f73b76bf..57cbb2c496 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj @@ -285,6 +285,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" /> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" /> @@ -552,6 +553,8 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c"> diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters index d88585d002..620649a06c 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters @@ -379,6 +379,9 @@ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> <Filter>src\core\lib\surface</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + <Filter>src\core\lib\transport</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> <Filter>src\core\lib\transport</Filter> </ClCompile> @@ -827,6 +830,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h"> <Filter>src\core\lib\surface</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h"> + <Filter>src\core\lib\transport</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h"> <Filter>src\core\lib\transport</Filter> </ClInclude> diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 826c06576e..f2c9d1ae03 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -381,6 +381,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" /> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" /> @@ -669,6 +670,8 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c"> diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 06ddac9de7..d3117bd272 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -322,6 +322,9 @@ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c"> <Filter>src\core\lib\surface</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c"> + <Filter>src\core\lib\transport</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c"> <Filter>src\core\lib\transport</Filter> </ClCompile> @@ -950,6 +953,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h"> <Filter>src\core\lib\surface</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h"> + <Filter>src\core\lib\transport</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h"> <Filter>src\core\lib\transport</Filter> </ClInclude> diff --git a/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj b/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj new file mode 100644 index 0000000000..e37d7b9848 --- /dev/null +++ b/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{56314C05-7748-B7FD-F9DE-F975A0275427}</ProjectGuid> + <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected> + <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration"> + <PlatformToolset>v100</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration"> + <PlatformToolset>v110</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration"> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration"> + <PlatformToolset>v140</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(SolutionDir)\..\vsprojects\global.props" /> + <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" /> + <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" /> + <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)'=='Debug'"> + <TargetName>bdp_estimator_test</TargetName> + <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> + <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib> + <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl> + <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'"> + <TargetName>bdp_estimator_test</TargetName> + <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> + <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib> + <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl> + <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> + <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> + <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> + <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> + <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> + <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> + <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> + <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> + <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + + <ItemGroup> + <ClCompile Include="$(SolutionDir)\..\test\core\transport\bdp_estimator_test.c"> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj"> + <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project> + </ProjectReference> + <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj"> + <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project> + </ProjectReference> + <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj"> + <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project> + </ProjectReference> + <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj"> + <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> + <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> + <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> + <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" /> + <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" /> + <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" /> + <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" /> + <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" /> + </Target> +</Project> + diff --git a/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj.filters b/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj.filters new file mode 100644 index 0000000000..e45ccf8444 --- /dev/null +++ b/vsprojects/vcxproj/test/bdp_estimator_test/bdp_estimator_test.vcxproj.filters @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="$(SolutionDir)\..\test\core\transport\bdp_estimator_test.c"> + <Filter>test\core\transport</Filter> + </ClCompile> + </ItemGroup> + + <ItemGroup> + <Filter Include="test"> + <UniqueIdentifier>{1b8a7ad9-0b72-aa3d-2dc8-80ad82788751}</UniqueIdentifier> + </Filter> + <Filter Include="test\core"> + <UniqueIdentifier>{f503dc16-2668-27d5-0d1d-d32667aec533}</UniqueIdentifier> + </Filter> + <Filter Include="test\core\transport"> + <UniqueIdentifier>{0880eed5-543c-6ede-ac40-270a662f2563}</UniqueIdentifier> + </Filter> + </ItemGroup> +</Project> + |