diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f87beb02b9..db629e8499d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1073,6 +1073,8 @@ add_library(grpc
src/core/lib/transport/transport.c
src/core/lib/transport/transport_op_string.c
src/core/lib/debug/trace.c
+ src/core/lib/debug/stats.c
+ src/core/lib/debug/stats_data.c
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
src/core/ext/transport/chttp2/transport/bin_decoder.c
src/core/ext/transport/chttp2/transport/bin_encoder.c
@@ -1416,6 +1418,8 @@ add_library(grpc_cronet
src/core/lib/transport/transport.c
src/core/lib/transport/transport_op_string.c
src/core/lib/debug/trace.c
+ src/core/lib/debug/stats.c
+ src/core/lib/debug/stats_data.c
src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
src/core/ext/transport/cronet/transport/cronet_api_dummy.c
src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -1737,6 +1741,8 @@ add_library(grpc_test_util
src/core/lib/transport/transport.c
src/core/lib/transport/transport_op_string.c
src/core/lib/debug/trace.c
+ src/core/lib/debug/stats.c
+ src/core/lib/debug/stats_data.c
)
if(WIN32 AND MSVC)
@@ -2000,6 +2006,8 @@ add_library(grpc_unsecure
src/core/lib/transport/transport.c
src/core/lib/transport/transport_op_string.c
src/core/lib/debug/trace.c
+ src/core/lib/debug/stats.c
+ src/core/lib/debug/stats_data.c
src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -2659,6 +2667,8 @@ add_library(grpc++_cronet
src/core/lib/transport/transport.c
src/core/lib/transport/transport_op_string.c
src/core/lib/debug/trace.c
+ src/core/lib/debug/stats.c
+ src/core/lib/debug/stats_data.c
src/core/ext/transport/chttp2/alpn/alpn.c
src/core/ext/filters/http/client/http_client_filter.c
src/core/ext/filters/http/http_filters_plugin.c
diff --git a/Makefile b/Makefile
index 2ae02297165..d942f94e4a5 100644
--- a/Makefile
+++ b/Makefile
@@ -3017,6 +3017,8 @@ LIBGRPC_SRC = \
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
src/core/ext/transport/chttp2/transport/bin_decoder.c \
src/core/ext/transport/chttp2/transport/bin_encoder.c \
@@ -3358,6 +3360,8 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \
src/core/ext/transport/cronet/transport/cronet_api_dummy.c \
src/core/ext/transport/cronet/transport/cronet_transport.c \
@@ -3676,6 +3680,8 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
PUBLIC_HEADERS_C += \
include/grpc/byte_buffer.h \
@@ -3911,6 +3917,8 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/transport/bin_decoder.c \
@@ -4554,6 +4562,8 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
src/core/ext/transport/chttp2/alpn/alpn.c \
src/core/ext/filters/http/client/http_client_filter.c \
src/core/ext/filters/http/http_filters_plugin.c \
diff --git a/binding.gyp b/binding.gyp
index d11a60a68af..f091850be1d 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -762,6 +762,8 @@
'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c',
'src/core/lib/debug/trace.c',
+ 'src/core/lib/debug/stats.c',
+ 'src/core/lib/debug/stats_data.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c',
diff --git a/build.yaml b/build.yaml
index 5dac7706147..0811606e409 100644
--- a/build.yaml
+++ b/build.yaml
@@ -422,6 +422,7 @@ filegroups:
uses:
- grpc_codegen
- grpc_trace
+ - grpc_stats
- name: grpc_client_channel
headers:
- src/core/ext/filters/client_channel/client_channel.h
@@ -679,6 +680,15 @@ filegroups:
- src/core/ext/filters/workarounds/workaround_utils.c
uses:
- grpc_base
+- name: grpc_stats
+ headers:
+ - src/core/lib/debug/stats.h
+ - src/core/lib/debug/stats_data.h
+ src:
+ - src/core/lib/debug/stats.c
+ - src/core/lib/debug/stats_data.c
+ deps:
+ - gpr
- name: grpc_test_util_base
build: test
headers:
diff --git a/config.m4 b/config.m4
index f97baadde4d..9e43a78be59 100644
--- a/config.m4
+++ b/config.m4
@@ -212,6 +212,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \
src/core/lib/debug/trace.c \
+ src/core/lib/debug/stats.c \
+ src/core/lib/debug/stats_data.c \
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
src/core/ext/transport/chttp2/transport/bin_decoder.c \
src/core/ext/transport/chttp2/transport/bin_encoder.c \
diff --git a/config.w32 b/config.w32
index c00f3f953d4..2dd3b4d3de8 100644
--- a/config.w32
+++ b/config.w32
@@ -189,6 +189,8 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\transport\\transport.c " +
"src\\core\\lib\\transport\\transport_op_string.c " +
"src\\core\\lib\\debug\\trace.c " +
+ "src\\core\\lib\\debug\\stats.c " +
+ "src\\core\\lib\\debug\\stats_data.c " +
"src\\core\\ext\\transport\\chttp2\\server\\secure\\server_secure_chttp2.c " +
"src\\core\\ext\\transport\\chttp2\\transport\\bin_decoder.c " +
"src\\core\\ext\\transport\\chttp2\\transport\\bin_encoder.c " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 57b6f92d1e0..4135c6522ed 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -355,6 +355,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
'src/core/lib/debug/trace.h',
+ 'src/core/lib/debug/stats.h',
+ 'src/core/lib/debug/stats_data.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
@@ -586,6 +588,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c',
'src/core/lib/debug/trace.c',
+ 'src/core/lib/debug/stats.c',
+ 'src/core/lib/debug/stats_data.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c',
@@ -839,6 +843,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
'src/core/lib/debug/trace.h',
+ 'src/core/lib/debug/stats.h',
+ 'src/core/lib/debug/stats_data.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index dedee020b7d..9c4badb5a6a 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -287,6 +287,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/transport.h )
s.files += %w( src/core/lib/transport/transport_impl.h )
s.files += %w( src/core/lib/debug/trace.h )
+ s.files += %w( src/core/lib/debug/stats.h )
+ s.files += %w( src/core/lib/debug/stats_data.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h )
@@ -522,6 +524,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/transport.c )
s.files += %w( src/core/lib/transport/transport_op_string.c )
s.files += %w( src/core/lib/debug/trace.c )
+ s.files += %w( src/core/lib/debug/stats.c )
+ s.files += %w( src/core/lib/debug/stats_data.c )
s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.c )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.c )
diff --git a/package.xml b/package.xml
index 38f51424e6a..ded7ffc52bd 100644
--- a/package.xml
+++ b/package.xml
@@ -301,6 +301,8 @@
+
+
@@ -536,6 +538,8 @@
+
+
diff --git a/src/core/lib/debug/stats.c b/src/core/lib/debug/stats.c
new file mode 100644
index 00000000000..6daf03484a3
--- /dev/null
+++ b/src/core/lib/debug/stats.c
@@ -0,0 +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.
+ *
+ */
+
+#include "src/core/lib/debug/stats.h"
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include "src/core/lib/support/string.h"
+
+grpc_stats_data *grpc_stats_per_cpu_storage;
+static size_t g_num_cores;
+
+void grpc_stats_init(void) {
+ g_num_cores = GPR_MAX(1, gpr_cpu_num_cores());
+ grpc_stats_per_cpu_storage =
+ gpr_zalloc(sizeof(grpc_stats_data) * g_num_cores);
+}
+
+void grpc_stats_shutdown(void) { gpr_free(grpc_stats_per_cpu_storage); }
+
+void grpc_stats_collect(grpc_stats_data *output) {
+ memset(output, 0, sizeof(*output));
+ for (size_t core = 0; core < g_num_cores; core++) {
+ for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ output->counters[i] += gpr_atm_no_barrier_load(
+ &grpc_stats_per_cpu_storage[core].counters[i]);
+ }
+ }
+}
+
+char *grpc_stats_data_as_json(const grpc_stats_data *data) {
+ gpr_strvec v;
+ char *tmp;
+ bool is_first = true;
+ gpr_strvec_init(&v);
+ gpr_strvec_add(&v, gpr_strdup("{"));
+ for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
+ gpr_asprintf(&tmp, "%s\"%s\": %" PRIdPTR, is_first ? "" : ", ",
+ grpc_stats_counter_name[i], data->counters[i]);
+ gpr_strvec_add(&v, tmp);
+ is_first = false;
+ }
+ gpr_strvec_add(&v, gpr_strdup("}"));
+ tmp = gpr_strvec_flatten(&v, NULL);
+ gpr_strvec_destroy(&v);
+ return tmp;
+}
diff --git a/src/core/lib/debug/stats.h b/src/core/lib/debug/stats.h
new file mode 100644
index 00000000000..b30e008e2b1
--- /dev/null
+++ b/src/core/lib/debug/stats.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_DEBUG_STATS_H
+#define GRPC_CORE_LIB_DEBUG_STATS_H
+
+#include
+#include "src/core/lib/debug/stats_data.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct grpc_stats_data {
+ gpr_atm counters[GRPC_STATS_COUNTER_COUNT];
+} grpc_stats_data;
+
+extern grpc_stats_data *grpc_stats_per_cpu_storage;
+
+#define GRPC_THREAD_STATS_DATA(exec_ctx) \
+ (&grpc_stats_per_cpu_storage[(exec_ctx)->starting_cpu])
+
+#define GRPC_STATS_INC_COUNTER(exec_ctx, ctr) \
+ (gpr_atm_no_barrier_fetch_add( \
+ &GRPC_THREAD_STATS_DATA((exec_ctx))->counters[(ctr)], 1), \
+ 0)
+
+void grpc_stats_init(void);
+void grpc_stats_shutdown(void);
+void grpc_stats_collect(grpc_stats_data *output);
+char *grpc_stats_data_as_json(const grpc_stats_data *data);
+
+#endif
diff --git a/src/core/lib/debug/stats_data.c b/src/core/lib/debug/stats_data.c
new file mode 100644
index 00000000000..f2969654ef9
--- /dev/null
+++ b/src/core/lib/debug/stats_data.c
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/*
+ * Automatically generated by tools/codegen/core/gen_stats_data.py
+ */
+
+#include "src/core/lib/debug/stats_data.h"
+const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {
+ "client_calls_created",
+ "server_calls_created",
+};
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
new file mode 100644
index 00000000000..3107205c44f
--- /dev/null
+++ b/src/core/lib/debug/stats_data.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ * Automatically generated by tools/codegen/core/gen_stats_data.py
+ */
+
+#ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H
+#define GRPC_CORE_LIB_DEBUG_STATS_DATA_H
+
+typedef enum {
+ GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED,
+ GRPC_STATS_COUNTER_SERVER_CALLS_CREATED,
+ GRPC_STATS_COUNTER_COUNT
+} grpc_stats_counters;
+#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)
+extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];
+
+#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
new file mode 100644
index 00000000000..3347d9c8ae7
--- /dev/null
+++ b/src/core/lib/debug/stats_data.yaml
@@ -0,0 +1,5 @@
+# Stats data declaration
+# use tools/codegen/core/gen_stats_data.py to turn this into stats_data.h
+
+- counter: client_calls_created
+- counter: server_calls_created
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index a0d2a965d53..c89792c8c4f 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -19,6 +19,7 @@
#ifndef GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
#define GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
+#include
#include "src/core/lib/iomgr/closure.h"
/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */
@@ -62,6 +63,7 @@ struct grpc_exec_ctx {
/** last active combiner in the active combiner list */
grpc_combiner *last_combiner;
uintptr_t flags;
+ unsigned starting_cpu;
void *check_ready_to_finish_arg;
bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
};
@@ -69,7 +71,10 @@ struct grpc_exec_ctx {
/* initializer for grpc_exec_ctx:
prefer to use GRPC_EXEC_CTX_INIT whenever possible */
#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \
- { GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, finish_check_arg, finish_check }
+ { \
+ GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, gpr_cpu_current_cpu(), \
+ finish_check_arg, finish_check \
+ }
/* initialize an execution context at the top level of an API call into grpc
(this is safe to use elsewhere, though possibly not as efficient) */
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 2365d27307c..2f42726c7f0 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -32,6 +32,7 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/compression/algorithm_metadata.h"
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
@@ -314,6 +315,11 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
+ if (call->is_client) {
+ GRPC_STATS_INC_CLIENT_CALLS_CREATED(exec_ctx);
+ } else {
+ GRPC_STATS_INC_SERVER_CALLS_CREATED(exec_ctx);
+ }
call->stream_op_payload.context = call->context;
grpc_slice path = grpc_empty_slice();
if (call->is_client) {
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index db111e597f6..822056af5a1 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -28,6 +28,7 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/handshaker_registry.h"
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/combiner.h"
@@ -117,6 +118,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
+ grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();
grpc_channel_init_init();
@@ -184,6 +186,7 @@ void grpc_shutdown(void) {
grpc_mdctx_global_shutdown(&exec_ctx);
grpc_handshaker_factory_registry_shutdown(&exec_ctx);
grpc_slice_intern_shutdown();
+ grpc_stats_shutdown();
}
gpr_mu_unlock(&g_init_mu);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 605044b65e0..1f3a8c8a63a 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -188,6 +188,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c',
'src/core/lib/debug/trace.c',
+ 'src/core/lib/debug/stats.c',
+ 'src/core/lib/debug/stats_data.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c',
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index 7a81133dfa7..82ab0a1cfeb 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -27,6 +27,7 @@
#include
#include
#include
+#include "src/core/lib/debug/stats.h"
#include "src/core/lib/support/string.h"
#include "test/core/end2end/cq_verifier.h"
@@ -102,6 +103,10 @@ static void simple_request_body(grpc_end2end_test_config config,
grpc_slice details;
int was_cancelled = 2;
char *peer;
+ grpc_stats_data before;
+ grpc_stats_data after;
+
+ grpc_stats_collect(&before);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
@@ -208,6 +213,23 @@ static void simple_request_body(grpc_end2end_test_config config,
grpc_call_unref(s);
cq_verifier_destroy(cqv);
+
+ grpc_stats_collect(&after);
+
+ char *stats = grpc_stats_data_as_json(&after);
+ gpr_log(GPR_DEBUG, "%s", stats);
+ gpr_free(stats);
+
+ int expected_calls = 1;
+ if (config.feature_mask & FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) {
+ expected_calls *= 2;
+ }
+ GPR_ASSERT(after.counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] -
+ before.counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] ==
+ expected_calls);
+ GPR_ASSERT(after.counters[GRPC_STATS_COUNTER_SERVER_CALLS_CREATED] -
+ before.counters[GRPC_STATS_COUNTER_SERVER_CALLS_CREATED] ==
+ expected_calls);
}
static void test_invoke_simple_request(grpc_end2end_test_config config) {
diff --git a/tools/codegen/core/gen_stats_data.py b/tools/codegen/core/gen_stats_data.py
new file mode 100755
index 00000000000..bc601a89a7f
--- /dev/null
+++ b/tools/codegen/core/gen_stats_data.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import collections
+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')
+
+counters = []
+
+for attr in attrs:
+ if 'counter' in attr:
+ counters.append(Counter(name=attr['counter']))
+ else:
+ print 'Error: bad attr %r' % attr
+
+# utility: print a big comment block into a set of files
+def put_banner(files, banner):
+ for f in files:
+ print >>f, '/*'
+ for line in banner:
+ print >>f, ' * %s' % line
+ print >>f, ' */'
+ print >>f
+
+with open('src/core/lib/debug/stats_data.h', 'w') as H:
+ # copy-paste copyright notice from this file
+ with open(sys.argv[0]) as my_source:
+ copyright = []
+ for line in my_source:
+ if line[0] != '#': break
+ for line in my_source:
+ if line[0] == '#':
+ copyright.append(line)
+ break
+ for line in my_source:
+ if line[0] != '#':
+ break
+ copyright.append(line)
+ put_banner([H], [line[2:].rstrip() for line in copyright])
+
+ put_banner([H], ["Automatically generated by tools/codegen/core/gen_stats_data.py"])
+
+ print >>H, "#ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H"
+ print >>H, "#define GRPC_CORE_LIB_DEBUG_STATS_DATA_H"
+ print >>H
+
+ 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;"
+
+ 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())
+
+ print >>H, "extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];"
+
+ print >>H
+ print >>H, "#endif /* GRPC_CORE_LIB_DEBUG_STATS_DATA_H */"
+
+with open('src/core/lib/debug/stats_data.c', 'w') as C:
+ # copy-paste copyright notice from this file
+ with open(sys.argv[0]) as my_source:
+ copyright = []
+ for line in my_source:
+ if line[0] != '#': break
+ for line in my_source:
+ if line[0] == '#':
+ copyright.append(line)
+ break
+ for line in my_source:
+ if line[0] != '#':
+ break
+ copyright.append(line)
+ put_banner([C], [line[2:].rstrip() for line in copyright])
+
+ put_banner([C], ["Automatically generated by tools/codegen/core/gen_stats_data.py"])
+
+ 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, "};"
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 4ad8a0ddb46..2995145fe17 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1073,6 +1073,10 @@ src/core/lib/compression/message_compress.c \
src/core/lib/compression/message_compress.h \
src/core/lib/compression/stream_compression.c \
src/core/lib/compression/stream_compression.h \
+src/core/lib/debug/stats.c \
+src/core/lib/debug/stats.h \
+src/core/lib/debug/stats_data.c \
+src/core/lib/debug/stats_data.h \
src/core/lib/debug/trace.c \
src/core/lib/debug/trace.h \
src/core/lib/http/format_request.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 8993e9340ac..bdad9e9d01d 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -7691,6 +7691,7 @@
"deps": [
"gpr",
"grpc_codegen",
+ "grpc_stats",
"grpc_trace"
],
"headers": [
@@ -8551,6 +8552,26 @@
"third_party": false,
"type": "filegroup"
},
+ {
+ "deps": [
+ "gpr"
+ ],
+ "headers": [
+ "src/core/lib/debug/stats.h",
+ "src/core/lib/debug/stats_data.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "grpc_stats",
+ "src": [
+ "src/core/lib/debug/stats.c",
+ "src/core/lib/debug/stats.h",
+ "src/core/lib/debug/stats_data.c",
+ "src/core/lib/debug/stats_data.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
{
"deps": [
"gpr_test_util",
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 41fe1b222b7..6ffb0ac0849 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -412,6 +412,8 @@
+
+
@@ -776,6 +778,10 @@
+
+
+
+
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 00b8705826c..ea58322a651 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -382,6 +382,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
src\core\ext\transport\chttp2\server\secure
@@ -1193,6 +1199,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
src\core\ext\transport\chttp2\transport
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 32809ca5899..4ba0ef78cf5 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -307,6 +307,8 @@
+
+
@@ -601,6 +603,10 @@
+
+
+
+
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index def8de42028..fa2a6e3545f 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -439,6 +439,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
@@ -917,6 +923,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index ac98dc05401..7684ed42e2d 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -402,6 +402,8 @@
+
+
@@ -742,6 +744,10 @@
+
+
+
+
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index fea68c51dc8..93f68e56987 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -385,6 +385,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
src\core\ext\transport\chttp2\server\insecure
@@ -1100,6 +1106,12 @@
src\core\lib\debug
+
+ src\core\lib\debug
+
+
+ src\core\lib\debug
+
src\core\ext\transport\chttp2\transport