histogram.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. *
  3. * Copyright 2015 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 "test/core/util/histogram.h"
  20. #include <math.h>
  21. #include <stddef.h>
  22. #include <string.h>
  23. #include <grpc/support/alloc.h>
  24. #include <grpc/support/log.h>
  25. #include "src/core/lib/gpr/useful.h"
  26. /* Histograms are stored with exponentially increasing bucket sizes.
  27. The first bucket is [0, m) where m = 1 + resolution
  28. Bucket n (n>=1) contains [m**n, m**(n+1))
  29. There are sufficient buckets to reach max_bucket_start */
  30. struct grpc_histogram {
  31. /* Sum of all values seen so far */
  32. double sum;
  33. /* Sum of squares of all values seen so far */
  34. double sum_of_squares;
  35. /* number of values seen so far */
  36. double count;
  37. /* m in the description */
  38. double multiplier;
  39. double one_on_log_multiplier;
  40. /* minimum value seen */
  41. double min_seen;
  42. /* maximum value seen */
  43. double max_seen;
  44. /* maximum representable value */
  45. double max_possible;
  46. /* number of buckets */
  47. size_t num_buckets;
  48. /* the buckets themselves */
  49. uint32_t* buckets;
  50. };
  51. /* determine a bucket index given a value - does no bounds checking */
  52. static size_t bucket_for_unchecked(grpc_histogram* h, double x) {
  53. return static_cast<size_t>(log(x) * h->one_on_log_multiplier);
  54. }
  55. /* bounds checked version of the above */
  56. static size_t bucket_for(grpc_histogram* h, double x) {
  57. size_t bucket =
  58. bucket_for_unchecked(h, grpc_core::Clamp(x, 1.0, h->max_possible));
  59. GPR_ASSERT(bucket < h->num_buckets);
  60. return bucket;
  61. }
  62. /* at what value does a bucket start? */
  63. static double bucket_start(grpc_histogram* h, double x) {
  64. return pow(h->multiplier, x);
  65. }
  66. grpc_histogram* grpc_histogram_create(double resolution,
  67. double max_bucket_start) {
  68. grpc_histogram* h =
  69. static_cast<grpc_histogram*>(gpr_malloc(sizeof(grpc_histogram)));
  70. GPR_ASSERT(resolution > 0.0);
  71. GPR_ASSERT(max_bucket_start > resolution);
  72. h->sum = 0.0;
  73. h->sum_of_squares = 0.0;
  74. h->multiplier = 1.0 + resolution;
  75. h->one_on_log_multiplier = 1.0 / log(1.0 + resolution);
  76. h->max_possible = max_bucket_start;
  77. h->count = 0.0;
  78. h->min_seen = max_bucket_start;
  79. h->max_seen = 0.0;
  80. h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
  81. GPR_ASSERT(h->num_buckets > 1);
  82. GPR_ASSERT(h->num_buckets < 100000000);
  83. h->buckets =
  84. static_cast<uint32_t*>(gpr_zalloc(sizeof(uint32_t) * h->num_buckets));
  85. return h;
  86. }
  87. void grpc_histogram_destroy(grpc_histogram* h) {
  88. gpr_free(h->buckets);
  89. gpr_free(h);
  90. }
  91. void grpc_histogram_add(grpc_histogram* h, double x) {
  92. h->sum += x;
  93. h->sum_of_squares += x * x;
  94. h->count++;
  95. if (x < h->min_seen) {
  96. h->min_seen = x;
  97. }
  98. if (x > h->max_seen) {
  99. h->max_seen = x;
  100. }
  101. h->buckets[bucket_for(h, x)]++;
  102. }
  103. int grpc_histogram_merge(grpc_histogram* dst, const grpc_histogram* src) {
  104. if ((dst->num_buckets != src->num_buckets) ||
  105. (dst->multiplier != src->multiplier)) {
  106. /* Fail because these histograms don't match */
  107. return 0;
  108. }
  109. grpc_histogram_merge_contents(dst, src->buckets, src->num_buckets,
  110. src->min_seen, src->max_seen, src->sum,
  111. src->sum_of_squares, src->count);
  112. return 1;
  113. }
  114. void grpc_histogram_merge_contents(grpc_histogram* histogram,
  115. const uint32_t* data, size_t data_count,
  116. double min_seen, double max_seen, double sum,
  117. double sum_of_squares, double count) {
  118. size_t i;
  119. GPR_ASSERT(histogram->num_buckets == data_count);
  120. histogram->sum += sum;
  121. histogram->sum_of_squares += sum_of_squares;
  122. histogram->count += count;
  123. if (min_seen < histogram->min_seen) {
  124. histogram->min_seen = min_seen;
  125. }
  126. if (max_seen > histogram->max_seen) {
  127. histogram->max_seen = max_seen;
  128. }
  129. for (i = 0; i < histogram->num_buckets; i++) {
  130. histogram->buckets[i] += data[i];
  131. }
  132. }
  133. static double threshold_for_count_below(grpc_histogram* h, double count_below) {
  134. double count_so_far;
  135. double lower_bound;
  136. double upper_bound;
  137. size_t lower_idx;
  138. size_t upper_idx;
  139. if (h->count == 0) {
  140. return 0.0;
  141. }
  142. if (count_below <= 0) {
  143. return h->min_seen;
  144. }
  145. if (count_below >= h->count) {
  146. return h->max_seen;
  147. }
  148. /* find the lowest bucket that gets us above count_below */
  149. count_so_far = 0.0;
  150. for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) {
  151. count_so_far += h->buckets[lower_idx];
  152. if (count_so_far >= count_below) {
  153. break;
  154. }
  155. }
  156. if (count_so_far == count_below) {
  157. /* this bucket hits the threshold exactly... we should be midway through
  158. any run of zero values following the bucket */
  159. for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) {
  160. if (h->buckets[upper_idx]) {
  161. break;
  162. }
  163. }
  164. return (bucket_start(h, static_cast<double>(lower_idx)) +
  165. bucket_start(h, static_cast<double>(upper_idx))) /
  166. 2.0;
  167. } else {
  168. /* treat values as uniform throughout the bucket, and find where this value
  169. should lie */
  170. lower_bound = bucket_start(h, static_cast<double>(lower_idx));
  171. upper_bound = bucket_start(h, static_cast<double>(lower_idx + 1));
  172. return grpc_core::Clamp(upper_bound - (upper_bound - lower_bound) *
  173. (count_so_far - count_below) /
  174. h->buckets[lower_idx],
  175. h->min_seen, h->max_seen);
  176. }
  177. }
  178. double grpc_histogram_percentile(grpc_histogram* h, double percentile) {
  179. return threshold_for_count_below(h, h->count * percentile / 100.0);
  180. }
  181. double grpc_histogram_mean(grpc_histogram* h) {
  182. GPR_ASSERT(h->count != 0);
  183. return h->sum / h->count;
  184. }
  185. double grpc_histogram_stddev(grpc_histogram* h) {
  186. return sqrt(grpc_histogram_variance(h));
  187. }
  188. double grpc_histogram_variance(grpc_histogram* h) {
  189. if (h->count == 0) return 0.0;
  190. return (h->sum_of_squares * h->count - h->sum * h->sum) /
  191. (h->count * h->count);
  192. }
  193. double grpc_histogram_maximum(grpc_histogram* h) { return h->max_seen; }
  194. double grpc_histogram_minimum(grpc_histogram* h) { return h->min_seen; }
  195. double grpc_histogram_count(grpc_histogram* h) { return h->count; }
  196. double grpc_histogram_sum(grpc_histogram* h) { return h->sum; }
  197. double grpc_histogram_sum_of_squares(grpc_histogram* h) {
  198. return h->sum_of_squares;
  199. }
  200. const uint32_t* grpc_histogram_get_contents(grpc_histogram* histogram,
  201. size_t* count) {
  202. *count = histogram->num_buckets;
  203. return histogram->buckets;
  204. }