aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt66
-rw-r--r--Makefile117
-rw-r--r--build.yaml14
-rw-r--r--grpc.gyp12
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c12
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c4
-rw-r--r--src/core/lib/debug/stats.c110
-rw-r--r--src/core/lib/debug/stats.h17
-rw-r--r--src/core/lib/debug/stats_data.c174
-rw-r--r--src/core/lib/debug/stats_data.h261
-rw-r--r--src/core/lib/debug/stats_data.yaml64
-rw-r--r--src/core/lib/iomgr/combiner.c5
-rw-r--r--src/core/lib/iomgr/executor.c6
-rw-r--r--src/core/lib/iomgr/tcp_posix.c12
-rw-r--r--src/cpp/util/core_stats.cc90
-rw-r--r--src/cpp/util/core_stats.h35
-rw-r--r--src/proto/grpc/core/stats.proto38
-rw-r--r--src/proto/grpc/testing/stats.proto8
-rw-r--r--test/cpp/microbenchmarks/helpers.cc13
-rw-r--r--test/cpp/qps/client.h5
-rw-r--r--test/cpp/qps/report.cc28
-rw-r--r--test/cpp/qps/report.h3
-rw-r--r--test/cpp/qps/server.h5
-rwxr-xr-xtools/codegen/core/gen_stats_data.py199
-rw-r--r--tools/run_tests/generated/sources_and_headers.json28
25 files changed, 1265 insertions, 61 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index efc33c0a6c..ecfc8c8c30 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2770,6 +2770,68 @@ if (gRPC_INSTALL)
)
endif()
+if (gRPC_BUILD_TESTS)
+
+add_library(grpc++_core_stats
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.grpc.pb.h
+ src/cpp/util/core_stats.cc
+)
+
+if(WIN32 AND MSVC)
+ set_target_properties(grpc++_core_stats PROPERTIES COMPILE_PDB_NAME "grpc++_core_stats"
+ COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+ )
+ if (gRPC_INSTALL)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/grpc++_core_stats.pdb
+ DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL
+ )
+ endif()
+endif()
+
+protobuf_generate_grpc_cpp(
+ src/proto/grpc/core/stats.proto
+)
+
+target_include_directories(grpc++_core_stats
+ PUBLIC $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${BORINGSSL_ROOT_DIR}/include
+ PRIVATE ${PROTOBUF_ROOT_DIR}/src
+ PRIVATE ${ZLIB_INCLUDE_DIR}
+ PRIVATE ${BENCHMARK}/include
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+ PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+ PRIVATE ${CARES_INCLUDE_DIR}
+ PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc++_core_stats
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++
+)
+
+foreach(_hdr
+ src/cpp/util/core_stats.h
+)
+ string(REPLACE "include/" "" _path ${_hdr})
+ get_filename_component(_path ${_path} PATH)
+ install(FILES ${_hdr}
+ DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
+ )
+endforeach()
+
+endif (gRPC_BUILD_TESTS)
add_library(grpc++_cronet
src/cpp/client/cronet_credentials.cc
@@ -4596,6 +4658,7 @@ target_link_libraries(qps
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc++_test_util
+ grpc++_core_stats
grpc++
grpc
)
@@ -10398,6 +10461,7 @@ target_include_directories(codegen_test_full
target_link_libraries(codegen_test_full
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_core_stats
grpc++
grpc
gpr
@@ -10473,6 +10537,7 @@ target_include_directories(codegen_test_minimal
target_link_libraries(codegen_test_minimal
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_core_stats
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
@@ -12044,6 +12109,7 @@ target_link_libraries(qps_json_driver
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
qps
+ grpc++_core_stats
grpc++_test_util
grpc_test_util
grpc++
diff --git a/Makefile b/Makefile
index 4fd534df09..78451e2bda 100644
--- a/Makefile
+++ b/Makefile
@@ -1328,9 +1328,9 @@ pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
ifeq ($(EMBED_OPENSSL),true)
-privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_sign_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_verify_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_sign_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_verify_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
else
-privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
endif
@@ -2241,6 +2241,22 @@ $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc:
$(Q) echo "$(GRPCXX_UNSECURE_PC_FILE)" | tr , '\n' >$@
ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/core/stats.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc: protoc_dep_error
+else
+
+$(GENDIR)/src/proto/grpc/core/stats.pb.cc: src/proto/grpc/core/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[PROTOC] Generating protobuf CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc: src/proto/grpc/core/stats.proto $(GENDIR)/src/proto/grpc/core/stats.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+ $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
+endif
+
+ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc: protoc_dep_error
else
@@ -2471,12 +2487,12 @@ $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error
else
-$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/core/stats.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
-$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: src/proto/grpc/testing/stats.proto $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: src/proto/grpc/testing/stats.proto $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/core/stats.pb.cc $(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
@@ -4659,6 +4675,58 @@ endif
endif
+LIBGRPC++_CORE_STATS_SRC = \
+ $(GENDIR)/src/proto/grpc/core/stats.pb.cc $(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc \
+ src/cpp/util/core_stats.cc \
+
+PUBLIC_HEADERS_CXX += \
+ src/cpp/util/core_stats.h \
+
+LIBGRPC++_CORE_STATS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_CORE_STATS_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_CORE_STATS_OBJS)
+ $(E) "[AR] Creating $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a
+ $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBGRPC++_CORE_STATS_OBJS)
+ifeq ($(SYSTEM),Darwin)
+ $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC++_CORE_STATS_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/src/cpp/util/core_stats.o: $(GENDIR)/src/proto/grpc/core/stats.pb.cc $(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc
+
+
LIBGRPC++_CRONET_SRC = \
src/cpp/client/cronet_credentials.cc \
src/cpp/client/insecure_credentials.cc \
@@ -14441,26 +14509,26 @@ $(BINDIR)/$(CONFIG)/codegen_test_full: protobuf_dep_error
else
-$(BINDIR)/$(CONFIG)/codegen_test_full: $(PROTOBUF_DEP) $(CODEGEN_TEST_FULL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/codegen_test_full: $(PROTOBUF_DEP) $(CODEGEN_TEST_FULL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(CODEGEN_TEST_FULL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/codegen_test_full
+ $(Q) $(LDXX) $(LDFLAGS) $(CODEGEN_TEST_FULL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/codegen_test_full
endif
endif
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/control.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/control.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/payloads.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/payloads.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/services.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/services.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/stats.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/stats.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test_full.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test_full.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_codegen_test_full: $(CODEGEN_TEST_FULL_OBJS:.o=.dep)
@@ -14501,28 +14569,28 @@ $(BINDIR)/$(CONFIG)/codegen_test_minimal: protobuf_dep_error
else
-$(BINDIR)/$(CONFIG)/codegen_test_minimal: $(PROTOBUF_DEP) $(CODEGEN_TEST_MINIMAL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/codegen_test_minimal: $(PROTOBUF_DEP) $(CODEGEN_TEST_MINIMAL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(CODEGEN_TEST_MINIMAL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/codegen_test_minimal
+ $(Q) $(LDXX) $(LDFLAGS) $(CODEGEN_TEST_MINIMAL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/codegen_test_minimal
endif
endif
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/control.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/control.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/payloads.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/payloads.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/services.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/services.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/stats.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/stats.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test_minimal.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test_minimal.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_codegen_test_minimal: $(CODEGEN_TEST_MINIMAL_OBJS:.o=.dep)
@@ -16018,16 +16086,16 @@ $(BINDIR)/$(CONFIG)/qps_json_driver: protobuf_dep_error
else
-$(BINDIR)/$(CONFIG)/qps_json_driver: $(PROTOBUF_DEP) $(QPS_JSON_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(BINDIR)/$(CONFIG)/qps_json_driver: $(PROTOBUF_DEP) $(QPS_JSON_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(QPS_JSON_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_json_driver
+ $(Q) $(LDXX) $(LDFLAGS) $(QPS_JSON_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_json_driver
endif
endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_json_driver.o: $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_json_driver.o: $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
deps_qps_json_driver: $(QPS_JSON_DRIVER_OBJS:.o=.dep)
@@ -19766,6 +19834,7 @@ src/cpp/common/secure_create_auth_context.cc: $(OPENSSL_DEP)
src/cpp/ext/proto_server_reflection.cc: $(OPENSSL_DEP)
src/cpp/ext/proto_server_reflection_plugin.cc: $(OPENSSL_DEP)
src/cpp/server/secure_server_credentials.cc: $(OPENSSL_DEP)
+src/cpp/util/core_stats.cc: $(OPENSSL_DEP)
src/cpp/util/error_details.cc: $(OPENSSL_DEP)
src/csharp/ext/grpc_csharp_ext.c: $(OPENSSL_DEP)
test/core/bad_client/bad_client.c: $(OPENSSL_DEP)
diff --git a/build.yaml b/build.yaml
index a43ad6ae31..00d34292fc 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1323,6 +1323,16 @@ libs:
- grpc++_codegen_base_src
secure: check
vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}'
+- name: grpc++_core_stats
+ build: private
+ language: c++
+ public_headers:
+ - src/cpp/util/core_stats.h
+ src:
+ - src/proto/grpc/core/stats.proto
+ - src/cpp/util/core_stats.cc
+ deps:
+ - grpc++
- name: grpc++_cronet
build: all
language: c++
@@ -1665,6 +1675,7 @@ libs:
deps:
- grpc_test_util
- grpc++_test_util
+ - grpc++_core_stats
- grpc++
- grpc
- name: grpc_csharp_ext
@@ -3796,6 +3807,7 @@ targets:
- src/proto/grpc/testing/stats.proto
- test/cpp/codegen/codegen_test_full.cc
deps:
+ - grpc++_core_stats
- grpc++
- grpc
- gpr
@@ -3813,6 +3825,7 @@ targets:
- src/proto/grpc/testing/stats.proto
- test/cpp/codegen/codegen_test_minimal.cc
deps:
+ - grpc++_core_stats
- grpc
- gpr
filegroups:
@@ -4303,6 +4316,7 @@ targets:
- test/cpp/qps/qps_json_driver.cc
deps:
- qps
+ - grpc++_core_stats
- grpc++_test_util
- grpc_test_util
- grpc++
diff --git a/grpc.gyp b/grpc.gyp
index 40938a4564..39f68766ed 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -1227,6 +1227,17 @@
],
},
{
+ 'target_name': 'grpc++_core_stats',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'grpc++',
+ ],
+ 'sources': [
+ 'src/proto/grpc/core/stats.proto',
+ 'src/cpp/util/core_stats.cc',
+ ],
+ },
+ {
'target_name': 'grpc++_error_details',
'type': 'static_library',
'dependencies': [
@@ -1508,6 +1519,7 @@
'dependencies': [
'grpc_test_util',
'grpc++_test_util',
+ 'grpc++_core_stats',
'grpc++',
'grpc',
],
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 7541bd5c92..3277cefc2d 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -34,6 +34,7 @@
#include "src/core/ext/transport/chttp2/transport/varint.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/compression/stream_compression.h"
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/timer.h"
@@ -1258,6 +1259,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
grpc_transport_stream_op_batch_payload *op_payload = op->payload;
grpc_chttp2_transport *t = s->t;
+ GRPC_STATS_INC_HTTP2_OP_BATCHES(exec_ctx);
+
if (GRPC_TRACER_ON(grpc_http_trace)) {
char *str = grpc_transport_stream_op_batch_string(op);
gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str,
@@ -1291,11 +1294,13 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->cancel_stream) {
+ GRPC_STATS_INC_HTTP2_OP_CANCEL(exec_ctx);
grpc_chttp2_cancel_stream(exec_ctx, t, s,
op_payload->cancel_stream.cancel_error);
}
if (op->send_initial_metadata) {
+ GRPC_STATS_INC_HTTP2_OP_SEND_INITIAL_METADATA(exec_ctx);
GPR_ASSERT(s->send_initial_metadata_finished == NULL);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
@@ -1373,6 +1378,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->send_message) {
+ GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE(exec_ctx);
+ GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE(
+ exec_ctx, op->payload->send_message.send_message->length);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
if (s->write_closed) {
@@ -1410,6 +1418,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->send_trailing_metadata) {
+ GRPC_STATS_INC_HTTP2_OP_SEND_TRAILING_METADATA(exec_ctx);
GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->send_trailing_metadata_finished = add_closure_barrier(on_complete);
@@ -1459,6 +1468,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->recv_initial_metadata) {
+ GRPC_STATS_INC_HTTP2_OP_RECV_INITIAL_METADATA(exec_ctx);
GPR_ASSERT(s->recv_initial_metadata_ready == NULL);
s->recv_initial_metadata_ready =
op_payload->recv_initial_metadata.recv_initial_metadata_ready;
@@ -1470,6 +1480,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->recv_message) {
+ GRPC_STATS_INC_HTTP2_OP_RECV_MESSAGE(exec_ctx);
size_t already_received;
GPR_ASSERT(s->recv_message_ready == NULL);
GPR_ASSERT(!s->pending_byte_stream);
@@ -1491,6 +1502,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->recv_trailing_metadata) {
+ GRPC_STATS_INC_HTTP2_OP_RECV_TRAILING_METADATA(exec_ctx);
GPR_ASSERT(s->recv_trailing_metadata_finished == NULL);
s->recv_trailing_metadata_finished = add_closure_barrier(on_complete);
s->recv_trailing_metadata =
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 80eb51ff0d..c16ffaa5ef 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -22,6 +22,7 @@
#include <grpc/support/log.h>
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/http2_errors.h"
@@ -116,6 +117,7 @@ static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx,
&pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]);
grpc_slice_buffer_add(&t->outbuf,
grpc_chttp2_ping_create(false, pq->inflight_id));
+ GRPC_STATS_INC_HTTP2_PINGS_SENT(exec_ctx);
t->ping_state.last_ping_sent_time = now;
t->ping_state.pings_before_data_required -=
(t->ping_state.pings_before_data_required != 0);
@@ -171,6 +173,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
grpc_chttp2_stream *s;
+ GRPC_STATS_INC_HTTP2_WRITES_BEGUN(exec_ctx);
+
GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 0);
if (t->dirtied_local_settings && !t->sent_local_settings) {
diff --git a/src/core/lib/debug/stats.c b/src/core/lib/debug/stats.c
index 4dbd94c724..5079ed2ffa 100644
--- a/src/core/lib/debug/stats.c
+++ b/src/core/lib/debug/stats.c
@@ -45,7 +45,98 @@ void grpc_stats_collect(grpc_stats_data *output) {
output->counters[i] += gpr_atm_no_barrier_load(
&grpc_stats_per_cpu_storage[core].counters[i]);
}
+ for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_BUCKETS; i++) {
+ output->histograms[i] += gpr_atm_no_barrier_load(
+ &grpc_stats_per_cpu_storage[core].histograms[i]);
+ }
+ }
+}
+
+void grpc_stats_diff(const grpc_stats_data *b, const grpc_stats_data *a,
+ grpc_stats_data *c) {
+ for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ c->counters[i] = b->counters[i] - a->counters[i];
+ }
+ for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_BUCKETS; i++) {
+ c->histograms[i] = b->histograms[i] - a->histograms[i];
+ }
+}
+
+int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, double value,
+ const double *table, int table_size) {
+ GRPC_STATS_INC_HISTOGRAM_SLOW_LOOKUPS(exec_ctx);
+ if (value < 0.0) return 0;
+ if (value >= table[table_size - 1]) return table_size - 1;
+ int a = 0;
+ int b = table_size - 1;
+ while (a < b) {
+ int c = a + ((b - a) / 2);
+ if (value < table[c]) {
+ b = c - 1;
+ } else if (value > table[c]) {
+ a = c + 1;
+ } else {
+ return c;
+ }
+ }
+ return a;
+}
+
+size_t grpc_stats_histo_count(const grpc_stats_data *stats,
+ grpc_stats_histograms histogram) {
+ size_t sum = 0;
+ for (int i = 0; i < grpc_stats_histo_buckets[histogram]; i++) {
+ sum += (size_t)stats->histograms[grpc_stats_histo_start[histogram] + i];
+ }
+ return sum;
+}
+
+static double threshold_for_count_below(const gpr_atm *bucket_counts,
+ const double *bucket_boundaries,
+ int num_buckets, double count_below) {
+ double count_so_far;
+ double lower_bound;
+ double upper_bound;
+ int lower_idx;
+ int upper_idx;
+
+ /* find the lowest bucket that gets us above count_below */
+ count_so_far = 0.0;
+ for (lower_idx = 0; lower_idx < num_buckets; lower_idx++) {
+ count_so_far += (double)bucket_counts[lower_idx];
+ if (count_so_far >= count_below) {
+ break;
+ }
}
+ if (count_so_far == count_below) {
+ /* this bucket hits the threshold exactly... we should be midway through
+ any run of zero values following the bucket */
+ for (upper_idx = lower_idx + 1; upper_idx < num_buckets; upper_idx++) {
+ if (bucket_counts[upper_idx]) {
+ break;
+ }
+ }
+ return (bucket_boundaries[lower_idx] + bucket_boundaries[upper_idx]) / 2.0;
+ } else {
+ /* treat values as uniform throughout the bucket, and find where this value
+ should lie */
+ lower_bound = bucket_boundaries[lower_idx];
+ upper_bound = bucket_boundaries[lower_idx + 1];
+ return upper_bound -
+ (upper_bound - lower_bound) * (count_so_far - count_below) /
+ (double)bucket_counts[lower_idx];
+ }
+}
+
+double grpc_stats_histo_percentile(const grpc_stats_data *stats,
+ grpc_stats_histograms histogram,
+ double percentile) {
+ size_t count = grpc_stats_histo_count(stats, histogram);
+ if (count == 0) return 0.0;
+ return threshold_for_count_below(
+ stats->histograms + grpc_stats_histo_start[histogram],
+ grpc_stats_histo_bucket_boundaries[histogram],
+ grpc_stats_histo_buckets[histogram], (double)count * percentile / 100.0);
}
char *grpc_stats_data_as_json(const grpc_stats_data *data) {
@@ -60,6 +151,25 @@ char *grpc_stats_data_as_json(const grpc_stats_data *data) {
gpr_strvec_add(&v, tmp);
is_first = false;
}
+ for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
+ gpr_asprintf(&tmp, "%s\"%s\": [", is_first ? "" : ", ",
+ grpc_stats_histogram_name[i]);
+ gpr_strvec_add(&v, tmp);
+ for (int j = 0; j < grpc_stats_histo_buckets[i]; j++) {
+ gpr_asprintf(&tmp, "%s%" PRIdPTR, j == 0 ? "" : ",",
+ data->histograms[grpc_stats_histo_start[i] + j]);
+ gpr_strvec_add(&v, tmp);
+ }
+ gpr_asprintf(&tmp, "], \"%s_bkt\": [", grpc_stats_histogram_name[i]);
+ gpr_strvec_add(&v, tmp);
+ for (int j = 0; j < grpc_stats_histo_buckets[i]; j++) {
+ gpr_asprintf(&tmp, "%s%lf", j == 0 ? "" : ",",
+ grpc_stats_histo_bucket_boundaries[i][j]);
+ gpr_strvec_add(&v, tmp);
+ }
+ gpr_strvec_add(&v, gpr_strdup("]"));
+ is_first = false;
+ }
gpr_strvec_add(&v, gpr_strdup("}"));
tmp = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v);
diff --git a/src/core/lib/debug/stats.h b/src/core/lib/debug/stats.h
index 563b108dff..c440ab3b66 100644
--- a/src/core/lib/debug/stats.h
+++ b/src/core/lib/debug/stats.h
@@ -25,6 +25,7 @@
typedef struct grpc_stats_data {
gpr_atm counters[GRPC_STATS_COUNTER_COUNT];
+ gpr_atm histograms[GRPC_STATS_HISTOGRAM_BUCKETS];
} grpc_stats_data;
extern grpc_stats_data *grpc_stats_per_cpu_storage;
@@ -36,9 +37,25 @@ extern grpc_stats_data *grpc_stats_per_cpu_storage;
(gpr_atm_no_barrier_fetch_add( \
&GRPC_THREAD_STATS_DATA((exec_ctx))->counters[(ctr)], 1))
+#define GRPC_STATS_INC_HISTOGRAM(exec_ctx, histogram, index) \
+ (gpr_atm_no_barrier_fetch_add( \
+ &GRPC_THREAD_STATS_DATA((exec_ctx)) \
+ ->histograms[histogram##_FIRST_SLOT + (index)], \
+ 1))
+
void grpc_stats_init(void);
void grpc_stats_shutdown(void);
void grpc_stats_collect(grpc_stats_data *output);
+// c = b-a
+void grpc_stats_diff(const grpc_stats_data *b, const grpc_stats_data *a,
+ grpc_stats_data *c);
char *grpc_stats_data_as_json(const grpc_stats_data *data);
+int grpc_stats_histo_find_bucket_slow(grpc_exec_ctx *exec_ctx, double value,
+ const double *table, int table_size);
+double grpc_stats_histo_percentile(const grpc_stats_data *data,
+ grpc_stats_histograms histogram,
+ double percentile);
+size_t grpc_stats_histo_count(const grpc_stats_data *data,
+ grpc_stats_histograms histogram);
#endif
diff --git a/src/core/lib/debug/stats_data.c b/src/core/lib/debug/stats_data.c
index 2203358a7e..9277ee57b2 100644
--- a/src/core/lib/debug/stats_data.c
+++ b/src/core/lib/debug/stats_data.c
@@ -20,6 +20,176 @@
#include "src/core/lib/debug/stats_data.h"
const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {
- "client_calls_created", "server_calls_created", "syscall_write",
- "syscall_read", "syscall_poll", "syscall_wait",
+ "client_calls_created",
+ "server_calls_created",
+ "syscall_poll",
+ "syscall_wait",
+ "histogram_slow_lookups",
+ "syscall_write",
+ "syscall_read",
+ "http2_op_batches",
+ "http2_op_cancel",
+ "http2_op_send_initial_metadata",
+ "http2_op_send_message",
+ "http2_op_send_trailing_metadata",
+ "http2_op_recv_initial_metadata",
+ "http2_op_recv_message",
+ "http2_op_recv_trailing_metadata",
+ "http2_pings_sent",
+ "http2_writes_begun",
+ "combiner_locks_initiated",
+ "combiner_locks_scheduled_items",
+ "combiner_locks_scheduled_final_items",
+ "combiner_locks_offloaded",
+ "executor_scheduled_items",
+ "executor_scheduled_to_self",
+ "executor_wakeup_initiated",
+ "executor_queue_drained",
};
+const char *grpc_stats_histogram_name[GRPC_STATS_HISTOGRAM_COUNT] = {
+ "tcp_write_size", "tcp_write_iov_size", "tcp_read_size",
+ "tcp_read_offer", "tcp_read_iov_size", "http2_send_message_size",
+};
+const double grpc_stats_table_0[64] = {0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5.17974600698,
+ 6.70744217421,
+ 8.68571170472,
+ 11.2474451301,
+ 14.5647272503,
+ 18.8603969544,
+ 24.4230164536,
+ 31.6262554885,
+ 40.9539926456,
+ 53.032819969,
+ 68.6741343683,
+ 88.9286433193,
+ 115.156946285,
+ 149.120933174,
+ 193.102139541,
+ 250.055009057,
+ 323.805358672,
+ 419.307378404,
+ 542.976429747,
+ 703.119998467,
+ 910.495751121,
+ 1179.03418281,
+ 1526.77440013,
+ 1977.07590065,
+ 2560.18775048,
+ 3315.28056941,
+ 4293.07782286,
+ 5559.26317765,
+ 7198.89281155,
+ 9322.10907382,
+ 12071.5393129,
+ 15631.8768886,
+ 20242.2879738,
+ 26212.4775761,
+ 33943.4940145,
+ 43954.6693961,
+ 56918.5058232,
+ 73705.8508152,
+ 95444.3966128,
+ 123594.433061,
+ 160046.942783,
+ 207250.628202,
+ 268376.403469,
+ 347530.401059,
+ 450029.801797,
+ 582760.01722,
+ 754637.218056,
+ 977207.279236,
+ 1265421.37565,
+ 1638640.32942,
+ 2121935.1758,
+ 2747771.31348,
+ 3558189.37227,
+ 4607629.29828,
+ 5966587.36485,
+ 7726351.7696,
+ 10005134.9318,
+ 12956014.428,
+ 16777216.0};
+const uint8_t grpc_stats_table_1[87] = {
+ 0, 1, 3, 3, 4, 6, 6, 7, 9, 9, 10, 12, 12, 13, 15, 15, 16, 18,
+ 18, 19, 21, 21, 22, 24, 24, 25, 27, 27, 28, 30, 30, 31, 32, 34, 34, 36,
+ 36, 37, 39, 39, 40, 42, 42, 43, 44, 46, 46, 47, 49, 49, 51, 51, 52, 53,
+ 55, 55, 56, 58, 58, 59, 61, 61, 63, 63, 64, 65, 67, 67, 68, 70, 70, 71,
+ 73, 73, 75, 75, 76, 77, 79, 79, 80, 82, 82, 83, 85, 85, 87};
+const double grpc_stats_table_2[64] = {0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12.0020736244,
+ 13.0954337532,
+ 14.2883963681,
+ 15.5900350167,
+ 17.0102498252,
+ 18.5598427974,
+ 20.2505999737,
+ 22.0953810747,
+ 24.1082173107,
+ 26.3044181014,
+ 28.7006875181,
+ 31.315251333,
+ 34.1679956422,
+ 37.2806181177,
+ 40.6767930374,
+ 44.3823513489,
+ 48.4254771375,
+ 52.8369219909,
+ 57.6502388927,
+ 62.902037423,
+ 68.6322622068,
+ 74.8844967285,
+ 81.7062948236,
+ 89.1495423679,
+ 97.2708519163,
+ 106.131993291,
+ 115.800363399,
+ 126.34949884,
+ 137.859635225,
+ 150.418317437,
+ 164.121065485,
+ 179.072101023,
+ 195.38514005,
+ 213.184257818,
+ 232.604832535,
+ 253.794575043,
+ 276.914652285,
+ 302.140913126,
+ 329.665225843,
+ 359.696937452,
+ 392.464465978,
+ 428.217037783,
+ 467.226583154,
+ 509.78980457,
+ 556.230433401,
+ 606.901692163,
+ 662.1889811,
+ 722.512809492,
+ 788.331994007,
+ 860.147148411,
+ 938.504491184,
+ 1024.0};
+const uint8_t grpc_stats_table_3[52] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52};
+const int grpc_stats_histo_buckets[6] = {64, 64, 64, 64, 64, 64};
+const int grpc_stats_histo_start[6] = {0, 64, 128, 192, 256, 320};
+const double *const grpc_stats_histo_bucket_boundaries[6] = {
+ grpc_stats_table_0, grpc_stats_table_2, grpc_stats_table_0,
+ grpc_stats_table_0, grpc_stats_table_2, grpc_stats_table_0};
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
index c9c2f65c30..4d1078dfdb 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -21,27 +21,274 @@
#ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H
#define GRPC_CORE_LIB_DEBUG_STATS_DATA_H
+#include <inttypes.h>
+
typedef enum {
GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED,
GRPC_STATS_COUNTER_SERVER_CALLS_CREATED,
- GRPC_STATS_COUNTER_SYSCALL_WRITE,
- GRPC_STATS_COUNTER_SYSCALL_READ,
GRPC_STATS_COUNTER_SYSCALL_POLL,
GRPC_STATS_COUNTER_SYSCALL_WAIT,
+ GRPC_STATS_COUNTER_HISTOGRAM_SLOW_LOOKUPS,
+ GRPC_STATS_COUNTER_SYSCALL_WRITE,
+ GRPC_STATS_COUNTER_SYSCALL_READ,
+ GRPC_STATS_COUNTER_HTTP2_OP_BATCHES,
+ GRPC_STATS_COUNTER_HTTP2_OP_CANCEL,
+ GRPC_STATS_COUNTER_HTTP2_OP_SEND_INITIAL_METADATA,
+ GRPC_STATS_COUNTER_HTTP2_OP_SEND_MESSAGE,
+ GRPC_STATS_COUNTER_HTTP2_OP_SEND_TRAILING_METADATA,
+ GRPC_STATS_COUNTER_HTTP2_OP_RECV_INITIAL_METADATA,
+ GRPC_STATS_COUNTER_HTTP2_OP_RECV_MESSAGE,
+ GRPC_STATS_COUNTER_HTTP2_OP_RECV_TRAILING_METADATA,
+ GRPC_STATS_COUNTER_HTTP2_PINGS_SENT,
+ GRPC_STATS_COUNTER_HTTP2_WRITES_BEGUN,
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_INITIATED,
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_ITEMS,
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS,
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED,
+ GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_ITEMS,
+ GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_TO_SELF,
+ GRPC_STATS_COUNTER_EXECUTOR_WAKEUP_INITIATED,
+ GRPC_STATS_COUNTER_EXECUTOR_QUEUE_DRAINED,
GRPC_STATS_COUNTER_COUNT
} grpc_stats_counters;
+extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];
+typedef enum {
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE,
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE,
+ GRPC_STATS_HISTOGRAM_TCP_READ_SIZE,
+ GRPC_STATS_HISTOGRAM_TCP_READ_OFFER,
+ GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE,
+ GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE,
+ GRPC_STATS_HISTOGRAM_COUNT
+} grpc_stats_histograms;
+extern const char *grpc_stats_histogram_name[GRPC_STATS_HISTOGRAM_COUNT];
+typedef enum {
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE_FIRST_SLOT = 0,
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE_FIRST_SLOT = 64,
+ GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_TCP_READ_SIZE_FIRST_SLOT = 128,
+ GRPC_STATS_HISTOGRAM_TCP_READ_SIZE_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_TCP_READ_OFFER_FIRST_SLOT = 192,
+ GRPC_STATS_HISTOGRAM_TCP_READ_OFFER_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE_FIRST_SLOT = 256,
+ GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE_FIRST_SLOT = 320,
+ GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE_BUCKETS = 64,
+ GRPC_STATS_HISTOGRAM_BUCKETS = 384
+} grpc_stats_histogram_constants;
#define GRPC_STATS_INC_CLIENT_CALLS_CREATED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED)
#define GRPC_STATS_INC_SERVER_CALLS_CREATED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SERVER_CALLS_CREATED)
-#define GRPC_STATS_INC_SYSCALL_WRITE(exec_ctx) \
- GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_WRITE)
-#define GRPC_STATS_INC_SYSCALL_READ(exec_ctx) \
- GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_READ)
#define GRPC_STATS_INC_SYSCALL_POLL(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_POLL)
#define GRPC_STATS_INC_SYSCALL_WAIT(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_WAIT)
-extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];
+#define GRPC_STATS_INC_HISTOGRAM_SLOW_LOOKUPS(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HISTOGRAM_SLOW_LOOKUPS)
+#define GRPC_STATS_INC_SYSCALL_WRITE(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_WRITE)
+#define GRPC_STATS_INC_SYSCALL_READ(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_SYSCALL_READ)
+#define GRPC_STATS_INC_HTTP2_OP_BATCHES(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_OP_BATCHES)
+#define GRPC_STATS_INC_HTTP2_OP_CANCEL(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_OP_CANCEL)
+#define GRPC_STATS_INC_HTTP2_OP_SEND_INITIAL_METADATA(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_HTTP2_OP_SEND_INITIAL_METADATA)
+#define GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_OP_SEND_MESSAGE)
+#define GRPC_STATS_INC_HTTP2_OP_SEND_TRAILING_METADATA(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_HTTP2_OP_SEND_TRAILING_METADATA)
+#define GRPC_STATS_INC_HTTP2_OP_RECV_INITIAL_METADATA(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_HTTP2_OP_RECV_INITIAL_METADATA)
+#define GRPC_STATS_INC_HTTP2_OP_RECV_MESSAGE(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_OP_RECV_MESSAGE)
+#define GRPC_STATS_INC_HTTP2_OP_RECV_TRAILING_METADATA(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_HTTP2_OP_RECV_TRAILING_METADATA)
+#define GRPC_STATS_INC_HTTP2_PINGS_SENT(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_PINGS_SENT)
+#define GRPC_STATS_INC_HTTP2_WRITES_BEGUN(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_HTTP2_WRITES_BEGUN)
+#define GRPC_STATS_INC_COMBINER_LOCKS_INITIATED(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_INITIATED)
+#define GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_ITEMS)
+#define GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS(exec_ctx) \
+ GRPC_STATS_INC_COUNTER( \
+ (exec_ctx), GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS)
+#define GRPC_STATS_INC_COMBINER_LOCKS_OFFLOADED(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED)
+#define GRPC_STATS_INC_EXECUTOR_SCHEDULED_ITEMS(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_ITEMS)
+#define GRPC_STATS_INC_EXECUTOR_SCHEDULED_TO_SELF(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_TO_SELF)
+#define GRPC_STATS_INC_EXECUTOR_WAKEUP_INITIATED(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), \
+ GRPC_STATS_COUNTER_EXECUTOR_WAKEUP_INITIATED)
+#define GRPC_STATS_INC_EXECUTOR_QUEUE_DRAINED(exec_ctx) \
+ GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_EXECUTOR_QUEUE_DRAINED)
+#define GRPC_STATS_INC_TCP_WRITE_SIZE(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 5.000000) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE, (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4715268809856909312ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE, \
+ grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_SIZE, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_0, 64)); \
+ } \
+ } \
+ } while (false)
+#define GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 12.000000) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE, (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4652218415073722368ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE, \
+ grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 49)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_WRITE_IOV_SIZE, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_2, 64)); \
+ } \
+ } \
+ } while (false)
+#define GRPC_STATS_INC_TCP_READ_SIZE(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 5.000000) { \
+ GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE, \
+ (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4715268809856909312ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE, \
+ grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_SIZE, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_0, 64)); \
+ } \
+ } \
+ } while (false)
+#define GRPC_STATS_INC_TCP_READ_OFFER(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 5.000000) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER, (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4715268809856909312ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER, \
+ grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_OFFER, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_0, 64)); \
+ } \
+ } \
+ } while (false)
+#define GRPC_STATS_INC_TCP_READ_IOV_SIZE(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 12.000000) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE, (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4652218415073722368ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE, \
+ grpc_stats_table_3[((_val.uint - 4622945017495814144ull) >> 49)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_TCP_READ_IOV_SIZE, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_2, 64)); \
+ } \
+ } \
+ } while (false)
+#define GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE(exec_ctx, value) \
+ do { \
+ union { \
+ double dbl; \
+ uint64_t uint; \
+ } _val; \
+ _val.dbl = (double)(value); \
+ if (_val.dbl < 0) _val.dbl = 0; \
+ if (_val.dbl < 5.000000) { \
+ GRPC_STATS_INC_HISTOGRAM((exec_ctx), \
+ GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE, \
+ (int)_val.dbl); \
+ } else { \
+ if (_val.uint < 4715268809856909312ull) { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE, \
+ grpc_stats_table_1[((_val.uint - 4617315517961601024ull) >> 50)]); \
+ } else { \
+ GRPC_STATS_INC_HISTOGRAM( \
+ (exec_ctx), GRPC_STATS_HISTOGRAM_HTTP2_SEND_MESSAGE_SIZE, \
+ grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, \
+ grpc_stats_table_0, 64)); \
+ } \
+ } \
+ } while (false)
+extern const double grpc_stats_table_0[64];
+extern const uint8_t grpc_stats_table_1[87];
+extern const double grpc_stats_table_2[64];
+extern const uint8_t grpc_stats_table_3[52];
+extern const int grpc_stats_histo_buckets[6];
+extern const int grpc_stats_histo_start[6];
+extern const double *const grpc_stats_histo_bucket_boundaries[6];
#endif /* GRPC_CORE_LIB_DEBUG_STATS_DATA_H */
diff --git a/src/core/lib/debug/stats_data.yaml b/src/core/lib/debug/stats_data.yaml
index 8afe48f5cd..a0d042a688 100644
--- a/src/core/lib/debug/stats_data.yaml
+++ b/src/core/lib/debug/stats_data.yaml
@@ -1,9 +1,67 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
# Stats data declaration
-# use tools/codegen/core/gen_stats_data.py to turn this into stats_data.h
+# use tools / codegen / core / gen_stats_data.py to turn this into stats_data.h
+# overall
- counter: client_calls_created
- counter: server_calls_created
-- counter: syscall_write
-- counter: syscall_read
+# polling
- counter: syscall_poll
- counter: syscall_wait
+# stats system
+- counter: histogram_slow_lookups
+# tcp
+- counter: syscall_write
+- counter: syscall_read
+- histogram: tcp_write_size
+ max: 16777216 # 16 meg max write tracked
+ buckets: 64
+- histogram: tcp_write_iov_size
+ max: 1024
+ buckets: 64
+- histogram: tcp_read_size
+ max: 16777216
+ buckets: 64
+- histogram: tcp_read_offer
+ max: 16777216
+ buckets: 64
+- histogram: tcp_read_iov_size
+ max: 1024
+ buckets: 64
+# chttp2
+- counter: http2_op_batches
+- counter: http2_op_cancel
+- counter: http2_op_send_initial_metadata
+- counter: http2_op_send_message
+- counter: http2_op_send_trailing_metadata
+- counter: http2_op_recv_initial_metadata
+- counter: http2_op_recv_message
+- counter: http2_op_recv_trailing_metadata
+- histogram: http2_send_message_size
+ max: 16777216
+ buckets: 64
+- counter: http2_pings_sent
+- counter: http2_writes_begun
+# combiner locks
+- counter: combiner_locks_initiated
+- counter: combiner_locks_scheduled_items
+- counter: combiner_locks_scheduled_final_items
+- counter: combiner_locks_offloaded
+# executor
+- counter: executor_scheduled_items
+- counter: executor_scheduled_to_self
+- counter: executor_wakeup_initiated
+- counter: executor_queue_drained
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
index 9b66987b68..4c1503bddb 100644
--- a/src/core/lib/iomgr/combiner.c
+++ b/src/core/lib/iomgr/combiner.c
@@ -24,6 +24,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/profiling/timers.h"
@@ -153,6 +154,7 @@ static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx,
static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
grpc_error *error) {
+ GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx);
GPR_TIMER_BEGIN("combiner.execute", 0);
grpc_combiner *lock = COMBINER_FROM_CLOSURE_SCHEDULER(cl, scheduler);
gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
@@ -160,6 +162,7 @@ static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
"C:%p grpc_combiner_execute c=%p last=%" PRIdPTR,
lock, cl, last));
if (last == 1) {
+ GRPC_STATS_INC_COMBINER_LOCKS_INITIATED(exec_ctx);
gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null,
(gpr_atm)exec_ctx);
// first element on this list: add it to the list of combiner locks
@@ -195,6 +198,7 @@ static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
}
static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
+ GRPC_STATS_INC_COMBINER_LOCKS_OFFLOADED(exec_ctx);
move_next(exec_ctx);
GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload", lock));
GRPC_CLOSURE_SCHED(exec_ctx, &lock->offload, GRPC_ERROR_NONE);
@@ -325,6 +329,7 @@ static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
static void combiner_finally_exec(grpc_exec_ctx *exec_ctx,
grpc_closure *closure, grpc_error *error) {
+ GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS(exec_ctx);
grpc_combiner *lock =
COMBINER_FROM_CLOSURE_SCHEDULER(closure, finally_scheduler);
GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
index 7621a7fe75..dd5cb2a64e 100644
--- a/src/core/lib/iomgr/executor.c
+++ b/src/core/lib/iomgr/executor.c
@@ -28,6 +28,7 @@
#include <grpc/support/tls.h>
#include <grpc/support/useful.h>
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/support/spinlock.h"
@@ -145,6 +146,7 @@ static void executor_thread(void *arg) {
gpr_mu_unlock(&ts->mu);
break;
}
+ GRPC_STATS_INC_EXECUTOR_QUEUE_DRAINED(&exec_ctx);
grpc_closure_list exec = ts->elems;
ts->elems = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT;
gpr_mu_unlock(&ts->mu);
@@ -158,6 +160,7 @@ static void executor_thread(void *arg) {
static void executor_push(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error) {
size_t cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads);
+ GRPC_STATS_INC_EXECUTOR_SCHEDULED_ITEMS(exec_ctx);
if (cur_thread_count == 0) {
grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
return;
@@ -165,9 +168,12 @@ static void executor_push(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
thread_state *ts = (thread_state *)gpr_tls_get(&g_this_thread_state);
if (ts == NULL) {
ts = &g_thread_state[GPR_HASH_POINTER(exec_ctx, cur_thread_count)];
+ } else {
+ GRPC_STATS_INC_EXECUTOR_SCHEDULED_TO_SELF(exec_ctx);
}
gpr_mu_lock(&ts->mu);
if (grpc_closure_list_empty(ts->elems)) {
+ GRPC_STATS_INC_EXECUTOR_WAKEUP_INITIATED(exec_ctx);
gpr_cv_signal(&ts->cv);
}
grpc_closure_list_append(&ts->elems, closure, error);
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 7e789cc5b5..793147f30a 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -67,7 +67,6 @@ typedef struct {
grpc_fd *em_fd;
int fd;
bool finished_edge;
- msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
double target_length;
double bytes_read_this_round;
gpr_refcount refcount;
@@ -240,7 +239,6 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
size_t i;
GPR_ASSERT(!tcp->finished_edge);
- GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
GPR_TIMER_BEGIN("tcp_continue_read", 0);
@@ -252,11 +250,14 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
- msg.msg_iovlen = tcp->iov_size;
+ msg.msg_iovlen = tcp->incoming_buffer->count;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
+ GRPC_STATS_INC_TCP_READ_OFFER(exec_ctx, tcp->incoming_buffer->length);
+ GRPC_STATS_INC_TCP_READ_IOV_SIZE(exec_ctx, tcp->incoming_buffer->count);
+
GPR_TIMER_BEGIN("recvmsg", 0);
do {
GRPC_STATS_INC_SYSCALL_READ(exec_ctx);
@@ -287,6 +288,7 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
+ GRPC_STATS_INC_TCP_READ_SIZE(exec_ctx, read_bytes);
add_to_estimate(tcp, (size_t)read_bytes);
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
if ((size_t)read_bytes < tcp->incoming_buffer->length) {
@@ -403,6 +405,9 @@ static bool tcp_flush(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
msg.msg_controllen = 0;
msg.msg_flags = 0;
+ GRPC_STATS_INC_TCP_WRITE_SIZE(exec_ctx, sending_length);
+ GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(exec_ctx, iov_size);
+
GPR_TIMER_BEGIN("sendmsg", 1);
do {
/* TODO(klempner): Cork if this is a partial write */
@@ -621,7 +626,6 @@ grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *em_fd,
tcp->min_read_chunk_size = tcp_min_read_chunk_size;
tcp->max_read_chunk_size = tcp_max_read_chunk_size;
tcp->bytes_read_this_round = 0;
- tcp->iov_size = 1;
tcp->finished_edge = true;
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);
diff --git a/src/cpp/util/core_stats.cc b/src/cpp/util/core_stats.cc
new file mode 100644
index 0000000000..edf0b1bb67
--- /dev/null
+++ b/src/cpp/util/core_stats.cc
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/cpp/util/core_stats.h"
+
+#include <grpc/support/log.h>
+
+using grpc::core::Bucket;
+using grpc::core::Histogram;
+using grpc::core::Metric;
+using grpc::core::Stats;
+
+namespace grpc {
+
+void CoreStatsToProto(const grpc_stats_data& core, Stats* proto) {
+ for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ Metric* m = proto->add_metrics();
+ m->set_name(grpc_stats_counter_name[i]);
+ m->set_count(core.counters[i]);
+ }
+ for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
+ Metric* m = proto->add_metrics();
+ m->set_name(grpc_stats_histogram_name[i]);
+ Histogram* h = m->mutable_histogram();
+ for (int j = 0; j < grpc_stats_histo_buckets[i]; j++) {
+ Bucket* b = h->add_buckets();
+ b->set_start(grpc_stats_histo_bucket_boundaries[i][j]);
+ b->set_count(core.histograms[grpc_stats_histo_start[i] + j]);
+ }
+ }
+}
+
+void ProtoToCoreStats(const grpc::core::Stats& proto, grpc_stats_data* core) {
+ memset(core, 0, sizeof(*core));
+ for (const auto& m : proto.metrics()) {
+ switch (m.value_case()) {
+ case Metric::VALUE_NOT_SET:
+ break;
+ case Metric::kCount:
+ for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ if (m.name() == grpc_stats_counter_name[i]) {
+ core->counters[i] = m.count();
+ break;
+ }
+ }
+ break;
+ case Metric::kHistogram:
+ for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
+ if (m.name() == grpc_stats_histogram_name[i]) {
+ const auto& h = m.histogram();
+ bool valid = true;
+ if (grpc_stats_histo_buckets[i] != h.buckets_size()) valid = false;
+ for (int j = 0; valid && j < h.buckets_size(); j++) {
+ if (grpc_stats_histo_bucket_boundaries[i][j] !=
+ h.buckets(j).start()) {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ gpr_log(GPR_ERROR,
+ "Found histogram %s but shape is different from proto",
+ m.name().c_str());
+ }
+ for (int j = 0; valid && j < h.buckets_size(); j++) {
+ core->histograms[grpc_stats_histo_start[i] + j] =
+ h.buckets(j).count();
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+} // namespace grpc
diff --git a/src/cpp/util/core_stats.h b/src/cpp/util/core_stats.h
new file mode 100644
index 0000000000..00e38bf266
--- /dev/null
+++ b/src/cpp/util/core_stats.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_UTIL_CORE_STATS_H
+#define GRPC_INTERNAL_CPP_UTIL_CORE_STATS_H
+
+#include "src/proto/grpc/core/stats.pb.h"
+
+extern "C" {
+#include "src/core/lib/debug/stats.h"
+}
+
+namespace grpc {
+
+void CoreStatsToProto(const grpc_stats_data& core, grpc::core::Stats* proto);
+void ProtoToCoreStats(const grpc::core::Stats& proto, grpc_stats_data* core);
+
+} // namespace grpc
+
+#endif // GRPC_INTERNAL_CPP_UTIL_CORE_STATS_H
diff --git a/src/proto/grpc/core/stats.proto b/src/proto/grpc/core/stats.proto
new file mode 100644
index 0000000000..ac181b0439
--- /dev/null
+++ b/src/proto/grpc/core/stats.proto
@@ -0,0 +1,38 @@
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package grpc.core;
+
+message Bucket {
+ double start = 1;
+ uint64 count = 2;
+}
+
+message Histogram {
+ repeated Bucket buckets = 1;
+}
+
+message Metric {
+ string name = 1;
+ oneof value {
+ uint64 count = 10;
+ Histogram histogram = 11;
+ }
+}
+
+message Stats {
+ repeated Metric metrics = 1;
+}
diff --git a/src/proto/grpc/testing/stats.proto b/src/proto/grpc/testing/stats.proto
index c738c4f895..a0f84ddbce 100644
--- a/src/proto/grpc/testing/stats.proto
+++ b/src/proto/grpc/testing/stats.proto
@@ -16,6 +16,8 @@ syntax = "proto3";
package grpc.testing;
+import "src/proto/grpc/core/stats.proto";
+
message ServerStats {
// wall clock time change in seconds since last reset
double time_elapsed = 1;
@@ -35,6 +37,9 @@ message ServerStats {
// Number of polls called inside completion queue
uint64 cq_poll_count = 6;
+
+ // Core library stats
+ grpc.core.Stats core_stats = 7;
}
// Histogram params based on grpc/support/histogram.c
@@ -72,4 +77,7 @@ message ClientStats {
// Number of polls called inside completion queue
uint64 cq_poll_count = 6;
+
+ // Core library stats
+ grpc.core.Stats core_stats = 7;
}
diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc
index 415d27445f..b0caa48cd0 100644
--- a/test/cpp/microbenchmarks/helpers.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -31,10 +31,17 @@ void TrackCounters::Finish(benchmark::State &state) {
void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) {
grpc_stats_data stats_end;
grpc_stats_collect(&stats_end);
+ grpc_stats_data stats;
+ grpc_stats_diff(&stats_end, &stats_begin_, &stats);
for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
- out << " " << grpc_stats_counter_name[i] << "/iter:"
- << ((double)(stats_end.counters[i] - stats_begin_.counters[i]) /
- (double)state.iterations());
+ out << " " << grpc_stats_counter_name[i]
+ << "/iter:" << ((double)stats.counters[i] / (double)state.iterations());
+ }
+ for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
+ out << " " << grpc_stats_histogram_name[i] << "-median:"
+ << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 50.0)
+ << " " << grpc_stats_histogram_name[i] << "-99p:"
+ << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0);
}
#ifdef GPR_LOW_LEVEL_COUNTERS
grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index b1d90aa9c4..7fbaf63492 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -34,6 +34,7 @@
#include "src/proto/grpc/testing/payloads.pb.h"
#include "src/proto/grpc/testing/services.grpc.pb.h"
+#include "src/cpp/util/core_stats.h"
#include "test/cpp/qps/histogram.h"
#include "test/cpp/qps/interarrival.h"
#include "test/cpp/qps/usage_timer.h"
@@ -172,6 +173,9 @@ class Client {
timer_result = timer_->Mark();
}
+ grpc_stats_data core_stats;
+ grpc_stats_collect(&core_stats);
+
ClientStats stats;
latencies.FillProto(stats.mutable_latencies());
for (StatusHistogram::const_iterator it = statuses.begin();
@@ -184,6 +188,7 @@ class Client {
stats.set_time_system(timer_result.system);
stats.set_time_user(timer_result.user);
stats.set_cq_poll_count(poll_count);
+ CoreStatsToProto(core_stats, stats.mutable_core_stats());
return stats;
}
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index a45b10bcb8..3c99bda144 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -26,6 +26,7 @@
#include "test/cpp/qps/stats.h"
#include <grpc++/client_context.h>
+#include "src/cpp/util/core_stats.h"
#include "src/proto/grpc/testing/services.grpc.pb.h"
namespace grpc {
@@ -85,6 +86,33 @@ void GprLogReporter::ReportQPS(const ScenarioResult& result) {
gpr_log(GPR_INFO, "successful requests/second: %.1f",
result.summary().successful_requests_per_second());
}
+ for (int i = 0; i < result.client_stats_size(); i++) {
+ if (result.client_stats(i).has_core_stats()) {
+ ReportCoreStats("CLIENT", i, result.client_stats(i).core_stats());
+ }
+ }
+ for (int i = 0; i < result.server_stats_size(); i++) {
+ if (result.server_stats(i).has_core_stats()) {
+ ReportCoreStats("SERVER", i, result.server_stats(i).core_stats());
+ }
+ }
+}
+
+void GprLogReporter::ReportCoreStats(const char* name, int idx,
+ const grpc::core::Stats& stats) {
+ grpc_stats_data data;
+ ProtoToCoreStats(stats, &data);
+ for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ gpr_log(GPR_DEBUG, "%s[%d].%s = %" PRIdPTR, name, idx,
+ grpc_stats_counter_name[i], data.counters[i]);
+ }
+ for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
+ gpr_log(GPR_DEBUG, "%s[%d].%s = %lf/%lf/%lf (50/95/99%%-ile)", name, idx,
+ grpc_stats_histogram_name[i],
+ grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 50),
+ grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 95),
+ grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 99));
+ }
}
void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) {
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 321be2a97f..1d7b2b54e7 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -104,6 +104,9 @@ class GprLogReporter : public Reporter {
void ReportCpuUsage(const ScenarioResult& result) override;
void ReportPollCount(const ScenarioResult& result) override;
void ReportQueriesPerCpuSec(const ScenarioResult& result) override;
+
+ void ReportCoreStats(const char* name, int idx,
+ const grpc::core::Stats& stats);
};
/** Dumps the report to a JSON file. */
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 3d6f347cae..16d101d5e6 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -26,6 +26,7 @@
#include <grpc/support/log.h>
#include <vector>
+#include "src/cpp/util/core_stats.h"
#include "src/proto/grpc/testing/control.pb.h"
#include "src/proto/grpc/testing/messages.pb.h"
#include "test/core/end2end/data/ssl_test_data.h"
@@ -63,6 +64,9 @@ class Server {
timer_result = timer_->Mark();
}
+ grpc_stats_data core_stats;
+ grpc_stats_collect(&core_stats);
+
ServerStats stats;
stats.set_time_elapsed(timer_result.wall);
stats.set_time_system(timer_result.system);
@@ -70,6 +74,7 @@ class Server {
stats.set_total_cpu_time(timer_result.total_cpu_time);
stats.set_idle_cpu_time(timer_result.idle_cpu_time);
stats.set_cq_poll_count(poll_count);
+ CoreStatsToProto(core_stats, stats.mutable_core_stats());
return stats;
}
diff --git a/tools/codegen/core/gen_stats_data.py b/tools/codegen/core/gen_stats_data.py
index bc601a89a7..85489eb7dc 100755
--- a/tools/codegen/core/gen_stats_data.py
+++ b/tools/codegen/core/gen_stats_data.py
@@ -15,21 +15,143 @@
# limitations under the License.
import collections
+import ctypes
+import math
import sys
import yaml
with open('src/core/lib/debug/stats_data.yaml') as f:
attrs = yaml.load(f.read())
-Counter = collections.namedtuple('Counter', 'name')
+types = (
+ (collections.namedtuple('Counter', 'name'), []),
+ (collections.namedtuple('Histogram', 'name max buckets'), []),
+)
-counters = []
+inst_map = dict((t[0].__name__, t[1]) for t in types)
+
+stats = []
for attr in attrs:
- if 'counter' in attr:
- counters.append(Counter(name=attr['counter']))
+ found = False
+ for t, lst in types:
+ t_name = t.__name__.lower()
+ if t_name in attr:
+ name = attr[t_name]
+ del attr[t_name]
+ lst.append(t(name=name, **attr))
+ found = True
+ break
+ assert found, "Bad decl: %s" % attr
+
+def dbl2u64(d):
+ return ctypes.c_ulonglong.from_buffer(ctypes.c_double(d)).value
+
+def shift_works_until(mapped_bounds, shift_bits):
+ for i, ab in enumerate(zip(mapped_bounds, mapped_bounds[1:])):
+ a, b = ab
+ if (a >> shift_bits) == (b >> shift_bits):
+ return i
+ return len(mapped_bounds)
+
+def find_ideal_shift(mapped_bounds, max_size):
+ best = None
+ for shift_bits in reversed(range(0,64)):
+ n = shift_works_until(mapped_bounds, shift_bits)
+ if n == 0: continue
+ table_size = mapped_bounds[n-1] >> shift_bits
+ if table_size > max_size: continue
+ if table_size > 65535: continue
+ if best is None:
+ best = (shift_bits, n, table_size)
+ elif best[1] < n:
+ best = (shift_bits, n, table_size)
+ print best
+ return best
+
+def gen_map_table(mapped_bounds, shift_data):
+ tbl = []
+ cur = 0
+ mapped_bounds = [x >> shift_data[0] for x in mapped_bounds]
+ for i in range(0, mapped_bounds[shift_data[1]-1]):
+ while i > mapped_bounds[cur]:
+ cur += 1
+ tbl.append(mapped_bounds[cur])
+ return tbl
+
+static_tables = []
+
+def decl_static_table(values, type):
+ global static_tables
+ v = (type, values)
+ for i, vp in enumerate(static_tables):
+ if v == vp: return i
+ print "ADD TABLE: %s %r" % (type, values)
+ r = len(static_tables)
+ static_tables.append(v)
+ return r
+
+def type_for_uint_table(table):
+ mv = max(table)
+ if mv < 2**8:
+ return 'uint8_t'
+ elif mv < 2**16:
+ return 'uint16_t'
+ elif mv < 2**32:
+ return 'uint32_t'
else:
- print 'Error: bad attr %r' % attr
+ return 'uint64_t'
+
+def gen_bucket_code(histogram):
+ bounds = [0, 1]
+ done_trivial = False
+ done_unmapped = False
+ first_nontrivial = None
+ first_unmapped = None
+ while len(bounds) < histogram.buckets:
+ mul = math.pow(float(histogram.max) / bounds[-1],
+ 1.0 / (histogram.buckets - len(bounds)))
+ nextb = bounds[-1] * mul
+ if nextb < bounds[-1] + 1:
+ nextb = bounds[-1] + 1
+ elif not done_trivial:
+ done_trivial = True
+ first_nontrivial = len(bounds)
+ bounds.append(nextb)
+ bounds_idx = decl_static_table(bounds, 'double')
+ if done_trivial:
+ first_nontrivial_code = dbl2u64(first_nontrivial)
+ code_bounds = [dbl2u64(x) - first_nontrivial_code for x in bounds]
+ shift_data = find_ideal_shift(code_bounds[first_nontrivial:], 256 * histogram.buckets)
+ print first_nontrivial, shift_data, bounds
+ if shift_data is not None: print [hex(x >> shift_data[0]) for x in code_bounds[first_nontrivial:]]
+ code = 'do {\\\n'
+ code += ' union { double dbl; uint64_t uint; } _val;\\\n'
+ code += '_val.dbl = (double)(value);\\\n'
+ code += 'if (_val.dbl < 0) _val.dbl = 0;\\\n'
+ map_table = gen_map_table(code_bounds[first_nontrivial:], shift_data)
+ if first_nontrivial is None:
+ code += ('GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, (int)_val.dbl);\\\n'
+ % histogram.name.upper())
+ else:
+ code += 'if (_val.dbl < %f) {\\\n' % first_nontrivial
+ code += ('GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, (int)_val.dbl);\\\n'
+ % histogram.name.upper())
+ code += '} else {'
+ first_nontrivial_code = dbl2u64(first_nontrivial)
+ if shift_data is not None:
+ map_table_idx = decl_static_table(map_table, type_for_uint_table(map_table))
+ code += 'if (_val.uint < %dull) {\\\n' % ((map_table[-1] << shift_data[0]) + first_nontrivial_code)
+ code += 'GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, ' % histogram.name.upper()
+ code += 'grpc_stats_table_%d[((_val.uint - %dull) >> %d)]);\\\n' % (map_table_idx, first_nontrivial_code, shift_data[0])
+ code += '} else {\\\n'
+ code += 'GRPC_STATS_INC_HISTOGRAM((exec_ctx), GRPC_STATS_HISTOGRAM_%s, '% histogram.name.upper()
+ code += 'grpc_stats_histo_find_bucket_slow((exec_ctx), _val.dbl, grpc_stats_table_%d, %d));\\\n' % (bounds_idx, len(bounds))
+ if shift_data is not None:
+ code += '}'
+ code += '}'
+ code += '} while (false)'
+ return (code, bounds_idx)
# utility: print a big comment block into a set of files
def put_banner(files, banner):
@@ -61,17 +183,50 @@ with open('src/core/lib/debug/stats_data.h', 'w') as H:
print >>H, "#ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H"
print >>H, "#define GRPC_CORE_LIB_DEBUG_STATS_DATA_H"
print >>H
+ print >>H, "#include <inttypes.h>"
+ print >>H
+
+ for typename, instances in sorted(inst_map.items()):
+ print >>H, "typedef enum {"
+ for inst in instances:
+ print >>H, " GRPC_STATS_%s_%s," % (typename.upper(), inst.name.upper())
+ print >>H, " GRPC_STATS_%s_COUNT" % (typename.upper())
+ print >>H, "} grpc_stats_%ss;" % (typename.lower())
+ print >>H, "extern const char *grpc_stats_%s_name[GRPC_STATS_%s_COUNT];" % (
+ typename.lower(), typename.upper())
+
+ histo_start = []
+ histo_buckets = []
+ histo_bucket_boundaries = []
print >>H, "typedef enum {"
- for ctr in counters:
- print >>H, " GRPC_STATS_COUNTER_%s," % ctr.name.upper()
- print >>H, " GRPC_STATS_COUNTER_COUNT"
- print >>H, "} grpc_stats_counters;"
+ first_slot = 0
+ for histogram in inst_map['Histogram']:
+ histo_start.append(first_slot)
+ histo_buckets.append(histogram.buckets)
+ print >>H, " GRPC_STATS_HISTOGRAM_%s_FIRST_SLOT = %d," % (histogram.name.upper(), first_slot)
+ print >>H, " GRPC_STATS_HISTOGRAM_%s_BUCKETS = %d," % (histogram.name.upper(), histogram.buckets)
+ first_slot += histogram.buckets
+ print >>H, " GRPC_STATS_HISTOGRAM_BUCKETS = %d" % first_slot
+ print >>H, "} grpc_stats_histogram_constants;"
+
+ for ctr in inst_map['Counter']:
+ print >>H, ("#define GRPC_STATS_INC_%s(exec_ctx) " +
+ "GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_%s)") % (
+ ctr.name.upper(), ctr.name.upper())
+ for histogram in inst_map['Histogram']:
+ code, bounds_idx = gen_bucket_code(histogram)
+ histo_bucket_boundaries.append(bounds_idx)
+ print >>H, ("#define GRPC_STATS_INC_%s(exec_ctx, value) %s") % (
+ histogram.name.upper(),
+ code)
- for ctr in counters:
- print >>H, "#define GRPC_STATS_INC_%s(exec_ctx) GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_%s)" % (ctr.name.upper(), ctr.name.upper())
+ for i, tbl in enumerate(static_tables):
+ print >>H, "extern const %s grpc_stats_table_%d[%d];" % (tbl[0], i, len(tbl[1]))
- print >>H, "extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];"
+ print >>H, "extern const int grpc_stats_histo_buckets[%d];" % len(inst_map['Histogram'])
+ print >>H, "extern const int grpc_stats_histo_start[%d];" % len(inst_map['Histogram'])
+ print >>H, "extern const double *const grpc_stats_histo_bucket_boundaries[%d];" % len(inst_map['Histogram'])
print >>H
print >>H, "#endif /* GRPC_CORE_LIB_DEBUG_STATS_DATA_H */"
@@ -96,7 +251,19 @@ with open('src/core/lib/debug/stats_data.c', 'w') as C:
print >>C, "#include \"src/core/lib/debug/stats_data.h\""
- print >>C, "const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {";
- for ctr in counters:
- print >>C, " \"%s\"," % ctr.name
- print >>C, "};"
+ for typename, instances in sorted(inst_map.items()):
+ print >>C, "const char *grpc_stats_%s_name[GRPC_STATS_%s_COUNT] = {" % (
+ typename.lower(), typename.upper())
+ for inst in instances:
+ print >>C, " \"%s\"," % inst.name
+ print >>C, "};"
+ for i, tbl in enumerate(static_tables):
+ print >>C, "const %s grpc_stats_table_%d[%d] = {%s};" % (
+ tbl[0], i, len(tbl[1]), ','.join('%s' % x for x in tbl[1]))
+
+ print >>C, "const int grpc_stats_histo_buckets[%d] = {%s};" % (
+ len(inst_map['Histogram']), ','.join('%s' % x for x in histo_buckets))
+ print >>C, "const int grpc_stats_histo_start[%d] = {%s};" % (
+ len(inst_map['Histogram']), ','.join('%s' % x for x in histo_start))
+ print >>C, "const double *const grpc_stats_histo_bucket_boundaries[%d] = {%s};" % (
+ len(inst_map['Histogram']), ','.join('grpc_stats_table_%d' % x for x in histo_bucket_boundaries))
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 5ce25dc14a..ecfb96ee8d 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -2969,7 +2969,8 @@
"gpr",
"grpc",
"grpc++",
- "grpc++_codegen_base"
+ "grpc++_codegen_base",
+ "grpc++_core_stats"
],
"headers": [
"src/proto/grpc/testing/control.grpc.pb.h",
@@ -3002,7 +3003,8 @@
"gpr",
"grpc",
"grpc++_codegen_base",
- "grpc++_codegen_base_src"
+ "grpc++_codegen_base_src",
+ "grpc++_core_stats"
],
"headers": [
"src/proto/grpc/testing/control.grpc.pb.h",
@@ -3702,6 +3704,7 @@
"gpr_test_util",
"grpc",
"grpc++",
+ "grpc++_core_stats",
"grpc++_test_config",
"grpc++_test_util",
"grpc_test_util",
@@ -6024,6 +6027,26 @@
},
{
"deps": [
+ "grpc++"
+ ],
+ "headers": [
+ "src/cpp/util/core_stats.h",
+ "src/proto/grpc/core/stats.grpc.pb.h",
+ "src/proto/grpc/core/stats.pb.h",
+ "src/proto/grpc/core/stats_mock.grpc.pb.h"
+ ],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "grpc++_core_stats",
+ "src": [
+ "src/cpp/util/core_stats.cc",
+ "src/cpp/util/core_stats.h"
+ ],
+ "third_party": false,
+ "type": "lib"
+ },
+ {
+ "deps": [
"census",
"gpr",
"grpc",
@@ -6518,6 +6541,7 @@
"deps": [
"grpc",
"grpc++",
+ "grpc++_core_stats",
"grpc++_test_util",
"grpc_test_util"
],