blob: c78d6fd61279d8b841a78655207d675ee5914cff [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller2e190362016-03-25 14:33:26 -07003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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 Nobleb7ebd3b2014-11-26 16:33:03 -080036#include <grpc/support/alloc.h>
hongyu24200d32015-01-08 15:13:49 -080037#include <grpc/support/log.h>
hongyu24200d32015-01-08 15:13:49 -080038#include <grpc/support/sync.h>
Craig Tillerf40df232016-03-25 13:38:14 -070039#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"
hongyu24200d32015-01-08 15:13:49 -080046
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 */
53typedef census_per_method_rpc_stats per_method_stats;
54
55/* Ensure mu is only initialized once. */
56static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT;
57/* Guards two stats stores. */
58static gpr_mu g_mu;
Craig Tiller45724b32015-09-22 10:42:19 -070059static census_ht *g_client_stats_store = NULL;
60static census_ht *g_server_stats_store = NULL;
hongyu24200d32015-01-08 15:13:49 -080061
Craig Tillera82950e2015-09-22 12:33:20 -070062static void init_mutex(void) { gpr_mu_init(&g_mu); }
63
64static void init_mutex_once(void) {
65 gpr_once_init(&g_stats_store_mu_init, init_mutex);
hongyu24200d32015-01-08 15:13:49 -080066}
67
Craig Tillera82950e2015-09-22 12:33:20 -070068static int cmp_str_keys(const void *k1, const void *k2) {
69 return strcmp((const char *)k1, (const char *)k2);
hongyu24200d32015-01-08 15:13:49 -080070}
71
72/* TODO(hongyu): replace it with cityhash64 */
Craig Tiller7536af02015-12-22 13:49:30 -080073static uint64_t simple_hash(const void *k) {
Craig Tillera82950e2015-09-22 12:33:20 -070074 size_t len = strlen(k);
Craig Tiller7536af02015-12-22 13:49:30 -080075 uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0);
Craig Tillera82950e2015-09-22 12:33:20 -070076 return higher << 32 |
77 gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0);
hongyu24200d32015-01-08 15:13:49 -080078}
79
Craig Tillera82950e2015-09-22 12:33:20 -070080static void delete_stats(void *stats) {
81 census_window_stats_destroy((struct census_window_stats *)stats);
hongyu24200d32015-01-08 15:13:49 -080082}
83
Craig Tillera82950e2015-09-22 12:33:20 -070084static void delete_key(void *key) { gpr_free(key); }
hongyu24200d32015-01-08 15:13:49 -080085
86static const census_ht_option ht_opt = {
Craig Tillera82950e2015-09-22 12:33:20 -070087 CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */,
Craig Tillerf40df232016-03-25 13:38:14 -070088 simple_hash /* hash function */, cmp_str_keys /* key comparator */,
89 delete_stats /* data deleter */, delete_key /* key deleter */
Craig Tillerecd49342015-01-18 14:36:47 -080090};
hongyu24200d32015-01-08 15:13:49 -080091
Craig Tillera82950e2015-09-22 12:33:20 -070092static void init_rpc_stats(void *stats) {
93 memset(stats, 0, sizeof(census_rpc_stats));
hongyu24200d32015-01-08 15:13:49 -080094}
95
Craig Tillera82950e2015-09-22 12:33:20 -070096static 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;
hongyu24200d32015-01-08 15:13:49 -080099 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 Tillera82950e2015-09-22 12:33:20 -0700109static void stat_add(void *base, const void *addme) {
110 stat_add_proportion(1.0, base, addme);
hongyu24200d32015-01-08 15:13:49 -0800111}
112
113static gpr_timespec min_hour_total_intervals[3] = {
Craig Tillera82950e2015-09-22 12:33:20 -0700114 {60, 0}, {3600, 0}, {36000000, 0}};
hongyu24200d32015-01-08 15:13:49 -0800115
116static const census_window_stats_stat_info window_stats_settings = {
Craig Tillera82950e2015-09-22 12:33:20 -0700117 sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800118
Craig Tillera82950e2015-09-22 12:33:20 -0700119census_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 Nobleb7ebd3b2014-11-26 16:33:03 -0800123 return ret;
124}
125
Craig Tillera82950e2015-09-22 12:33:20 -0700126void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) {
hongyu24200d32015-01-08 15:13:49 -0800127 int i = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700128 for (i = 0; i < data->num_entries; i++) {
129 if (data->stats[i].method != NULL) {
130 gpr_free((void *)data->stats[i].method);
hongyu24200d32015-01-08 15:13:49 -0800131 }
Craig Tillera82950e2015-09-22 12:33:20 -0700132 }
133 if (data->stats != NULL) {
134 gpr_free(data->stats);
135 }
hongyu24200d32015-01-08 15:13:49 -0800136 data->num_entries = 0;
137 data->stats = NULL;
138}
139
Craig Tillera82950e2015-09-22 12:33:20 -0700140static 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();
hongyu24200d32015-01-08 15:13:49 -0800163 }
Craig Tillera82950e2015-09-22 12:33:20 -0700164 }
165 gpr_mu_unlock(&g_mu);
hongyu24200d32015-01-08 15:13:49 -0800166}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800167
Craig Tillera82950e2015-09-22 12:33:20 -0700168void 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);
hongyu24200d32015-01-08 15:13:49 -0800171}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800172
Craig Tillera82950e2015-09-22 12:33:20 -0700173void 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);
hongyu24200d32015-01-08 15:13:49 -0800176}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800177
hongyu24200d32015-01-08 15:13:49 -0800178/* Get stats from input stats store */
Craig Tillera82950e2015-09-22 12:33:20 -0700179static 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);
hongyu24200d32015-01-08 15:13:49 -0800212 }
Craig Tillera82950e2015-09-22 12:33:20 -0700213 }
214 gpr_mu_unlock(&g_mu);
hongyu24200d32015-01-08 15:13:49 -0800215}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800216
Craig Tillera82950e2015-09-22 12:33:20 -0700217void census_get_client_stats(census_aggregated_rpc_stats *data) {
218 get_stats(g_client_stats_store, data);
hongyu24200d32015-01-08 15:13:49 -0800219}
220
Craig Tillera82950e2015-09-22 12:33:20 -0700221void census_get_server_stats(census_aggregated_rpc_stats *data) {
222 get_stats(g_server_stats_store, data);
hongyu24200d32015-01-08 15:13:49 -0800223}
224
Craig Tillera82950e2015-09-22 12:33:20 -0700225void 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);
hongyu24200d32015-01-08 15:13:49 -0800235}
236
Craig Tillera82950e2015-09-22 12:33:20 -0700237void 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 Tiller190d3602015-02-18 09:23:38 -0800253}