Merge github.com:grpc/grpc into new_transport_op

reviewable/pr9949/r2
Craig Tiller 8 years ago
commit 84a2ac885c
  1. 2
      BUILD
  2. 9
      CMakeLists.txt
  3. 6
      INSTALL.md
  4. 123
      Makefile
  5. 1
      binding.gyp
  6. 5
      build.yaml
  7. 1
      config.m4
  8. 3
      gRPC-Core.podspec
  9. 2
      grpc.gemspec
  10. 26
      include/grpc++/impl/codegen/grpc_library.h
  11. 1
      include/grpc++/impl/codegen/server_context.h
  12. 9
      include/grpc/impl/codegen/grpc_types.h
  13. 2
      package.xml
  14. 2
      src/core/lib/channel/http_server_filter.c
  15. 386
      src/core/lib/channel/max_age_filter.c
  16. 39
      src/core/lib/channel/max_age_filter.h
  17. 4
      src/core/lib/surface/init.c
  18. 7
      src/cpp/common/completion_queue_cc.cc
  19. 1
      src/cpp/server/server_context.cc
  20. 9
      src/objective-c/tests/build_example_test.sh
  21. 1
      src/objective-c/tests/build_tests.sh
  22. 6
      src/objective-c/tests/run_tests.sh
  23. 1
      src/python/grpcio/grpc_core_dependencies.py
  24. 16601
      tags
  25. 4
      templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
  26. 16
      test/core/end2end/end2end_nosec_tests.c
  27. 16
      test/core/end2end/end2end_tests.c
  28. BIN
      test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-5417405008314368
  29. 3
      test/core/end2end/gen_build_yaml.py
  30. 2
      test/core/end2end/generate_tests.bzl
  31. 383
      test/core/end2end/tests/max_connection_age.c
  32. 117
      test/core/end2end/tests/max_connection_idle.c
  33. 2
      test/cpp/microbenchmarks/bm_chttp2_hpack.cc
  34. 11
      test/cpp/microbenchmarks/bm_cq.cc
  35. 3
      tools/README.md
  36. 4
      tools/dockerfile/test/multilang_jessie_x64/Dockerfile
  37. 2
      tools/doxygen/Doxyfile.core.internal
  38. 2
      tools/gce/linux_performance_worker_init.sh
  39. 4
      tools/jenkins/run_performance.sh
  40. 243
      tools/profiling/microbenchmarks/bm_diff.py
  41. 4
      tools/profiling/microbenchmarks/bm_json.py
  42. 51
      tools/run_tests/generated/configs.json
  43. 7
      tools/run_tests/generated/sources_and_headers.json
  44. 1681
      tools/run_tests/generated/tests.json
  45. 2
      tools/run_tests/helper_scripts/post_tests_php.sh
  46. 20
      tools/run_tests/helper_scripts/post_tests_python.sh
  47. 106
      tools/run_tests/performance/README.md
  48. 23
      tools/run_tests/performance/scenario_config.py
  49. 49
      tools/run_tests/python_utils/comment_on_pr.py
  50. 38
      tools/run_tests/run_microbenchmark.py
  51. 9
      tools/run_tests/run_tests.py
  52. 3
      vsprojects/vcxproj/grpc/grpc.vcxproj
  53. 6
      vsprojects/vcxproj/grpc/grpc.vcxproj.filters
  54. 3
      vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
  55. 6
      vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
  56. 3
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
  57. 6
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
  58. 4
      vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
  59. 6
      vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
  60. 4
      vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
  61. 6
      vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters

@ -437,6 +437,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.c",
"src/core/lib/channel/http_client_filter.c",
"src/core/lib/channel/http_server_filter.c",
"src/core/lib/channel/max_age_filter.c",
"src/core/lib/channel/message_size_filter.c",
"src/core/lib/compression/compression.c",
"src/core/lib/compression/message_compress.c",
@ -564,6 +565,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/channel/http_client_filter.h",
"src/core/lib/channel/http_server_filter.h",
"src/core/lib/channel/max_age_filter.h",
"src/core/lib/channel/message_size_filter.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/message_compress.h",

