Index: third_party/grpc/src/core/support/histogram.c |
diff --git a/third_party/grpc/src/core/support/histogram.c b/third_party/grpc/src/core/support/histogram.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..20ed2b14b140b6322295197be9c6d47321c1acab |
--- /dev/null |
+++ b/third_party/grpc/src/core/support/histogram.c |
@@ -0,0 +1,244 @@ |
+/* |
+ * |
+ * Copyright 2015, Google Inc. |
+ * All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ * |
+ */ |
+ |
+#include <grpc/support/histogram.h> |
+ |
+#include <math.h> |
+#include <stddef.h> |
+#include <string.h> |
+ |
+#include <grpc/support/alloc.h> |
+#include <grpc/support/port_platform.h> |
+#include <grpc/support/log.h> |
+#include <grpc/support/useful.h> |
+ |
+/* Histograms are stored with exponentially increasing bucket sizes. |
+ The first bucket is [0, m) where m = 1 + resolution |
+ Bucket n (n>=1) contains [m**n, m**(n+1)) |
+ There are sufficient buckets to reach max_bucket_start */ |
+ |
+struct gpr_histogram { |
+ /* Sum of all values seen so far */ |
+ double sum; |
+ /* Sum of squares of all values seen so far */ |
+ double sum_of_squares; |
+ /* number of values seen so far */ |
+ double count; |
+ /* m in the description */ |
+ double multiplier; |
+ double one_on_log_multiplier; |
+ /* minimum value seen */ |
+ double min_seen; |
+ /* maximum value seen */ |
+ double max_seen; |
+ /* maximum representable value */ |
+ double max_possible; |
+ /* number of buckets */ |
+ size_t num_buckets; |
+ /* the buckets themselves */ |
+ uint32_t *buckets; |
+}; |
+ |
+/* determine a bucket index given a value - does no bounds checking */ |
+static size_t bucket_for_unchecked(gpr_histogram *h, double x) { |
+ return (size_t)(log(x) * h->one_on_log_multiplier); |
+} |
+ |
+/* bounds checked version of the above */ |
+static size_t bucket_for(gpr_histogram *h, double x) { |
+ size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible)); |
+ GPR_ASSERT(bucket < h->num_buckets); |
+ return bucket; |
+} |
+ |
+/* at what value does a bucket start? */ |
+static double bucket_start(gpr_histogram *h, double x) { |
+ return pow(h->multiplier, x); |
+} |
+ |
+gpr_histogram *gpr_histogram_create(double resolution, |
+ double max_bucket_start) { |
+ gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); |
+ GPR_ASSERT(resolution > 0.0); |
+ GPR_ASSERT(max_bucket_start > resolution); |
+ h->sum = 0.0; |
+ h->sum_of_squares = 0.0; |
+ h->multiplier = 1.0 + resolution; |
+ h->one_on_log_multiplier = 1.0 / log(1.0 + resolution); |
+ h->max_possible = max_bucket_start; |
+ h->count = 0.0; |
+ h->min_seen = max_bucket_start; |
+ h->max_seen = 0.0; |
+ h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; |
+ GPR_ASSERT(h->num_buckets > 1); |
+ GPR_ASSERT(h->num_buckets < 100000000); |
+ h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets); |
+ memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets); |
+ return h; |
+} |
+ |
+void gpr_histogram_destroy(gpr_histogram *h) { |
+ gpr_free(h->buckets); |
+ gpr_free(h); |
+} |
+ |
+void gpr_histogram_add(gpr_histogram *h, double x) { |
+ h->sum += x; |
+ h->sum_of_squares += x * x; |
+ h->count++; |
+ if (x < h->min_seen) { |
+ h->min_seen = x; |
+ } |
+ if (x > h->max_seen) { |
+ h->max_seen = x; |
+ } |
+ h->buckets[bucket_for(h, x)]++; |
+} |
+ |
+int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) { |
+ if ((dst->num_buckets != src->num_buckets) || |
+ (dst->multiplier != src->multiplier)) { |
+ /* Fail because these histograms don't match */ |
+ return 0; |
+ } |
+ gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets, |
+ src->min_seen, src->max_seen, src->sum, |
+ src->sum_of_squares, src->count); |
+ return 1; |
+} |
+ |
+void gpr_histogram_merge_contents(gpr_histogram *dst, const uint32_t *data, |
+ size_t data_count, double min_seen, |
+ double max_seen, double sum, |
+ double sum_of_squares, double count) { |
+ size_t i; |
+ GPR_ASSERT(dst->num_buckets == data_count); |
+ dst->sum += sum; |
+ dst->sum_of_squares += sum_of_squares; |
+ dst->count += count; |
+ if (min_seen < dst->min_seen) { |
+ dst->min_seen = min_seen; |
+ } |
+ if (max_seen > dst->max_seen) { |
+ dst->max_seen = max_seen; |
+ } |
+ for (i = 0; i < dst->num_buckets; i++) { |
+ dst->buckets[i] += data[i]; |
+ } |
+} |
+ |
+static double threshold_for_count_below(gpr_histogram *h, double count_below) { |
+ double count_so_far; |
+ double lower_bound; |
+ double upper_bound; |
+ size_t lower_idx; |
+ size_t upper_idx; |
+ |
+ if (h->count == 0) { |
+ return 0.0; |
+ } |
+ |
+ if (count_below <= 0) { |
+ return h->min_seen; |
+ } |
+ if (count_below >= h->count) { |
+ return h->max_seen; |
+ } |
+ |
+ /* find the lowest bucket that gets us above count_below */ |
+ count_so_far = 0.0; |
+ for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) { |
+ count_so_far += h->buckets[lower_idx]; |
+ if (count_so_far >= count_below) { |
+ break; |
+ } |
+ } |
+ if (count_so_far == count_below) { |
+ /* this bucket hits the threshold exactly... we should be midway through |
+ any run of zero values following the bucket */ |
+ for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) { |
+ if (h->buckets[upper_idx]) { |
+ break; |
+ } |
+ } |
+ return (bucket_start(h, (double)lower_idx) + |
+ bucket_start(h, (double)upper_idx)) / |
+ 2.0; |
+ } else { |
+ /* treat values as uniform throughout the bucket, and find where this value |
+ should lie */ |
+ lower_bound = bucket_start(h, (double)lower_idx); |
+ upper_bound = bucket_start(h, (double)(lower_idx + 1)); |
+ return GPR_CLAMP(upper_bound - |
+ (upper_bound - lower_bound) * |
+ (count_so_far - count_below) / |
+ h->buckets[lower_idx], |
+ h->min_seen, h->max_seen); |
+ } |
+} |
+ |
+double gpr_histogram_percentile(gpr_histogram *h, double percentile) { |
+ return threshold_for_count_below(h, h->count * percentile / 100.0); |
+} |
+ |
+double gpr_histogram_mean(gpr_histogram *h) { |
+ GPR_ASSERT(h->count != 0); |
+ return h->sum / h->count; |
+} |
+ |
+double gpr_histogram_stddev(gpr_histogram *h) { |
+ return sqrt(gpr_histogram_variance(h)); |
+} |
+ |
+double gpr_histogram_variance(gpr_histogram *h) { |
+ if (h->count == 0) return 0.0; |
+ return (h->sum_of_squares * h->count - h->sum * h->sum) / |
+ (h->count * h->count); |
+} |
+ |
+double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; } |
+ |
+double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; } |
+ |
+double gpr_histogram_count(gpr_histogram *h) { return h->count; } |
+ |
+double gpr_histogram_sum(gpr_histogram *h) { return h->sum; } |
+ |
+double gpr_histogram_sum_of_squares(gpr_histogram *h) { |
+ return h->sum_of_squares; |
+} |
+ |
+const uint32_t *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) { |
+ *size = h->num_buckets; |
+ return h->buckets; |
+} |