aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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.c150
-rw-r--r--src/core/lib/debug/stats_data.h102
-rw-r--r--src/core/lib/debug/stats_data.yaml14
-rw-r--r--src/core/lib/iomgr/tcp_posix.c4
6 files changed, 392 insertions, 5 deletions
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..177234ab5b 100644
--- a/src/core/lib/debug/stats_data.c
+++ b/src/core/lib/debug/stats_data.c
@@ -20,6 +20,152 @@
#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_write",
+ "syscall_read", "syscall_poll", "syscall_wait",
+ "histogram_slow_lookups",
};
+const char *grpc_stats_histogram_name[GRPC_STATS_HISTOGRAM_COUNT] = {
+ "tcp_write_size", "tcp_write_iov_size", "tcp_read_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[3] = {64, 64, 64};
+const int grpc_stats_histo_start[3] = {0, 64, 128};
+const double *const grpc_stats_histo_bucket_boundaries[3] = {
+ 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..9a4ba68655 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -21,6 +21,8 @@
#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,
@@ -28,8 +30,26 @@ typedef enum {
GRPC_STATS_COUNTER_SYSCALL_READ,
GRPC_STATS_COUNTER_SYSCALL_POLL,
GRPC_STATS_COUNTER_SYSCALL_WAIT,
+ GRPC_STATS_COUNTER_HISTOGRAM_SLOW_LOOKUPS,
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_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_BUCKETS = 192
+} 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) \
@@ -42,6 +62,86 @@ typedef enum {
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_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)
+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[3];
+extern const int grpc_stats_histo_start[3];
+extern const double *const grpc_stats_histo_bucket_boundaries[3];
#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..b8d5f71991 100644
--- a/src/core/lib/debug/stats_data.yaml
+++ b/src/core/lib/debug/stats_data.yaml
@@ -1,5 +1,5 @@
-# Stats data declaration
-# use tools/codegen/core/gen_stats_data.py to turn this into stats_data.h
+#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
@@ -7,3 +7,13 @@
- counter: syscall_read
- counter: syscall_poll
- counter: syscall_wait
+- counter: histogram_slow_lookups
+- 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
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 7e789cc5b5..ccf328ec1c 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -287,6 +287,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 +404,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 */