diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/lib/debug/stats.c | 110 | ||||
-rw-r--r-- | src/core/lib/debug/stats.h | 17 | ||||
-rw-r--r-- | src/core/lib/debug/stats_data.c | 150 | ||||
-rw-r--r-- | src/core/lib/debug/stats_data.h | 102 | ||||
-rw-r--r-- | src/core/lib/debug/stats_data.yaml | 14 | ||||
-rw-r--r-- | src/core/lib/iomgr/tcp_posix.c | 4 |
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 */ |