@ -919,6 +919,7 @@ add_library(grpc
src/core/lib/channel/handshaker_registry.c
src/core/lib/channel/http_client_filter.c
src/core/lib/channel/http_server_filter.c
src/core/lib/channel/max_age_filter.c
src/core/lib/channel/message_size_filter.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
@ -1240,6 +1241,7 @@ add_library(grpc_cronet
src/core/lib/channel/handshaker_registry.c
src/core/lib/channel/http_client_filter.c
src/core/lib/channel/http_server_filter.c
src/core/lib/channel/max_age_filter.c
src/core/lib/channel/message_size_filter.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
@ -1548,6 +1550,7 @@ add_library(grpc_test_util
src/core/lib/channel/handshaker_registry.c
src/core/lib/channel/http_client_filter.c
src/core/lib/channel/http_server_filter.c
src/core/lib/channel/max_age_filter.c
src/core/lib/channel/message_size_filter.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
@ -1808,6 +1811,7 @@ add_library(grpc_unsecure
src/core/lib/channel/handshaker_registry.c
src/core/lib/channel/http_client_filter.c
src/core/lib/channel/http_server_filter.c
src/core/lib/channel/max_age_filter.c
src/core/lib/channel/message_size_filter.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
@ -2439,6 +2443,7 @@ add_library(grpc++_cronet
src/core/lib/channel/handshaker_registry.c
src/core/lib/channel/http_client_filter.c
src/core/lib/channel/http_server_filter.c
src/core/lib/channel/max_age_filter.c
src/core/lib/channel/message_size_filter.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
@ -4135,6 +4140,8 @@ add_library(end2end_tests
test/core/end2end/tests/large_metadata.c
test/core/end2end/tests/load_reporting_hook.c
test/core/end2end/tests/max_concurrent_streams.c
test/core/end2end/tests/max_connection_age.c
test/core/end2end/tests/max_connection_idle.c
test/core/end2end/tests/max_message_length.c
test/core/end2end/tests/negative_deadline.c
test/core/end2end/tests/network_status_change.c
@ -4229,6 +4236,8 @@ add_library(end2end_nosec_tests
test/core/end2end/tests/large_metadata.c
test/core/end2end/tests/load_reporting_hook.c
test/core/end2end/tests/max_concurrent_streams.c
test/core/end2end/tests/max_connection_age.c
test/core/end2end/tests/max_connection_idle.c
test/core/end2end/tests/max_message_length.c
test/core/end2end/tests/negative_deadline.c
test/core/end2end/tests/network_status_change.c

@ -22,6 +22,12 @@ refer to these documents
$ [sudo] apt-get install build-essential autoconf libtool
```
If you plan to build from source and run tests, install the following as well:
```sh
$ [sudo] apt-get install libgflags-dev libgtest-dev
$ [sudo] apt-get install clang libc++-dev
```
## Mac OSX
For a Mac system, git is not available by default. You will first need to

@ -95,6 +95,42 @@ LDXX_opt = $(DEFAULT_CXX)
CPPFLAGS_opt = -O2
DEFINES_opt = NDEBUG
VALID_CONFIG_asan-trace-cmp = 1
REQUIRE_CUSTOM_LIBRARIES_asan-trace-cmp = 1
CC_asan-trace-cmp = clang
CXX_asan-trace-cmp = clang++
LD_asan-trace-cmp = clang
LDXX_asan-trace-cmp = clang++
CPPFLAGS_asan-trace-cmp = -O0 -fsanitize-coverage=edge -fsanitize-coverage=trace-cmp -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_asan-trace-cmp = -fsanitize=address
VALID_CONFIG_dbg = 1
CC_dbg = $(DEFAULT_CC)
CXX_dbg = $(DEFAULT_CXX)
LD_dbg = $(DEFAULT_CC)
LDXX_dbg = $(DEFAULT_CXX)
CPPFLAGS_dbg = -O0
DEFINES_dbg = _DEBUG DEBUG
VALID_CONFIG_asan = 1
REQUIRE_CUSTOM_LIBRARIES_asan = 1
CC_asan = clang
CXX_asan = clang++
LD_asan = clang
LDXX_asan = clang++
CPPFLAGS_asan = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_asan = -fsanitize=address
VALID_CONFIG_msan = 1
REQUIRE_CUSTOM_LIBRARIES_msan = 1
CC_msan = clang
CXX_msan = clang++
LD_msan = clang
LDXX_msan = clang++
CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
DEFINES_msan = NDEBUG
VALID_CONFIG_basicprof = 1
CC_basicprof = $(DEFAULT_CC)
CXX_basicprof = $(DEFAULT_CXX)
@ -121,22 +157,25 @@ LDXX_asan-noleaks = clang++
CPPFLAGS_asan-noleaks = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_asan-noleaks = -fsanitize=address
VALID_CONFIG_asan-trace-cmp = 1
REQUIRE_CUSTOM_LIBRARIES_asan-trace-cmp = 1
CC_asan-trace-cmp = clang
CXX_asan-trace-cmp = clang++
LD_asan-trace-cmp = clang
LDXX_asan-trace-cmp = clang++
CPPFLAGS_asan-trace-cmp = -O0 -fsanitize-coverage=edge -fsanitize-coverage=trace-cmp -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_asan-trace-cmp = -fsanitize=address
VALID_CONFIG_ubsan = 1
REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
CC_ubsan = clang
CXX_ubsan = clang++
LD_ubsan = clang
LDXX_ubsan = clang++
CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs
LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow
DEFINES_ubsan = NDEBUG
VALID_CONFIG_dbg = 1
CC_dbg = $(DEFAULT_CC)
CXX_dbg = $(DEFAULT_CXX)
LD_dbg = $(DEFAULT_CC)
LDXX_dbg = $(DEFAULT_CXX)
CPPFLAGS_dbg = -O0
DEFINES_dbg = _DEBUG DEBUG
VALID_CONFIG_tsan = 1
REQUIRE_CUSTOM_LIBRARIES_tsan = 1
CC_tsan = clang
CXX_tsan = clang++
LD_tsan = clang
LDXX_tsan = clang++
CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_tsan = -fsanitize=thread
DEFINES_tsan = GRPC_TSAN
VALID_CONFIG_stapprof = 1
CC_stapprof = $(DEFAULT_CC)
@ -164,44 +203,13 @@ CPPFLAGS_memcheck = -O0
LDFLAGS_memcheck = -rdynamic
DEFINES_memcheck = _DEBUG DEBUG
VALID_CONFIG_asan = 1
REQUIRE_CUSTOM_LIBRARIES_asan = 1
CC_asan = clang
CXX_asan = clang++
LD_asan = clang
LDXX_asan = clang++
CPPFLAGS_asan = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_asan = -fsanitize=address
VALID_CONFIG_tsan = 1
REQUIRE_CUSTOM_LIBRARIES_tsan = 1
CC_tsan = clang
CXX_tsan = clang++
LD_tsan = clang
LDXX_tsan = clang++
CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_tsan = -fsanitize=thread
DEFINES_tsan = GRPC_TSAN
VALID_CONFIG_ubsan = 1
REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
CC_ubsan = clang
CXX_ubsan = clang++
LD_ubsan = clang
LDXX_ubsan = clang++
CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs
LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow
DEFINES_ubsan = NDEBUG
VALID_CONFIG_msan = 1
REQUIRE_CUSTOM_LIBRARIES_msan = 1
CC_msan = clang
CXX_msan = clang++
LD_msan = clang
LDXX_msan = clang++
CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
DEFINES_msan = NDEBUG
VALID_CONFIG_lto = 1
CC_lto = $(DEFAULT_CC)
CXX_lto = $(DEFAULT_CXX)
LD_lto = $(DEFAULT_CC)
LDXX_lto = $(DEFAULT_CXX)
CPPFLAGS_lto = -O2
DEFINES_lto = NDEBUG
VALID_CONFIG_mutrace = 1
CC_mutrace = $(DEFAULT_CC)
@ -2813,6 +2821,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
@ -3132,6 +3141,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
@ -3439,6 +3449,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
@ -3671,6 +3682,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
@ -4288,6 +4300,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
@ -7963,6 +7976,8 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/tests/large_metadata.c \
test/core/end2end/tests/load_reporting_hook.c \
test/core/end2end/tests/max_concurrent_streams.c \
test/core/end2end/tests/max_connection_age.c \
test/core/end2end/tests/max_connection_idle.c \
test/core/end2end/tests/max_message_length.c \
test/core/end2end/tests/negative_deadline.c \
test/core/end2end/tests/network_status_change.c \
@ -8052,6 +8067,8 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/tests/large_metadata.c \
test/core/end2end/tests/load_reporting_hook.c \
test/core/end2end/tests/max_concurrent_streams.c \
test/core/end2end/tests/max_connection_age.c \
test/core/end2end/tests/max_connection_idle.c \
test/core/end2end/tests/max_message_length.c \
test/core/end2end/tests/negative_deadline.c \
test/core/end2end/tests/network_status_change.c \

@ -626,6 +626,7 @@
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/channel/http_client_filter.c',
'src/core/lib/channel/http_server_filter.c',
'src/core/lib/channel/max_age_filter.c',
'src/core/lib/channel/message_size_filter.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',

@ -186,6 +186,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.h
- src/core/lib/channel/http_client_filter.h
- src/core/lib/channel/http_server_filter.h
- src/core/lib/channel/max_age_filter.h
- src/core/lib/channel/message_size_filter.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/message_compress.h
@ -295,6 +296,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.c
- src/core/lib/channel/http_client_filter.c
- src/core/lib/channel/http_server_filter.c
- src/core/lib/channel/max_age_filter.c
- src/core/lib/channel/message_size_filter.c
- src/core/lib/compression/compression.c
- src/core/lib/compression/message_compress.c
@ -4287,6 +4289,9 @@ configs:
DEFINES: _DEBUG DEBUG
LDFLAGS: -rdynamic
valgrind: --tool=helgrind
lto:
CPPFLAGS: -O2
DEFINES: NDEBUG
memcheck:
CPPFLAGS: -O0
DEFINES: _DEBUG DEBUG

@ -94,6 +94,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/handshaker_registry.c \
src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/message_size_filter.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \

@ -268,6 +268,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/http_client_filter.h',
'src/core/lib/channel/http_server_filter.h',
'src/core/lib/channel/max_age_filter.h',
'src/core/lib/channel/message_size_filter.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/message_compress.h',
@ -469,6 +470,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/channel/http_client_filter.c',
'src/core/lib/channel/http_server_filter.c',
'src/core/lib/channel/max_age_filter.c',
'src/core/lib/channel/message_size_filter.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
@ -716,6 +718,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/http_client_filter.h',
'src/core/lib/channel/http_server_filter.h',
'src/core/lib/channel/max_age_filter.h',
'src/core/lib/channel/message_size_filter.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/message_compress.h',

@ -184,6 +184,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.h )
s.files += %w( src/core/lib/channel/http_client_filter.h )
s.files += %w( src/core/lib/channel/http_server_filter.h )
s.files += %w( src/core/lib/channel/max_age_filter.h )
s.files += %w( src/core/lib/channel/message_size_filter.h )
s.files += %w( src/core/lib/compression/algorithm_metadata.h )
s.files += %w( src/core/lib/compression/message_compress.h )
@ -385,6 +386,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.c )
s.files += %w( src/core/lib/channel/http_client_filter.c )
s.files += %w( src/core/lib/channel/http_server_filter.c )
s.files += %w( src/core/lib/channel/max_age_filter.c )
s.files += %w( src/core/lib/channel/message_size_filter.c )
s.files += %w( src/core/lib/compression/compression.c )
s.files += %w( src/core/lib/compression/message_compress.c )

@ -51,18 +51,26 @@ extern GrpcLibraryInterface* g_glip;
/// Classes that require gRPC to be initialized should inherit from this class.
class GrpcLibraryCodegen {
public:
GrpcLibraryCodegen() {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->init();
GrpcLibraryCodegen(bool call_grpc_init = true) : grpc_init_called_(false) {
if (call_grpc_init) {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->init();
grpc_init_called_ = true;
}
}
virtual ~GrpcLibraryCodegen() {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->shutdown();
if (grpc_init_called_) {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->shutdown();
}
}
private:
bool grpc_init_called_;
};
} // namespace grpc

@ -39,7 +39,6 @@
#include <vector>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/load_reporting.h>
#include <grpc++/impl/codegen/config.h>
#include <grpc++/impl/codegen/create_auth_context.h>

@ -163,6 +163,15 @@ typedef struct {
/** Maximum message length that the channel can send. Int valued, bytes.
-1 means unlimited. */
#define GRPC_ARG_MAX_SEND_MESSAGE_LENGTH "grpc.max_send_message_length"
/** Maximum time that a channel may have no outstanding rpcs. Int valued,
milliseconds. INT_MAX means unlimited. */
#define GRPC_ARG_MAX_CONNECTION_IDLE_MS "grpc.max_connection_idle_ms"
/** Maximum time that a channel may exist. Int valued, milliseconds. INT_MAX
means unlimited. */
#define GRPC_ARG_MAX_CONNECTION_AGE_MS "grpc.max_connection_age_ms"
/** Grace period after the chennel reaches its max age. Int valued,
milliseconds. INT_MAX means unlimited. */
#define GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS "grpc.max_connection_age_grace_ms"
/** Initial sequence number for http2 transports. Int valued. */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"

@ -193,6 +193,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/max_age_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
@ -394,6 +395,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/max_age_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.c" role="src" />

@ -222,7 +222,7 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
size_t path_length = GRPC_SLICE_LENGTH(path_slice);
/* offset of the character '?' */
size_t offset = 0;
for (offset = 0; *path_ptr != k_query_separator && offset < path_length;
for (offset = 0; offset < path_length && *path_ptr != k_query_separator;
path_ptr++, offset++)
;
if (offset < path_length) {

@ -0,0 +1,386 @@
/*
*
* 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 "src/core/lib/channel/message_size_filter.h"
#include <limits.h>
#include <string.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/transport/http2_errors.h"
#include "src/core/lib/transport/service_config.h"
#define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX
#define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX
#define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX
typedef struct channel_data {
/* We take a reference to the channel stack for the timer callback */
grpc_channel_stack* channel_stack;
/* Guards access to max_age_timer, max_age_timer_pending, max_age_grace_timer
and max_age_grace_timer_pending */
gpr_mu max_age_timer_mu;
/* True if the max_age timer callback is currently pending */
bool max_age_timer_pending;
/* True if the max_age_grace timer callback is currently pending */
bool max_age_grace_timer_pending;
/* The timer for checking if the channel has reached its max age */
grpc_timer max_age_timer;
/* The timer for checking if the max-aged channel has uesed up the grace
period */
grpc_timer max_age_grace_timer;
/* The timer for checking if the channel's idle duration reaches
max_connection_idle */
grpc_timer max_idle_timer;
/* Allowed max time a channel may have no outstanding rpcs */
gpr_timespec max_connection_idle;
/* Allowed max time a channel may exist */
gpr_timespec max_connection_age;
/* Allowed grace period after the channel reaches its max age */
gpr_timespec max_connection_age_grace;
/* Closure to run when the channel's idle duration reaches max_connection_idle
and should be closed gracefully */
grpc_closure close_max_idle_channel;
/* Closure to run when the channel reaches its max age and should be closed
gracefully */
grpc_closure close_max_age_channel;
/* Closure to run the channel uses up its max age grace time and should be
closed forcibly */
grpc_closure force_close_max_age_channel;
/* Closure to run when the init fo channel stack is done and the max_idle
timer should be started */
grpc_closure start_max_idle_timer_after_init;
/* Closure to run when the init fo channel stack is done and the max_age timer
should be started */
grpc_closure start_max_age_timer_after_init;
/* Closure to run when the goaway op is finished and the max_age_timer */
grpc_closure start_max_age_grace_timer_after_goaway_op;
/* Closure to run when the channel connectivity state changes */
grpc_closure channel_connectivity_changed;
/* Records the current connectivity state */
grpc_connectivity_state connectivity_state;
/* Number of active calls */
gpr_atm call_count;
} channel_data;
/* Increase the nubmer of active calls. Before the increasement, if there are no
calls, the max_idle_timer should be cancelled. */
static void increase_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) {
if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) {
grpc_timer_cancel(exec_ctx, &chand->max_idle_timer);
}
}
/* Decrease the nubmer of active calls. After the decrement, if there are no
calls, the max_idle_timer should be started. */
static void decrease_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) {
if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_idle_timer");
grpc_timer_init(
exec_ctx, &chand->max_idle_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_idle),
&chand->close_max_idle_channel, gpr_now(GPR_CLOCK_MONOTONIC));
}
}
static void start_max_idle_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
/* Decrease call_count. If there are no active calls at this time,
max_idle_timer will start here. If the number of active calls is not 0,
max_idle_timer will start after all the active calls end. */
decrease_call_count(exec_ctx, chand);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age start_max_idle_timer_after_init");
}
static void start_max_age_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_mu_lock(&chand->max_age_timer_mu);
chand->max_age_timer_pending = true;
GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
grpc_timer_init(
exec_ctx, &chand->max_age_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_age),
&chand->close_max_age_channel, gpr_now(GPR_CLOCK_MONOTONIC));
gpr_mu_unlock(&chand->max_age_timer_mu);
grpc_transport_op* op = grpc_make_transport_op(NULL);
op->on_connectivity_state_change = &chand->channel_connectivity_changed,
op->connectivity_state = &chand->connectivity_state;
grpc_channel_next_op(exec_ctx,
grpc_channel_stack_element(chand->channel_stack, 0), op);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age start_max_age_timer_after_init");
}
static void start_max_age_grace_timer_after_goaway_op(grpc_exec_ctx* exec_ctx,
void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_mu_lock(&chand->max_age_timer_mu);
chand->max_age_grace_timer_pending = true;
GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
grpc_timer_init(exec_ctx, &chand->max_age_grace_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
chand->max_connection_age_grace),
&chand->force_close_max_age_channel,
gpr_now(GPR_CLOCK_MONOTONIC));
gpr_mu_unlock(&chand->max_age_timer_mu);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age start_max_age_grace_timer_after_goaway_op");
}
static void close_max_idle_channel(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
if (error == GRPC_ERROR_NONE) {
grpc_transport_op* op = grpc_make_transport_op(NULL);
op->goaway_error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
grpc_channel_element* elem =
grpc_channel_stack_element(chand->channel_stack, 0);
elem->filter->start_transport_op(exec_ctx, elem, op);
} else if (error != GRPC_ERROR_CANCELLED) {
GRPC_LOG_IF_ERROR("close_max_idle_channel", error);
}
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age max_idle_timer");
}
static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_mu_lock(&chand->max_age_timer_mu);
chand->max_age_timer_pending = false;
gpr_mu_unlock(&chand->max_age_timer_mu);
if (error == GRPC_ERROR_NONE) {
GRPC_CHANNEL_STACK_REF(chand->channel_stack,
"max_age start_max_age_grace_timer_after_goaway_op");
grpc_transport_op* op = grpc_make_transport_op(
&chand->start_max_age_grace_timer_after_goaway_op);
op->goaway_error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_age"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
grpc_channel_element* elem =
grpc_channel_stack_element(chand->channel_stack, 0);
elem->filter->start_transport_op(exec_ctx, elem, op);
} else if (error != GRPC_ERROR_CANCELLED) {
GRPC_LOG_IF_ERROR("close_max_age_channel", error);
}
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age max_age_timer");
}
static void force_close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_mu_lock(&chand->max_age_timer_mu);
chand->max_age_grace_timer_pending = false;
gpr_mu_unlock(&chand->max_age_timer_mu);
if (error == GRPC_ERROR_NONE) {
grpc_transport_op* op = grpc_make_transport_op(NULL);
op->disconnect_with_error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel reaches max age");
grpc_channel_element* elem =
grpc_channel_stack_element(chand->channel_stack, 0);
elem->filter->start_transport_op(exec_ctx, elem, op);
} else if (error != GRPC_ERROR_CANCELLED) {
GRPC_LOG_IF_ERROR("force_close_max_age_channel", error);
}
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age max_age_grace_timer");
}
static void channel_connectivity_changed(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
grpc_transport_op* op = grpc_make_transport_op(NULL);
op->on_connectivity_state_change = &chand->channel_connectivity_changed,
op->connectivity_state = &chand->connectivity_state;
grpc_channel_next_op(
exec_ctx, grpc_channel_stack_element(chand->channel_stack, 0), op);
} else {
gpr_mu_lock(&chand->max_age_timer_mu);
if (chand->max_age_timer_pending) {
grpc_timer_cancel(exec_ctx, &chand->max_age_timer);
chand->max_age_timer_pending = false;
}
if (chand->max_age_grace_timer_pending) {
grpc_timer_cancel(exec_ctx, &chand->max_age_grace_timer);
chand->max_age_grace_timer_pending = false;
}
gpr_mu_unlock(&chand->max_age_timer_mu);
/* If there are no active calls, this increasement will cancel
max_idle_timer, and prevent max_idle_timer from being started in the
future. */
increase_call_count(exec_ctx, chand);
}
}
/* Constructor for call_data. */
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
const grpc_call_element_args* args) {
channel_data* chand = elem->channel_data;
increase_call_count(exec_ctx, chand);
return GRPC_ERROR_NONE;
}
/* Destructor for call_data. */
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
channel_data* chand = elem->channel_data;
decrease_call_count(exec_ctx, chand);
}
/* Constructor for channel_data. */
static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_element* elem,
grpc_channel_element_args* args) {
channel_data* chand = elem->channel_data;
gpr_mu_init(&chand->max_age_timer_mu);
chand->max_age_timer_pending = false;
chand->max_age_grace_timer_pending = false;
chand->channel_stack = args->channel_stack;
chand->max_connection_age =
DEFAULT_MAX_CONNECTION_AGE_MS == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_MS, GPR_TIMESPAN);
chand->max_connection_age_grace =
DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_GRACE_MS,
GPR_TIMESPAN);
chand->max_connection_idle =
DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(DEFAULT_MAX_CONNECTION_IDLE_MS, GPR_TIMESPAN);
for (size_t i = 0; i < args->channel_args->num_args; ++i) {
if (0 == strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
const int value = grpc_channel_arg_get_integer(
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX});
chand->max_connection_age =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(value, GPR_TIMESPAN);
} else if (0 == strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) {
const int value = grpc_channel_arg_get_integer(
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_GRACE_MS, 0,
INT_MAX});
chand->max_connection_age_grace =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(value, GPR_TIMESPAN);
} else if (0 == strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_CONNECTION_IDLE_MS)) {
const int value = grpc_channel_arg_get_integer(
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX});
chand->max_connection_idle =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(value, GPR_TIMESPAN);
}
}
grpc_closure_init(&chand->close_max_idle_channel, close_max_idle_channel,
chand, grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->close_max_age_channel, close_max_age_channel, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->force_close_max_age_channel,
force_close_max_age_channel, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->start_max_idle_timer_after_init,
start_max_idle_timer_after_init, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->start_max_age_timer_after_init,
start_max_age_timer_after_init, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->start_max_age_grace_timer_after_goaway_op,
start_max_age_grace_timer_after_goaway_op, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->channel_connectivity_changed,
channel_connectivity_changed, chand,
grpc_schedule_on_exec_ctx);
if (gpr_time_cmp(chand->max_connection_age, gpr_inf_future(GPR_TIMESPAN)) !=
0) {
/* When the channel reaches its max age, we send down an op with
goaway_error set. However, we can't send down any ops until after the
channel stack is fully initialized. If we start the timer here, we have
no guarantee that the timer won't pop before channel stack initialization
is finished. To avoid that problem, we create a closure to start the
timer, and we schedule that closure to be run after call stack
initialization is done. */
GRPC_CHANNEL_STACK_REF(chand->channel_stack,
"max_age start_max_age_timer_after_init");
grpc_closure_sched(exec_ctx, &chand->start_max_age_timer_after_init,
GRPC_ERROR_NONE);
}
/* Initialize the number of calls as 1, so that the max_idle_timer will not
start until start_max_idle_timer_after_init is invoked. */
gpr_atm_rel_store(&chand->call_count, 1);
if (gpr_time_cmp(chand->max_connection_idle, gpr_inf_future(GPR_TIMESPAN)) !=
0) {
GRPC_CHANNEL_STACK_REF(chand->channel_stack,
"max_age start_max_idle_timer_after_init");
grpc_closure_sched(exec_ctx, &chand->start_max_idle_timer_after_init,
GRPC_ERROR_NONE);
}
return GRPC_ERROR_NONE;
}
/* Destructor for channel_data. */
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_element* elem) {}
const grpc_channel_filter grpc_max_age_filter = {
grpc_call_next_op,
grpc_channel_next_op,
0, /* sizeof_call_data */
init_call_elem,
grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
grpc_channel_next_get_info,
"max_age"};

@ -0,0 +1,39 @@
//
// 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.
//
#ifndef GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H
#define GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H
#include "src/core/lib/channel/channel_stack.h"
extern const grpc_channel_filter grpc_max_age_filter;
#endif /* GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H */

@ -47,6 +47,7 @@
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/channel/http_client_filter.h"
#include "src/core/lib/channel/http_server_filter.h"
#include "src/core/lib/channel/max_age_filter.h"
#include "src/core/lib/channel/message_size_filter.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/http/parser.h"
@ -113,6 +114,9 @@ static void register_builtin_channel_init() {
grpc_channel_init_register_stage(
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
(void *)&grpc_server_deadline_filter);
grpc_channel_init_register_stage(
GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
(void *)&grpc_max_age_filter);
grpc_channel_init_register_stage(
GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
prepend_filter, (void *)&grpc_message_size_filter);

@ -43,7 +43,12 @@ namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {
// 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
// i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
// a 'grpc_completion_queue' instance (which is being passed as the input to
// this constructor), one must have already called grpc_init().
CompletionQueue::CompletionQueue(grpc_completion_queue* take)
: GrpcLibraryCodegen(false), cq_(take) {
InitialAvalanching();
}

@ -42,6 +42,7 @@
#include <grpc++/support/time.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpc/load_reporting.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

@ -35,29 +35,38 @@ set -evo pipefail
cd `dirname $0`
trap 'echo "EXIT TIME: $(date)"' EXIT
echo "TIME: $(date)"
SCHEME=HelloWorld \
EXAMPLE_PATH=examples/objective-c/helloworld \
./build_one_example.sh
echo "TIME: $(date)"
SCHEME=RouteGuideClient \
EXAMPLE_PATH=examples/objective-c/route_guide \
./build_one_example.sh
echo "TIME: $(date)"
SCHEME=AuthSample \
EXAMPLE_PATH=examples/objective-c/auth_sample \
./build_one_example.sh
rm -f ../examples/RemoteTestClient/*.{h,m}
echo "TIME: $(date)"
SCHEME=Sample \
EXAMPLE_PATH=src/objective-c/examples/Sample \
./build_one_example.sh
echo "TIME: $(date)"
SCHEME=Sample \
EXAMPLE_PATH=src/objective-c/examples/Sample \
FRAMEWORKS=YES \
./build_one_example.sh
echo "TIME: $(date)"
SCHEME=SwiftSample \
EXAMPLE_PATH=src/objective-c/examples/SwiftSample \
./build_one_example.sh

@ -50,4 +50,5 @@ rm -rf Tests.xcworkspace
rm -f Podfile.lock
rm -f RemoteTestClient/*.{h,m}
echo "TIME: $(date)"
pod install

@ -47,31 +47,35 @@ BINDIR=../../../bins/$CONFIG
$BINDIR/interop_server --port=5050 --max_send_message_size=8388608 &
$BINDIR/interop_server --port=5051 --max_send_message_size=8388608 --use_tls &
# Kill them when this script exits.
trap 'kill -9 `jobs -p`' EXIT
trap 'kill -9 `jobs -p` ; echo "EXIT TIME: $(date)"' EXIT
# xcodebuild is very verbose. We filter its output and tell Bash to fail if any
# element of the pipe fails.
# TODO(jcanizales): Use xctool instead? Issue #2540.
set -o pipefail
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)'
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme AllTests \
-destination name="iPhone 6" \
test | xcpretty
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CoreCronetEnd2EndTests \
-destination name="iPhone 6" \
test | xcpretty
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CronetUnitTests \
-destination name="iPhone 6" \
test | xcpretty
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme InteropTestsRemoteWithCronet \

@ -88,6 +88,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/channel/http_client_filter.c',
'src/core/lib/channel/http_server_filter.c',
'src/core/lib/channel/max_age_filter.c',
'src/core/lib/channel/message_size_filter.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',

16601
tags

File diff suppressed because it is too large Load Diff

@ -38,6 +38,10 @@
<%include file="../../php_deps.include"/>
<%include file="../../ruby_deps.include"/>
<%include file="../../python_deps.include"/>
# Install coverage for Python test coverage reporting
RUN pip install coverage
ENV PATH ~/.local/bin:$PATH
<%include file="../../run_tests_addons.include"/>
# Define the default command.
CMD ["bash"]

@ -97,6 +97,10 @@ extern void load_reporting_hook(grpc_end2end_test_config config);
extern void load_reporting_hook_pre_init(void);
extern void max_concurrent_streams(grpc_end2end_test_config config);
extern void max_concurrent_streams_pre_init(void);
extern void max_connection_age(grpc_end2end_test_config config);
extern void max_connection_age_pre_init(void);
extern void max_connection_idle(grpc_end2end_test_config config);
extern void max_connection_idle_pre_init(void);
extern void max_message_length(grpc_end2end_test_config config);
extern void max_message_length_pre_init(void);
extern void negative_deadline(grpc_end2end_test_config config);
@ -174,6 +178,8 @@ void grpc_end2end_tests_pre_init(void) {
large_metadata_pre_init();
load_reporting_hook_pre_init();
max_concurrent_streams_pre_init();
max_connection_age_pre_init();
max_connection_idle_pre_init();
max_message_length_pre_init();
negative_deadline_pre_init();
network_status_change_pre_init();
@ -232,6 +238,8 @@ void grpc_end2end_tests(int argc, char **argv,
large_metadata(config);
load_reporting_hook(config);
max_concurrent_streams(config);
max_connection_age(config);
max_connection_idle(config);
max_message_length(config);
negative_deadline(config);
network_status_change(config);
@ -363,6 +371,14 @@ void grpc_end2end_tests(int argc, char **argv,
max_concurrent_streams(config);
continue;
}
if (0 == strcmp("max_connection_age", argv[i])) {
max_connection_age(config);
continue;
}
if (0 == strcmp("max_connection_idle", argv[i])) {
max_connection_idle(config);
continue;
}
if (0 == strcmp("max_message_length", argv[i])) {
max_message_length(config);
continue;

@ -99,6 +99,10 @@ extern void load_reporting_hook(grpc_end2end_test_config config);
extern void load_reporting_hook_pre_init(void);
extern void max_concurrent_streams(grpc_end2end_test_config config);
extern void max_concurrent_streams_pre_init(void);
extern void max_connection_age(grpc_end2end_test_config config);
extern void max_connection_age_pre_init(void);
extern void max_connection_idle(grpc_end2end_test_config config);
extern void max_connection_idle_pre_init(void);
extern void max_message_length(grpc_end2end_test_config config);
extern void max_message_length_pre_init(void);
extern void negative_deadline(grpc_end2end_test_config config);
@ -177,6 +181,8 @@ void grpc_end2end_tests_pre_init(void) {
large_metadata_pre_init();
load_reporting_hook_pre_init();
max_concurrent_streams_pre_init();
max_connection_age_pre_init();
max_connection_idle_pre_init();
max_message_length_pre_init();
negative_deadline_pre_init();
network_status_change_pre_init();
@ -236,6 +242,8 @@ void grpc_end2end_tests(int argc, char **argv,
large_metadata(config);
load_reporting_hook(config);
max_concurrent_streams(config);
max_connection_age(config);
max_connection_idle(config);
max_message_length(config);
negative_deadline(config);
network_status_change(config);
@ -371,6 +379,14 @@ void grpc_end2end_tests(int argc, char **argv,
max_concurrent_streams(config);
continue;
}
if (0 == strcmp("max_connection_age", argv[i])) {
max_connection_age(config);
continue;
}
if (0 == strcmp("max_connection_idle", argv[i])) {
max_connection_idle(config);
continue;
}
if (0 == strcmp("max_message_length", argv[i])) {
max_message_length(config);
continue;

@ -122,6 +122,9 @@ END2END_TESTS = {
'keepalive_timeout': default_test_options._replace(proxyable=False),
'large_metadata': default_test_options,
'max_concurrent_streams': default_test_options._replace(proxyable=False),
'max_connection_age': default_test_options,
'max_connection_idle': connectivity_test_options._replace(
proxyable=False, exclude_iomgrs=['uv']),
'max_message_length': default_test_options,
'negative_deadline': default_test_options,
'network_status_change': default_test_options,

@ -109,6 +109,8 @@ END2END_TESTS = {
'keepalive_timeout': test_options(proxyable=False),
'large_metadata': test_options(),
'max_concurrent_streams': test_options(proxyable=False),
'max_connection_age': test_options(),
'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
'max_message_length': test_options(),
'negative_deadline': test_options(),
'network_status_change': test_options(),

@ -0,0 +1,383 @@
/*
*
* 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 "test/core/end2end/end2end_tests.h"
#include <limits.h>
#include <string.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "test/core/end2end/cq_verifier.h"
#define MAX_CONNECTION_AGE_MS 500
#define MAX_CONNECTION_AGE_GRACE_MS 1000
#define MAX_CONNECTION_IDLE_MS 9999
#define CALL_DEADLINE_S 10
/* The amount of time we wait for the connection to time out, but after it the
connection should not use up its grace period. It should be a number between
MAX_CONNECTION_AGE_MS and MAX_CONNECTION_AGE_MS +
MAX_CONNECTION_AGE_GRACE_MS */
#define CQ_MAX_CONNECTION_AGE_WAIT_TIME_S 1
/* The amount of time we wait after the connection reaches its max age, it
should be shorter than CALL_DEADLINE_S - CQ_MAX_CONNECTION_AGE_WAIT_TIME_S */
#define CQ_MAX_CONNECTION_AGE_GRACE_WAIT_TIME_S 2
/* The grace period for the test to observe the channel shutdown process */
#define IMMEDIATE_SHUTDOWN_GRACE_TIME_MS 300
static void *tag(intptr_t t) { return (void *)t; }
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture *f) {
if (!f->server) return;
grpc_server_destroy(f->server);
f->server = NULL;
}
static void shutdown_client(grpc_end2end_test_fixture *f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = NULL;
}
static void end_test(grpc_end2end_test_fixture *f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
}
static void test_max_age_forcibly_close(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_arg server_a[] = {{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_AGE_MS,
.value.integer = MAX_CONNECTION_AGE_MS},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS,
.value.integer = MAX_CONNECTION_AGE_GRACE_MS},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_IDLE_MS,
.value.integer = MAX_CONNECTION_IDLE_MS}};
grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
.args = server_a};
config.init_client(&f, NULL);
config.init_server(&f, &server_args);
grpc_call *c;
grpc_call *s;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(CALL_DEADLINE_S);
grpc_op ops[6];
grpc_op *op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
NULL);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->data.send_initial_metadata.metadata = NULL;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
gpr_timespec channel_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec expect_shutdown_time = gpr_time_add(
channel_start_time,
gpr_time_from_millis(MAX_CONNECTION_AGE_MS + MAX_CONNECTION_AGE_GRACE_MS +
IMMEDIATE_SHUTDOWN_GRACE_TIME_MS,
GPR_TIMESPAN));
/* Wait for the channel to reach its max age */
cq_verify_empty_timeout(cqv, CQ_MAX_CONNECTION_AGE_WAIT_TIME_S);
/* After the channel reaches its max age, we still do nothing here. And wait
for it to use up its max age grace period. */
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
gpr_timespec channel_shutdown_time = gpr_now(GPR_CLOCK_MONOTONIC);
GPR_ASSERT(gpr_time_cmp(channel_shutdown_time, expect_shutdown_time) < 0);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
CQ_EXPECT_COMPLETION(cqv, tag(0xdead), true);
cq_verify(cqv);
grpc_call_destroy(s);
/* The connection should be closed immediately after the max age grace period,
the in-progress RPC should fail. */
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_destroy(c);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
static void test_max_age_gracefully_close(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_arg server_a[] = {{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_AGE_MS,
.value.integer = MAX_CONNECTION_AGE_MS},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS,
.value.integer = INT_MAX},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_IDLE_MS,
.value.integer = MAX_CONNECTION_IDLE_MS}};
grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
.args = server_a};
config.init_client(&f, NULL);
config.init_server(&f, &server_args);
grpc_call *c;
grpc_call *s;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(CALL_DEADLINE_S);
grpc_op ops[6];
grpc_op *op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
NULL);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->data.send_initial_metadata.metadata = NULL;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
/* Wait for the channel to reach its max age */
cq_verify_empty_timeout(cqv, CQ_MAX_CONNECTION_AGE_WAIT_TIME_S);
/* The connection is shutting down gracefully. In-progress rpc should not be
closed, hence the completion queue should see nothing here. */
cq_verify_empty_timeout(cqv, CQ_MAX_CONNECTION_AGE_GRACE_WAIT_TIME_S);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
CQ_EXPECT_COMPLETION(cqv, tag(0xdead), true);
cq_verify(cqv);
grpc_call_destroy(s);
/* The connection is closed gracefully with goaway, the rpc should still be
completed. */
GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_destroy(c);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void max_connection_age(grpc_end2end_test_config config) {
test_max_age_forcibly_close(config);
test_max_age_gracefully_close(config);
}
void max_connection_age_pre_init(void) {}

@ -0,0 +1,117 @@
/*
*
* 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 "test/core/end2end/end2end_tests.h"
#include <limits.h>
#include <string.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "test/core/end2end/cq_verifier.h"
#define MAX_CONNECTION_IDLE_MS 500
#define MAX_CONNECTION_AGE_MS 9999
static void *tag(intptr_t t) { return (void *)t; }
static void test_max_connection_idle(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_arg client_a[] = {{.type = GRPC_ARG_INTEGER,
.key = "grpc.testing.fixed_reconnect_backoff_ms",
.value.integer = 1000}};
grpc_arg server_a[] = {{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_IDLE_MS,
.value.integer = MAX_CONNECTION_IDLE_MS},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_MAX_CONNECTION_AGE_MS,
.value.integer = MAX_CONNECTION_AGE_MS}};
grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(client_a),
.args = client_a};
grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
.args = server_a};
config.init_client(&f, &client_args);
config.init_server(&f, &server_args);
/* check that we're still in idle, and start connecting */
GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==
GRPC_CHANNEL_IDLE);
/* we'll go through some set of transitions (some might be missed), until
READY is reached */
while (state != GRPC_CHANNEL_READY) {
grpc_channel_watch_connectivity_state(
f.client, state, grpc_timeout_seconds_to_deadline(3), f.cq, tag(99));
CQ_EXPECT_COMPLETION(cqv, tag(99), 1);
cq_verify(cqv);
state = grpc_channel_check_connectivity_state(f.client, 0);
GPR_ASSERT(state == GRPC_CHANNEL_READY ||
state == GRPC_CHANNEL_CONNECTING ||
state == GRPC_CHANNEL_TRANSIENT_FAILURE);
}
/* wait for the channel to reach its maximum idle time */
grpc_channel_watch_connectivity_state(
f.client, GRPC_CHANNEL_READY,
grpc_timeout_milliseconds_to_deadline(MAX_CONNECTION_IDLE_MS + 500), f.cq,
tag(99));
CQ_EXPECT_COMPLETION(cqv, tag(99), 1);
cq_verify(cqv);
state = grpc_channel_check_connectivity_state(f.client, 0);
GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_IDLE);
grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
cq_verify(cqv);
grpc_server_destroy(f.server);
grpc_channel_destroy(f.client);
grpc_completion_queue_shutdown(f.cq);
grpc_completion_queue_destroy(f.cq);
config.tear_down_data(&f);
cq_verifier_destroy(cqv);
}
void max_connection_idle(grpc_end2end_test_config config) {
test_max_connection_idle(config);
}
void max_connection_idle_pre_init(void) {}

@ -97,7 +97,7 @@ static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
logged_representative_output = true;
for (size_t i = 0; i < outbuf.count; i++) {
char *s = grpc_dump_slice(outbuf.slices[i], GPR_DUMP_HEX);
gpr_log(GPR_DEBUG, "%" PRId64 ": %s", i, s);
gpr_log(GPR_DEBUG, "%" PRIdPTR ": %s", i, s);
gpr_free(s);
}
}

@ -58,6 +58,17 @@ static void BM_CreateDestroyCpp(benchmark::State& state) {
}
BENCHMARK(BM_CreateDestroyCpp);
/* Create cq using a different constructor */
static void BM_CreateDestroyCpp2(benchmark::State& state) {
TrackCounters track_counters;
while (state.KeepRunning()) {
grpc_completion_queue* core_cq = grpc_completion_queue_create(NULL);
CompletionQueue cq(core_cq);
}
track_counters.Finish(state);
}
BENCHMARK(BM_CreateDestroyCpp2);
static void BM_CreateDestroyCore(benchmark::State& state) {
TrackCounters track_counters;
while (state.KeepRunning()) {

@ -16,3 +16,6 @@ internal_ci: Support for running tests on an internal CI platform.
jenkins: Support for running tests on Jenkins.
run_tests: Scripts to run gRPC tests in parallel.
run_tests/performance: See the [README](./run_tests/performance/README.md) for
more notes on the performance tests.

@ -135,6 +135,10 @@ RUN pip install pip --upgrade
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
# Install coverage for Python test coverage reporting
RUN pip install coverage
ENV PATH ~/.local/bin:$PATH
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++

@ -1041,6 +1041,8 @@ src/core/lib/channel/http_client_filter.c \
src/core/lib/channel/http_client_filter.h \
src/core/lib/channel/http_server_filter.c \
src/core/lib/channel/http_server_filter.h \
src/core/lib/channel/max_age_filter.c \
src/core/lib/channel/max_age_filter.h \
src/core/lib/channel/message_size_filter.c \
src/core/lib/channel/message_size_filter.h \
src/core/lib/compression/algorithm_metadata.h \

@ -166,3 +166,5 @@ echo 4096 | sudo tee /proc/sys/kernel/perf_event_mlock_kb
# on benchmarks
git clone -v https://github.com/brendangregg/FlameGraph ~/FlameGraph
# Install scipy and numpy for benchmarking scripts
sudo apt-get install python-scipy python-numpy

@ -37,6 +37,4 @@ BENCHMARKS_TO_RUN="bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_c
# Enter the gRPC repo root
cd $(dirname $0)/../..
tools/run_tests/run_performance_tests.py -l c++ node ruby csharp python --netperf --category smoketest
# todo(mattkwong): Change performance test to use microbenchmarking
# tools/run_tests/run_microbenchmark.py -c summary --diff_perf origin/$ghprbTargetBranch -b $BENCHMARKS_TO_RUN
tools/profiling/microbenchmarks/bm_diff.py -d origin/$ghprbTargetBranch -b $BENCHMARKS_TO_RUN

@ -33,6 +33,14 @@ import json
import bm_json
import tabulate
import argparse
from scipy import stats
import subprocess
import multiprocessing
import collections
import pipes
import os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..', '..', 'run_tests', 'python_utils'))
import comment_on_pr
def changed_ratio(n, o):
if float(o) <= .0001: o = 0
@ -41,78 +49,193 @@ def changed_ratio(n, o):
if o == 0: return 100
return (float(n)-float(o))/float(o)
def median(ary):
ary = sorted(ary)
n = len(ary)
if n%2 == 0:
return (ary[n/2] + ary[n/2+1]) / 2.0
else:
return ary[n/2]
def min_change(pct):
return lambda n, o: abs(changed_ratio(n,o)) > pct/100.0
nanos = {
'abs_diff': 5,
'pct_diff': 10,
}
counter = {
'abs_diff': 0.5,
'pct_diff': 10,
}
_INTERESTING = {
'cpu_time': min_change(10),
'real_time': min_change(10),
'locks_per_iteration': min_change(5),
'allocs_per_iteration': min_change(5),
'writes_per_iteration': min_change(5),
'atm_cas_per_iteration': min_change(1),
'atm_add_per_iteration': min_change(5),
'cpu_time': nanos,
'real_time': nanos,
'locks_per_iteration': counter,
'allocs_per_iteration': counter,
'writes_per_iteration': counter,
'atm_cas_per_iteration': counter,
'atm_add_per_iteration': counter,
}
_AVAILABLE_BENCHMARK_TESTS = ['bm_fullstack_unary_ping_pong',
'bm_fullstack_streaming_ping_pong',
'bm_fullstack_streaming_pump',
'bm_closure',
'bm_cq',
'bm_call_create',
'bm_error',
'bm_chttp2_hpack',
'bm_chttp2_transport',
'bm_pollset',
'bm_metadata',
'bm_fullstack_trickle']
argp = argparse.ArgumentParser(description='Perform diff on microbenchmarks')
argp.add_argument('-t', '--track',
choices=sorted(_INTERESTING.keys()),
nargs='+',
default=sorted(_INTERESTING.keys()),
help='Which metrics to track')
argp.add_argument('files', metavar='bm_file.json', type=str, nargs=4,
help='files to diff. ')
argp.add_argument('-b', '--benchmarks', nargs='+', choices=_AVAILABLE_BENCHMARK_TESTS, default=['bm_cq'])
argp.add_argument('-d', '--diff_base', type=str)
argp.add_argument('-r', '--repetitions', type=int, default=4)
argp.add_argument('-p', '--p_threshold', type=float, default=0.03)
args = argp.parse_args()
with open(args.files[0]) as f:
js_new_ctr = json.loads(f.read())
with open(args.files[1]) as f:
js_new_opt = json.loads(f.read())
with open(args.files[2]) as f:
js_old_ctr = json.loads(f.read())
with open(args.files[3]) as f:
js_old_opt = json.loads(f.read())
new = {}
old = {}
for row in bm_json.expand_json(js_new_ctr, js_new_opt):
new[row['cpp_name']] = row
for row in bm_json.expand_json(js_old_ctr, js_old_opt):
old[row['cpp_name']] = row
changed = []
for fld in args.track:
chk = _INTERESTING[fld]
for bm in new.keys():
if bm not in old: continue
n = new[bm]
o = old[bm]
if fld not in n or fld not in o: continue
if chk(n[fld], o[fld]):
changed.append((fld, chk))
break
headers = ['Benchmark'] + [c[0] for c in changed] + ['Details']
assert args.diff_base
def avg(lst):
sum = 0.0
n = 0.0
for el in lst:
sum += el
n += 1
return sum / n
def make_cmd(cfg):
return ['make'] + args.benchmarks + [
'CONFIG=%s' % cfg, '-j', '%d' % multiprocessing.cpu_count()]
def build():
subprocess.check_call(['git', 'submodule', 'update'])
try:
subprocess.check_call(make_cmd('opt'))
subprocess.check_call(make_cmd('counters'))
except subprocess.CalledProcessError, e:
subprocess.check_call(['make', 'clean'])
subprocess.check_call(make_cmd('opt'))
subprocess.check_call(make_cmd('counters'))
def collect1(bm, cfg, ver):
cmd = ['bins/%s/%s' % (cfg, bm),
'--benchmark_out=%s.%s.%s.json' % (bm, cfg, ver),
'--benchmark_out_format=json',
'--benchmark_repetitions=%d' % (args.repetitions)
]
print cmd
subprocess.check_call(cmd)
build()
for bm in args.benchmarks:
collect1(bm, 'opt', 'new')
collect1(bm, 'counters', 'new')
where_am_i = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
subprocess.check_call(['git', 'checkout', args.diff_base])
try:
build()
comparables = []
for bm in args.benchmarks:
try:
collect1(bm, 'opt', 'old')
collect1(bm, 'counters', 'old')
comparables.append(bm)
except subprocess.CalledProcessError, e:
pass
finally:
subprocess.check_call(['git', 'checkout', where_am_i])
subprocess.check_call(['git', 'submodule', 'update'])
class Benchmark:
def __init__(self):
self.samples = {
True: collections.defaultdict(list),
False: collections.defaultdict(list)
}
self.final = {}
def add_sample(self, data, new):
for f in args.track:
if f in data:
self.samples[new][f].append(float(data[f]))
def process(self):
for f in sorted(args.track):
new = self.samples[True][f]
old = self.samples[False][f]
if not new or not old: continue
p = stats.ttest_ind(new, old)[1]
new_mdn = median(new)
old_mdn = median(old)
delta = new_mdn - old_mdn
ratio = changed_ratio(new_mdn, old_mdn)
print '%s: new=%r old=%r new_mdn=%f old_mdn=%f delta=%f(%f:%f) ratio=%f(%f:%f) p=%f' % (
f, new, old, new_mdn, old_mdn, delta, abs(delta), _INTERESTING[f]['abs_diff'], ratio, abs(ratio), _INTERESTING[f]['pct_diff']/100.0, p
)
if p < args.p_threshold and abs(delta) > _INTERESTING[f]['abs_diff'] and abs(ratio) > _INTERESTING[f]['pct_diff']/100.0:
self.final[f] = delta
return self.final.keys()
def skip(self):
return not self.final
def row(self, flds):
return [self.final[f] if f in self.final else '' for f in flds]
benchmarks = collections.defaultdict(Benchmark)
for bm in comparables:
with open('%s.counters.new.json' % bm) as f:
js_new_ctr = json.loads(f.read())
with open('%s.opt.new.json' % bm) as f:
js_new_opt = json.loads(f.read())
with open('%s.counters.old.json' % bm) as f:
js_old_ctr = json.loads(f.read())
with open('%s.opt.old.json' % bm) as f:
js_old_opt = json.loads(f.read())
for row in bm_json.expand_json(js_new_ctr, js_new_opt):
print row
name = row['cpp_name']
if name.endswith('_mean') or name.endswith('_stddev'): continue
benchmarks[name].add_sample(row, True)
for row in bm_json.expand_json(js_old_ctr, js_old_opt):
print row
name = row['cpp_name']
if name.endswith('_mean') or name.endswith('_stddev'): continue
benchmarks[name].add_sample(row, False)
really_interesting = set()
for name, bm in benchmarks.items():
print name
really_interesting.update(bm.process())
fields = [f for f in args.track if f in args.track]
headers = ['Benchmark'] + fields
rows = []
for bm in sorted(new.keys()):
if bm not in old: continue
row = [bm]
any_changed = False
n = new[bm]
o = old[bm]
details = ''
for fld in args.track:
chk = _INTERESTING[fld]
if fld not in n or fld not in o: continue
if chk(n[fld], o[fld]):
row.append(changed_ratio(n[fld], o[fld]))
if details: details += ', '
details += '%s:%r-->%r' % (fld, float(o[fld]), float(n[fld]))
any_changed = True
else:
row.append('')
if any_changed:
row.append(details)
rows.append(row)
print tabulate.tabulate(rows, headers=headers, floatfmt='+.2f')
for name in sorted(benchmarks.keys()):
if benchmarks[name].skip(): continue
rows.append([name] + benchmarks[name].row(fields))
if rows:
text = 'Performance differences noted:\n' + tabulate.tabulate(rows, headers=headers, floatfmt='+.2f')
else:
text = 'No significant performance differences'
comment_on_pr.comment_on_pr('```\n%s\n```' % text)
print text

@ -179,6 +179,7 @@ def parse_name(name):
def expand_json(js, js2 = None):
for bm in js['benchmarks']:
if bm['name'].endswith('_stddev') or bm['name'].endswith('_mean'): continue
context = js['context']
if 'label' in bm:
labels_list = [s.split(':') for s in bm['label'].strip().split(' ') if len(s) and s[0] != '#']
@ -197,8 +198,9 @@ def expand_json(js, js2 = None):
row.update(labels)
if js2:
for bm2 in js2['benchmarks']:
if bm['name'] == bm2['name']:
if bm['name'] == bm2['name'] and 'already_used' not in bm2:
row['cpu_time'] = bm2['cpu_time']
row['real_time'] = bm2['real_time']
row['iterations'] = bm2['iterations']
bm2['already_used'] = True
yield row

@ -2,6 +2,26 @@
{
"config": "opt"
},
{
"config": "asan-trace-cmp",
"environ": {
"ASAN_OPTIONS": "detect_leaks=1:color=always",
"LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
}
},
{
"config": "dbg"
},
{
"config": "asan",
"environ": {
"ASAN_OPTIONS": "detect_leaks=1:color=always",
"LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
}
},
{
"config": "msan"
},
{
"config": "basicprof"
},
@ -19,14 +39,16 @@
}
},
{
"config": "asan-trace-cmp",
"config": "ubsan",
"environ": {
"ASAN_OPTIONS": "detect_leaks=1:color=always",
"LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
"UBSAN_OPTIONS": "halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt"
}
},
{
"config": "dbg"
"config": "tsan",
"environ": {
"TSAN_OPTIONS": "suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
}
},
{
"config": "stapprof"
@ -43,26 +65,7 @@
]
},
{
"config": "asan",
"environ": {
"ASAN_OPTIONS": "detect_leaks=1:color=always",
"LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
}
},
{
"config": "tsan",
"environ": {
"TSAN_OPTIONS": "suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
}
},
{
"config": "ubsan",
"environ": {
"UBSAN_OPTIONS": "halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt"
}
},
{
"config": "msan"
"config": "lto"
},
{
"config": "mutrace"

@ -7144,6 +7144,8 @@
"test/core/end2end/tests/large_metadata.c",
"test/core/end2end/tests/load_reporting_hook.c",
"test/core/end2end/tests/max_concurrent_streams.c",
"test/core/end2end/tests/max_connection_age.c",
"test/core/end2end/tests/max_connection_idle.c",
"test/core/end2end/tests/max_message_length.c",
"test/core/end2end/tests/negative_deadline.c",
"test/core/end2end/tests/network_status_change.c",
@ -7216,6 +7218,8 @@
"test/core/end2end/tests/large_metadata.c",
"test/core/end2end/tests/load_reporting_hook.c",
"test/core/end2end/tests/max_concurrent_streams.c",
"test/core/end2end/tests/max_connection_age.c",
"test/core/end2end/tests/max_connection_idle.c",
"test/core/end2end/tests/max_message_length.c",
"test/core/end2end/tests/negative_deadline.c",
"test/core/end2end/tests/network_status_change.c",
@ -7511,6 +7515,7 @@
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/channel/http_client_filter.h",
"src/core/lib/channel/http_server_filter.h",
"src/core/lib/channel/max_age_filter.h",
"src/core/lib/channel/message_size_filter.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/message_compress.h",
@ -7646,6 +7651,8 @@
"src/core/lib/channel/http_client_filter.h",
"src/core/lib/channel/http_server_filter.c",
"src/core/lib/channel/http_server_filter.h",
"src/core/lib/channel/max_age_filter.c",
"src/core/lib/channel/max_age_filter.h",
"src/core/lib/channel/message_size_filter.c",
"src/core/lib/channel/message_size_filter.h",
"src/core/lib/compression/algorithm_metadata.h",

File diff suppressed because it is too large Load Diff

@ -43,4 +43,4 @@ genhtml $tmp2 --output-directory $out
rm $tmp2
rm $tmp1
cp -rv $root/src/php/coverage $root/reports/php
# todo(mattkwong): generate coverage report for php and copy to reports/php

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Copyright 2017, Google Inc.
# All rights reserved.
#
@ -27,19 +27,13 @@
# 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.
#
# This script is invoked by Jenkins to comment $1 on pull requests
# when triggered by a build
set -e
set -ex
if [ -z "$1" ] || [ -z $JENKINS_OAUTH_TOKEN ] || [ -z $ghprbPullId ]; then
echo "Insufficient arguments or environment variables provided."
exit 1
fi
if [ "$CONFIG" != "gcov" ] ; then exit ; fi
# Format the comment message to JSON
COMMENT_MESSAGE="{\"body\":\"$1\"}"
# change to directory of Python coverage files
cd $(dirname $0)/../../../src/python/grpcio_tests/
curl -k -H "Authorization: token $JENKINS_OAUTH_TOKEN" -H "Content-Type: application/json" \
-d "$COMMENT_MESSAGE" https://api.github.com/repos/grpc/grpc/issues/$ghprbPullId/comments
coverage combine .
coverage html -i -d ./../../../reports/python

@ -0,0 +1,106 @@
# Overview of performance test suite, with steps for manual runs:
For design of the tests, see
http://www.grpc.io/docs/guides/benchmarking.html.
## Pre-reqs for running these manually:
In general the benchmark workers and driver build scripts expect
[linux_performance_worker_init.sh](../../gce/linux_performance_worker_init.sh) to have been ran already.
### To run benchmarks locally:
* From the grpc repo root, start the
[run_performance_tests.py](../run_performance_tests.py) runner script.
### On remote machines, to start the driver and workers manually:
The [run_performance_test.py](../run_performance_tests.py) top-level runner script can also
be used with remote machines, but for e.g., profiling the server,
it might be useful to run workers manually.
1. You'll need a "driver" and separate "worker" machines.
For example, you might use one GCE "driver" machine and 3 other
GCE "worker" machines that are in the same zone.
2. Connect to each worker machine and start up a benchmark worker with a "driver_port".
* For example, to start the grpc-go benchmark worker:
[grpc-go worker main.go](https://github.com/grpc/grpc-go/blob/master/benchmark/worker/main.go) --driver_port <driver_port>
#### Comands to start workers in different languages:
* Note that these commands are what the top-level
[run_performance_test.py](../run_performance_tests.py) script uses to
build and run different workers through the
[build_performance.sh](./build_performance.sh) script and "run worker"
scripts (such as the [run_worker_java.sh](./run_worker_java.sh)).
##### Running benchmark workers for C-core wrapped languages (C++, Python, C#, Node, Ruby):
* These are more simple since they all live in the main grpc repo.
```
$ cd <grpc_repo_root>
$ tools/run_tests/performance/build_performance.sh
$ tools/run_tests/performance/run_worker_<language>.sh
```
* Note that there is one "run_worker" script per language, e.g.,
[run_worker_csharp.sh](./run_worker_csharp.sh) for c#.
##### Running benchmark workers for gRPC-Java:
* You'll need the [grpc-java](https://github.com/grpc/grpc-java) repo.
```
$ cd <grpc-java-repo>
$ ./gradlew -PskipCodegen=true :grpc-benchmarks:installDist
$ benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker --driver_port <driver_port>
```
##### Running benchmark workers for gRPC-Go:
* You'll need the [grpc-go repo](https://github.com/grpc/grpc-go)
```
$ cd <grpc-go-repo>/benchmark/worker && go install
$ # if profiling, it might be helpful to turn off inlining by building with "-gcflags=-l"
$ $GOPATH/bin/worker --driver_port <driver_port>
```
#### Build the driver:
* Connect to the driver machine (if using a remote driver) and from the grpc repo root:
```
$ tools/run_tests/performance/build_performance.sh
```
#### Run the driver:
1. Get the 'scenario_json' relevant for the scenario to run. Note that "scenario
json" configs are generated from [scenario_config.py](./scenario_config.py).
The [driver](../../../test/cpp/qps/qps_json_driver.cc) takes a list of these configs as a json string of the form: `{scenario: <json_list_of_scenarios> }`
in its `--scenarios_json` command argument.
One quick way to get a valid json string to pass to the driver is by running
the [run_performance_tests.py](./run_performance_tests.py) locally and copying the logged scenario json command arg.
2. From the grpc repo root:
* Set `QPS_WORKERS` environment variable to a comma separated list of worker
machines. Note that the driver will start the "benchmark server" on the first
entry in the list, and the rest will be told to run as clients against the
benchmark server.
Example running and profiling of go benchmark server:
```
$ export QPS_WORKERS=<host1>:<10000>,<host2>,10000,<host3>:10000
$ bins/opt/qps_json_driver --scenario_json='<scenario_json_scenario_config_string>'
```
### Example profiling commands
While running the benchmark, a profiler can be attached to the server.
Example to count syscalls in grpc-go server during a benchmark:
* Connect to server machine and run:
```
$ netstat -tulpn | grep <driver_port> # to get pid of worker
$ perf stat -p <worker_pid> -e syscalls:sys_enter_write # stop after test complete
```
Example memory profile of grpc-go server, with `go tools pprof`:
* After a run is done on the server, see its alloc profile with:
```
$ go tool pprof --text --alloc_space http://localhost:<pprof_port>/debug/heap
```

@ -214,6 +214,29 @@ class CXXLanguage:
secure=secure,
categories=smoketest_categories+[SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_1channel_1MBmsg_%s' % secstr,
rpc_type='STREAMING',
req_size=1024*1024,
resp_size=1024*1024,
client_type='ASYNC_CLIENT',
server_type='ASYNC_GENERIC_SERVER',
unconstrained_client='async', use_generic_payload=True,
secure=secure,
categories=smoketest_categories+[SCALABLE],
channels=1, outstanding=100)
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_unconstrained_64KBmsg_%s' % secstr,
rpc_type='STREAMING',
req_size=64*1024,
resp_size=64*1024,
client_type='ASYNC_CLIENT',
server_type='ASYNC_GENERIC_SERVER',
unconstrained_client='async', use_generic_payload=True,
secure=secure,
categories=smoketest_categories+[SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_one_server_core_%s' % secstr,
rpc_type='STREAMING',

@ -0,0 +1,49 @@
# 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.
import os
import json
import urllib2
def comment_on_pr(text):
if 'JENKINS_OAUTH_TOKEN' not in os.environ:
print 'Missing JENKINS_OAUTH_TOKEN env var: not commenting'
return
if 'ghprbPullId' not in os.environ:
print 'Missing ghprbPullId env var: not commenting'
return
req = urllib2.Request(
url = 'https://api.github.com/repos/grpc/grpc/issues/%s/comments' %
os.environ['ghprbPullId'],
data = json.dumps({'body': text}),
headers = {
'Authorization': 'token %s' % os.environ['JENKINS_OAUTH_TOKEN'],
'Content-Type': 'application/json',
})
print urllib2.urlopen(req).read()

@ -219,10 +219,6 @@ argp.add_argument('-b', '--benchmarks',
nargs='+',
type=str,
help='Which microbenchmarks should be run')
argp.add_argument('--diff_perf',
default=None,
type=str,
help='Diff microbenchmarks against this git revision')
argp.add_argument('--bigquery_upload',
default=False,
action='store_const',
@ -238,41 +234,7 @@ try:
for collect in args.collect:
for bm_name in args.benchmarks:
collectors[collect](bm_name, args)
if args.diff_perf:
git_comment = 'Performance differences between this PR and %s\\n' % args.diff_perf
if 'summary' not in args.collect:
for bm_name in args.benchmarks:
run_summary(bm_name, 'opt', bm_name)
run_summary(bm_name, 'counters', bm_name)
where_am_i = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
subprocess.check_call(['git', 'checkout', args.diff_perf])
comparables = []
subprocess.check_call(['make', 'clean'])
try:
for bm_name in args.benchmarks:
try:
run_summary(bm_name, 'opt', '%s.old' % bm_name)
run_summary(bm_name, 'counters', '%s.old' % bm_name)
comparables.append(bm_name)
except subprocess.CalledProcessError, e:
pass
finally:
subprocess.check_call(['git', 'checkout', where_am_i])
for bm_name in comparables:
diff = subprocess.check_output(['tools/profiling/microbenchmarks/bm_diff.py',
'%s.counters.json' % bm_name,
'%s.opt.json' % bm_name,
'%s.old.counters.json' % bm_name,
'%s.old.opt.json' % bm_name]).strip()
if diff:
heading('Performance diff: %s' % bm_name)
text(diff)
git_comment += '```\\nPerformance diff: %s\\n%s\\n```\\n' % (bm_name, diff.replace('\n', '\\n'))
finally:
if args.diff_perf:
subprocess.call(['tools/jenkins/comment_on_pr.sh "%s"' % git_comment.replace('`', '\`')],
stdout=subprocess.PIPE,
shell=True)
if not os.path.exists('reports'):
os.makedirs('reports')
index_html += "</body>\n</html>\n"

@ -614,7 +614,10 @@ class PythonLanguage(object):
return [config.build for config in self.pythons]
def post_tests_steps(self):
return []
if self.config != 'gcov':
return []
else:
return [['tools/run_tests/helper_scripts/post_tests_python.sh']]
def makefile_name(self):
return 'Makefile'
@ -1270,7 +1273,9 @@ if any(language.make_options() for language in languages):
print('languages with custom make options cannot be built simultaneously with other languages')
sys.exit(1)
else:
language_make_options = next(iter(languages)).make_options()
# Combining make options is not clean and just happens to work. It allows C/C++ and C# to build
# together, and is only used under gcov. All other configs should build languages individually.
language_make_options = list(set([make_option for lang in languages for make_option in lang.make_options()]))
if args.use_docker:
if not args.travis:

@ -312,6 +312,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@ -527,6 +528,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">

@ -37,6 +37,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
@ -830,6 +833,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>

@ -207,6 +207,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@ -368,6 +369,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">

@ -94,6 +94,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
@ -611,6 +614,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>

@ -302,6 +302,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@ -494,6 +495,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">

@ -40,6 +40,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
<Filter>src\core\lib\channel</Filter>
</ClCompile>
@ -743,6 +746,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
<Filter>src\core\lib\channel</Filter>
</ClInclude>

@ -207,6 +207,10 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_age.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_idle.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\negative_deadline.c">

@ -85,6 +85,12 @@
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_age.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_idle.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>

@ -209,6 +209,10 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_age.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_idle.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\negative_deadline.c">

@ -88,6 +88,12 @@
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_age.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_connection_idle.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>

Loading…
Cancel
Save