histogram.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  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. #include <grpc/support/histogram.h>
  34. #include <math.h>
  35. #include <stddef.h>
  36. #include <string.h>
  37. #include <grpc/support/alloc.h>
  38. #include <grpc/support/port_platform.h>
  39. #include <grpc/support/log.h>
  40. #include <grpc/support/useful.h>
  41. /* Histograms are stored with exponentially increasing bucket sizes.
  42. The first bucket is [0, m) where m = 1 + resolution
  43. Bucket n (n>=1) contains [m**n, m**(n+1))
  44. There are sufficient buckets to reach max_bucket_start */
  45. struct gpr_histogram {
  46. /* Sum of all values seen so far */
  47. double sum;
  48. /* Sum of squares of all values seen so far */
  49. double sum_of_squares;
  50. /* number of values seen so far */
  51. double count;
  52. /* m in the description */
  53. double multiplier;
  54. double one_on_log_multiplier;
  55. /* minimum value seen */
  56. double min_seen;
  57. /* maximum value seen */
  58. double max_seen;
  59. /* maximum representable value */
  60. double max_possible;
  61. /* number of buckets */
  62. size_t num_buckets;
  63. /* the buckets themselves */
  64. gpr_uint32 *buckets;
  65. };
  66. /* determine a bucket index given a value - does no bounds checking */
  67. static size_t bucket_for_unchecked(gpr_histogram *h, double x) {
  68. return (size_t)(log(x) * h->one_on_log_multiplier);
  69. }
  70. /* bounds checked version of the above */
  71. static size_t bucket_for(gpr_histogram *h, double x) {
  72. size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 0, h->max_possible));
  73. GPR_ASSERT(bucket < h->num_buckets);
  74. return bucket;
  75. }
  76. /* at what value does a bucket start? */
  77. static double bucket_start(gpr_histogram *h, double x) {
  78. return pow(h->multiplier, x);
  79. }
  80. gpr_histogram *gpr_histogram_create(double resolution,
  81. double max_bucket_start) {
  82. gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram));
  83. GPR_ASSERT(resolution > 0.0);
  84. GPR_ASSERT(max_bucket_start > resolution);
  85. h->sum = 0.0;
  86. h->sum_of_squares = 0.0;
  87. h->multiplier = 1.0 + resolution;
  88. h->one_on_log_multiplier = 1.0 / log(1.0 + resolution);
  89. h->max_possible = max_bucket_start;
  90. h->count = 0.0;
  91. h->min_seen = max_bucket_start;
  92. h->max_seen = 0.0;
  93. h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
  94. GPR_ASSERT(h->num_buckets > 1);
  95. GPR_ASSERT(h->num_buckets < 100000000);
  96. h->buckets = gpr_malloc(sizeof(gpr_uint32) * h->num_buckets);
  97. memset(h->buckets, 0, sizeof(gpr_uint32) * h->num_buckets);
  98. return h;
  99. }
  100. void gpr_histogram_destroy(gpr_histogram *h) {
  101. gpr_free(h->buckets);
  102. gpr_free(h);
  103. }
  104. void gpr_histogram_add(gpr_histogram *h, double x) {
  105. h->sum += x;
  106. h->sum_of_squares += x * x;
  107. h->count++;
  108. if (x < h->min_seen) {
  109. h->min_seen = x;
  110. }
  111. if (x > h->max_seen) {
  112. h->max_seen = x;
  113. }
  114. h->buckets[bucket_for(h, x)]++;
  115. }
  116. int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) {
  117. size_t i;
  118. if ((dst->num_buckets != src->num_buckets) ||
  119. (dst->multiplier != src->multiplier)) {
  120. /* Fail because these histograms don't match */
  121. return 0;
  122. }
  123. dst->sum += src->sum;
  124. dst->sum_of_squares += src->sum_of_squares;
  125. dst->count += src->count;
  126. if (src->min_seen < dst->min_seen) {
  127. dst->min_seen = src->min_seen;
  128. }
  129. if (src->max_seen > dst->max_seen) {
  130. dst->max_seen = src->max_seen;
  131. }
  132. for (i = 0; i < dst->num_buckets; i++) {
  133. dst->buckets[i] += src->buckets[i];
  134. }
  135. return 1;
  136. }
  137. static double threshold_for_count_below(gpr_histogram *h, double count_below) {
  138. double count_so_far;
  139. double lower_bound;
  140. double upper_bound;
  141. size_t lower_idx;
  142. size_t upper_idx;
  143. GPR_ASSERT(h->count >= 1);
  144. if (count_below <= 0) {
  145. return h->min_seen;
  146. }
  147. if (count_below >= h->count) {
  148. return h->max_seen;
  149. }
  150. /* find the lowest bucket that gets us above count_below */
  151. count_so_far = 0.0;
  152. for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) {
  153. count_so_far += h->buckets[lower_idx];
  154. if (count_so_far >= count_below) {
  155. break;
  156. }
  157. }
  158. if (count_so_far == count_below) {
  159. /* this bucket hits the threshold exactly... we should be midway through
  160. any run of zero values following the bucket */
  161. for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) {
  162. if (h->buckets[upper_idx]) {
  163. break;
  164. }
  165. }
  166. return (bucket_start(h, lower_idx) + bucket_start(h, upper_idx)) / 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, lower_idx);
  171. upper_bound = bucket_start(h, lower_idx + 1);
  172. return GPR_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 gpr_histogram_percentile(gpr_histogram *h, double percentile) {
  179. return threshold_for_count_below(h, h->count * percentile / 100.0);
  180. }
  181. double gpr_histogram_mean(gpr_histogram *h) {
  182. GPR_ASSERT(h->count);
  183. return h->sum / h->count;
  184. }
  185. double gpr_histogram_stddev(gpr_histogram *h) {
  186. return sqrt(gpr_histogram_variance(h));
  187. }
  188. double gpr_histogram_variance(gpr_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 gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; }
  194. double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; }
  195. double gpr_histogram_count(gpr_histogram *h) { return h->count; }
  196. double gpr_histogram_sum(gpr_histogram *h) { return h->sum; }
  197. double gpr_histogram_sum_of_squares(gpr_histogram *h) {
  198. return h->sum_of_squares;
  199. }