stats.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <grpc/support/port_platform.h>
  19. #include "src/core/lib/debug/stats.h"
  20. #include <inttypes.h>
  21. #include <string.h>
  22. #include <grpc/support/alloc.h>
  23. #include <grpc/support/string_util.h>
  24. #include "src/core/lib/gpr/string.h"
  25. #include "src/core/lib/gpr/useful.h"
  26. grpc_stats_data* grpc_stats_per_cpu_storage = nullptr;
  27. static size_t g_num_cores;
  28. void grpc_stats_init(void) {
  29. g_num_cores = GPR_MAX(1, gpr_cpu_num_cores());
  30. grpc_stats_per_cpu_storage = static_cast<grpc_stats_data*>(
  31. gpr_zalloc(sizeof(grpc_stats_data) * g_num_cores));
  32. }
  33. void grpc_stats_shutdown(void) { gpr_free(grpc_stats_per_cpu_storage); }
  34. void grpc_stats_collect(grpc_stats_data* output) {
  35. memset(output, 0, sizeof(*output));
  36. for (size_t core = 0; core < g_num_cores; core++) {
  37. for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
  38. output->counters[i] += gpr_atm_no_barrier_load(
  39. &grpc_stats_per_cpu_storage[core].counters[i]);
  40. }
  41. for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_BUCKETS; i++) {
  42. output->histograms[i] += gpr_atm_no_barrier_load(
  43. &grpc_stats_per_cpu_storage[core].histograms[i]);
  44. }
  45. }
  46. }
  47. void grpc_stats_diff(const grpc_stats_data* b, const grpc_stats_data* a,
  48. grpc_stats_data* c) {
  49. for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
  50. c->counters[i] = b->counters[i] - a->counters[i];
  51. }
  52. for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_BUCKETS; i++) {
  53. c->histograms[i] = b->histograms[i] - a->histograms[i];
  54. }
  55. }
  56. int grpc_stats_histo_find_bucket_slow(int value, const int* table,
  57. int table_size) {
  58. GRPC_STATS_INC_HISTOGRAM_SLOW_LOOKUPS();
  59. const int* const start = table;
  60. while (table_size > 0) {
  61. int step = table_size / 2;
  62. const int* it = table + step;
  63. if (value >= *it) {
  64. table = it + 1;
  65. table_size -= step + 1;
  66. } else {
  67. table_size = step;
  68. }
  69. }
  70. return static_cast<int>(table - start) - 1;
  71. }
  72. size_t grpc_stats_histo_count(const grpc_stats_data* stats,
  73. grpc_stats_histograms histogram) {
  74. size_t sum = 0;
  75. for (int i = 0; i < grpc_stats_histo_buckets[histogram]; i++) {
  76. sum += static_cast<size_t>(
  77. stats->histograms[grpc_stats_histo_start[histogram] + i]);
  78. }
  79. return sum;
  80. }
  81. static double threshold_for_count_below(const gpr_atm* bucket_counts,
  82. const int* bucket_boundaries,
  83. int num_buckets, double count_below) {
  84. double count_so_far;
  85. double lower_bound;
  86. double upper_bound;
  87. int lower_idx;
  88. int upper_idx;
  89. /* find the lowest bucket that gets us above count_below */
  90. count_so_far = 0.0;
  91. for (lower_idx = 0; lower_idx < num_buckets; lower_idx++) {
  92. count_so_far += static_cast<double>(bucket_counts[lower_idx]);
  93. if (count_so_far >= count_below) {
  94. break;
  95. }
  96. }
  97. if (count_so_far == count_below) {
  98. /* this bucket hits the threshold exactly... we should be midway through
  99. any run of zero values following the bucket */
  100. for (upper_idx = lower_idx + 1; upper_idx < num_buckets; upper_idx++) {
  101. if (bucket_counts[upper_idx]) {
  102. break;
  103. }
  104. }
  105. return (bucket_boundaries[lower_idx] + bucket_boundaries[upper_idx]) / 2.0;
  106. } else {
  107. /* treat values as uniform throughout the bucket, and find where this value
  108. should lie */
  109. lower_bound = bucket_boundaries[lower_idx];
  110. upper_bound = bucket_boundaries[lower_idx + 1];
  111. return upper_bound - (upper_bound - lower_bound) *
  112. (count_so_far - count_below) /
  113. static_cast<double>(bucket_counts[lower_idx]);
  114. }
  115. }
  116. double grpc_stats_histo_percentile(const grpc_stats_data* stats,
  117. grpc_stats_histograms histogram,
  118. double percentile) {
  119. size_t count = grpc_stats_histo_count(stats, histogram);
  120. if (count == 0) return 0.0;
  121. return threshold_for_count_below(
  122. stats->histograms + grpc_stats_histo_start[histogram],
  123. grpc_stats_histo_bucket_boundaries[histogram],
  124. grpc_stats_histo_buckets[histogram],
  125. static_cast<double>(count) * percentile / 100.0);
  126. }
  127. char* grpc_stats_data_as_json(const grpc_stats_data* data) {
  128. gpr_strvec v;
  129. char* tmp;
  130. bool is_first = true;
  131. gpr_strvec_init(&v);
  132. gpr_strvec_add(&v, gpr_strdup("{"));
  133. for (size_t i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
  134. gpr_asprintf(&tmp, "%s\"%s\": %" PRIdPTR, is_first ? "" : ", ",
  135. grpc_stats_counter_name[i], data->counters[i]);
  136. gpr_strvec_add(&v, tmp);
  137. is_first = false;
  138. }
  139. for (size_t i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
  140. gpr_asprintf(&tmp, "%s\"%s\": [", is_first ? "" : ", ",
  141. grpc_stats_histogram_name[i]);
  142. gpr_strvec_add(&v, tmp);
  143. for (int j = 0; j < grpc_stats_histo_buckets[i]; j++) {
  144. gpr_asprintf(&tmp, "%s%" PRIdPTR, j == 0 ? "" : ",",
  145. data->histograms[grpc_stats_histo_start[i] + j]);
  146. gpr_strvec_add(&v, tmp);
  147. }
  148. gpr_asprintf(&tmp, "], \"%s_bkt\": [", grpc_stats_histogram_name[i]);
  149. gpr_strvec_add(&v, tmp);
  150. for (int j = 0; j < grpc_stats_histo_buckets[i]; j++) {
  151. gpr_asprintf(&tmp, "%s%d", j == 0 ? "" : ",",
  152. grpc_stats_histo_bucket_boundaries[i][j]);
  153. gpr_strvec_add(&v, tmp);
  154. }
  155. gpr_strvec_add(&v, gpr_strdup("]"));
  156. is_first = false;
  157. }
  158. gpr_strvec_add(&v, gpr_strdup("}"));
  159. tmp = gpr_strvec_flatten(&v, nullptr);
  160. gpr_strvec_destroy(&v);
  161. return tmp;
  162. }