Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 2e19036 | 2016-03-25 14:33:26 -0700 | [diff] [blame] | 3 | * Copyright 2015-2016, Google Inc. |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 4 | * All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions are |
| 8 | * met: |
| 9 | * |
| 10 | * * Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * * Redistributions in binary form must reproduce the above |
| 13 | * copyright notice, this list of conditions and the following disclaimer |
| 14 | * in the documentation and/or other materials provided with the |
| 15 | * distribution. |
| 16 | * * Neither the name of Google Inc. nor the names of its |
| 17 | * contributors may be used to endorse or promote products derived from |
| 18 | * this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | * |
| 32 | */ |
| 33 | |
| 34 | #include <string.h> |
| 35 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 36 | #include <grpc/support/alloc.h> |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 37 | #include <grpc/support/log.h> |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 38 | #include <grpc/support/sync.h> |
Craig Tiller | f40df23 | 2016-03-25 13:38:14 -0700 | [diff] [blame] | 39 | #include "src/core/statistics/census_interface.h" |
| 40 | #include "src/core/statistics/census_rpc_stats.h" |
| 41 | #include "src/core/statistics/census_tracing.h" |
| 42 | #include "src/core/statistics/hash_table.h" |
| 43 | #include "src/core/statistics/window_stats.h" |
| 44 | #include "src/core/support/murmur_hash.h" |
| 45 | #include "src/core/support/string.h" |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 46 | |
| 47 | #define NUM_INTERVALS 3 |
| 48 | #define MINUTE_INTERVAL 0 |
| 49 | #define HOUR_INTERVAL 1 |
| 50 | #define TOTAL_INTERVAL 2 |
| 51 | |
| 52 | /* for easier typing */ |
| 53 | typedef census_per_method_rpc_stats per_method_stats; |
| 54 | |
| 55 | /* Ensure mu is only initialized once. */ |
| 56 | static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT; |
| 57 | /* Guards two stats stores. */ |
| 58 | static gpr_mu g_mu; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 59 | static census_ht *g_client_stats_store = NULL; |
| 60 | static census_ht *g_server_stats_store = NULL; |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 61 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 62 | static void init_mutex(void) { gpr_mu_init(&g_mu); } |
| 63 | |
| 64 | static void init_mutex_once(void) { |
| 65 | gpr_once_init(&g_stats_store_mu_init, init_mutex); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 66 | } |
| 67 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 68 | static int cmp_str_keys(const void *k1, const void *k2) { |
| 69 | return strcmp((const char *)k1, (const char *)k2); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | /* TODO(hongyu): replace it with cityhash64 */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 73 | static uint64_t simple_hash(const void *k) { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 74 | size_t len = strlen(k); |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 75 | uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 76 | return higher << 32 | |
| 77 | gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 78 | } |
| 79 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 80 | static void delete_stats(void *stats) { |
| 81 | census_window_stats_destroy((struct census_window_stats *)stats); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 82 | } |
| 83 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 84 | static void delete_key(void *key) { gpr_free(key); } |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 85 | |
| 86 | static const census_ht_option ht_opt = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 87 | CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */, |
Craig Tiller | f40df23 | 2016-03-25 13:38:14 -0700 | [diff] [blame] | 88 | simple_hash /* hash function */, cmp_str_keys /* key comparator */, |
| 89 | delete_stats /* data deleter */, delete_key /* key deleter */ |
Craig Tiller | ecd4934 | 2015-01-18 14:36:47 -0800 | [diff] [blame] | 90 | }; |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 91 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 92 | static void init_rpc_stats(void *stats) { |
| 93 | memset(stats, 0, sizeof(census_rpc_stats)); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 94 | } |
| 95 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 96 | static void stat_add_proportion(double p, void *base, const void *addme) { |
| 97 | census_rpc_stats *b = (census_rpc_stats *)base; |
| 98 | census_rpc_stats *a = (census_rpc_stats *)addme; |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 99 | b->cnt += p * a->cnt; |
| 100 | b->rpc_error_cnt += p * a->rpc_error_cnt; |
| 101 | b->app_error_cnt += p * a->app_error_cnt; |
| 102 | b->elapsed_time_ms += p * a->elapsed_time_ms; |
| 103 | b->api_request_bytes += p * a->api_request_bytes; |
| 104 | b->wire_request_bytes += p * a->wire_request_bytes; |
| 105 | b->api_response_bytes += p * a->api_response_bytes; |
| 106 | b->wire_response_bytes += p * a->wire_response_bytes; |
| 107 | } |
| 108 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 109 | static void stat_add(void *base, const void *addme) { |
| 110 | stat_add_proportion(1.0, base, addme); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | static gpr_timespec min_hour_total_intervals[3] = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 114 | {60, 0}, {3600, 0}, {36000000, 0}}; |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 115 | |
| 116 | static const census_window_stats_stat_info window_stats_settings = { |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 117 | sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion}; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 118 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 119 | census_rpc_stats *census_rpc_stats_create_empty(void) { |
| 120 | census_rpc_stats *ret = |
| 121 | (census_rpc_stats *)gpr_malloc(sizeof(census_rpc_stats)); |
| 122 | memset(ret, 0, sizeof(census_rpc_stats)); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 123 | return ret; |
| 124 | } |
| 125 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 126 | void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) { |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 127 | int i = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 128 | for (i = 0; i < data->num_entries; i++) { |
| 129 | if (data->stats[i].method != NULL) { |
| 130 | gpr_free((void *)data->stats[i].method); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 131 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 132 | } |
| 133 | if (data->stats != NULL) { |
| 134 | gpr_free(data->stats); |
| 135 | } |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 136 | data->num_entries = 0; |
| 137 | data->stats = NULL; |
| 138 | } |
| 139 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 140 | static void record_stats(census_ht *store, census_op_id op_id, |
| 141 | const census_rpc_stats *stats) { |
| 142 | gpr_mu_lock(&g_mu); |
| 143 | if (store != NULL) { |
| 144 | census_trace_obj *trace = NULL; |
| 145 | census_internal_lock_trace_store(); |
| 146 | trace = census_get_trace_obj_locked(op_id); |
| 147 | if (trace != NULL) { |
| 148 | const char *method_name = census_get_trace_method_name(trace); |
| 149 | struct census_window_stats *window_stats = NULL; |
| 150 | census_ht_key key; |
| 151 | key.ptr = (void *)method_name; |
| 152 | window_stats = census_ht_find(store, key); |
| 153 | census_internal_unlock_trace_store(); |
| 154 | if (window_stats == NULL) { |
| 155 | window_stats = census_window_stats_create(3, min_hour_total_intervals, |
| 156 | 30, &window_stats_settings); |
| 157 | key.ptr = gpr_strdup(key.ptr); |
| 158 | census_ht_insert(store, key, (void *)window_stats); |
| 159 | } |
| 160 | census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats); |
| 161 | } else { |
| 162 | census_internal_unlock_trace_store(); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 163 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 164 | } |
| 165 | gpr_mu_unlock(&g_mu); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 166 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 167 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 168 | void census_record_rpc_client_stats(census_op_id op_id, |
| 169 | const census_rpc_stats *stats) { |
| 170 | record_stats(g_client_stats_store, op_id, stats); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 171 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 172 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 173 | void census_record_rpc_server_stats(census_op_id op_id, |
| 174 | const census_rpc_stats *stats) { |
| 175 | record_stats(g_server_stats_store, op_id, stats); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 176 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 177 | |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 178 | /* Get stats from input stats store */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 179 | static void get_stats(census_ht *store, census_aggregated_rpc_stats *data) { |
| 180 | GPR_ASSERT(data != NULL); |
| 181 | if (data->num_entries != 0) { |
| 182 | census_aggregated_rpc_stats_set_empty(data); |
| 183 | } |
| 184 | gpr_mu_lock(&g_mu); |
| 185 | if (store != NULL) { |
| 186 | size_t n; |
| 187 | unsigned i, j; |
| 188 | gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); |
| 189 | census_ht_kv *kv = census_ht_get_all_elements(store, &n); |
| 190 | if (kv != NULL) { |
| 191 | data->num_entries = n; |
| 192 | data->stats = |
| 193 | (per_method_stats *)gpr_malloc(sizeof(per_method_stats) * n); |
| 194 | for (i = 0; i < n; i++) { |
| 195 | census_window_stats_sums sums[NUM_INTERVALS]; |
| 196 | for (j = 0; j < NUM_INTERVALS; j++) { |
| 197 | sums[j].statistic = (void *)census_rpc_stats_create_empty(); |
| 198 | } |
| 199 | data->stats[i].method = gpr_strdup(kv[i].k.ptr); |
| 200 | census_window_stats_get_sums(kv[i].v, now, sums); |
| 201 | data->stats[i].minute_stats = |
| 202 | *(census_rpc_stats *)sums[MINUTE_INTERVAL].statistic; |
| 203 | data->stats[i].hour_stats = |
| 204 | *(census_rpc_stats *)sums[HOUR_INTERVAL].statistic; |
| 205 | data->stats[i].total_stats = |
| 206 | *(census_rpc_stats *)sums[TOTAL_INTERVAL].statistic; |
| 207 | for (j = 0; j < NUM_INTERVALS; j++) { |
| 208 | gpr_free(sums[j].statistic); |
| 209 | } |
| 210 | } |
| 211 | gpr_free(kv); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 212 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 213 | } |
| 214 | gpr_mu_unlock(&g_mu); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 215 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 216 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 217 | void census_get_client_stats(census_aggregated_rpc_stats *data) { |
| 218 | get_stats(g_client_stats_store, data); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 219 | } |
| 220 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 221 | void census_get_server_stats(census_aggregated_rpc_stats *data) { |
| 222 | get_stats(g_server_stats_store, data); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 223 | } |
| 224 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 225 | void census_stats_store_init(void) { |
| 226 | init_mutex_once(); |
| 227 | gpr_mu_lock(&g_mu); |
| 228 | if (g_client_stats_store == NULL && g_server_stats_store == NULL) { |
| 229 | g_client_stats_store = census_ht_create(&ht_opt); |
| 230 | g_server_stats_store = census_ht_create(&ht_opt); |
| 231 | } else { |
| 232 | gpr_log(GPR_ERROR, "Census stats store already initialized."); |
| 233 | } |
| 234 | gpr_mu_unlock(&g_mu); |
hongyu | 24200d3 | 2015-01-08 15:13:49 -0800 | [diff] [blame] | 235 | } |
| 236 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 237 | void census_stats_store_shutdown(void) { |
| 238 | init_mutex_once(); |
| 239 | gpr_mu_lock(&g_mu); |
| 240 | if (g_client_stats_store != NULL) { |
| 241 | census_ht_destroy(g_client_stats_store); |
| 242 | g_client_stats_store = NULL; |
| 243 | } else { |
| 244 | gpr_log(GPR_ERROR, "Census server stats store not initialized."); |
| 245 | } |
| 246 | if (g_server_stats_store != NULL) { |
| 247 | census_ht_destroy(g_server_stats_store); |
| 248 | g_server_stats_store = NULL; |
| 249 | } else { |
| 250 | gpr_log(GPR_ERROR, "Census client stats store not initialized."); |
| 251 | } |
| 252 | gpr_mu_unlock(&g_mu); |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 253 | } |