Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions deps/histogram/include/hdr/hdr_histogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,9 @@ int64_t hdr_add_while_correcting_for_coordinated_omission(
struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval);

/**
* Get minimum value from the histogram. Will return 2^63-1 if the histogram
* is empty.
* Get minimum value from the histogram. Will return 0 if the histogram is
* empty, like hdr_max; a recorded 0 also gives 0, so use hdr_total_count to
* tell the two apart.
*
* @param h "This" pointer
*/
Expand All @@ -292,35 +293,41 @@ int64_t hdr_total_count(const struct hdr_histogram* h);
* Get the value at a specific percentile.
*
* @param h "This" pointer.
* @param percentile The percentile to get the value for
* @param percentile The percentile to get the value for. Above 100 gives the value at
* 100; below 0 and -inf give the first recorded value. Exactly 0 returns the lowest
* equivalent value of that bucket.
* @return the value at the percentile, or 0 if no values have been recorded.
*/
int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile);

/**
* Get the values at the given percentiles.
*
* @param h "This" pointer.
* @param percentiles The ordered percentiles array to get the values for.
* @param percentiles The ordered percentiles array to get the values for, with the
* same out-of-range handling as hdr_value_at_percentile.
* @param length Number of elements in the arrays.
* @param values Destination array containing the values at the given percentiles.
* The values array should be allocated by the caller.
* @return 0 on success, ENOMEM if the provided destination array is null.
* Percentiles that cannot be resolved get the same value hdr_value_at_percentile
* returns for them, so all are 0 on an empty histogram.
* @return 0 on success, EINVAL if percentiles or values is null.
*/
int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length);

/**
* Gets the standard deviation for the values in the histogram.
*
* @param h "This" pointer
* @return The standard deviation
* @return The standard deviation, or 0.0 if the histogram is empty.
*/
double hdr_stddev(const struct hdr_histogram* h);

/**
* Gets the mean for the values in the histogram.
*
* @param h "This" pointer
* @return The mean
* @return The mean, or 0.0 if the histogram is empty.
*/
double hdr_mean(const struct hdr_histogram* h);

Expand Down
2 changes: 1 addition & 1 deletion deps/histogram/include/hdr/hdr_histogram_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
#ifndef HDR_HISTOGRAM_VERSION_H
#define HDR_HISTOGRAM_VERSION_H

#define HDR_HISTOGRAM_VERSION "0.12.0"
#define HDR_HISTOGRAM_VERSION "0.12.1"

#endif // HDR_HISTOGRAM_VERSION_H
64 changes: 52 additions & 12 deletions deps/histogram/src/hdr_histogram.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ int64_t hdr_total_count(const struct hdr_histogram* h)

int64_t hdr_min(const struct hdr_histogram* h)
{
if (0 < hdr_count_at_index(h, 0))
if (0 == hdr_total_count(h) || 0 < hdr_count_at_index(h, 0))
{
return 0;
}
Expand Down Expand Up @@ -914,36 +914,60 @@ static int64_t get_value_from_idx_up_to_count(const struct hdr_histogram* h, int
}


/* Target cumulative count in [1, total_count]; NaN/+inf -> total_count, -inf/negative -> 1 */
static int64_t count_at_percentile(int64_t total_count, double percentile)
{
const double requested = percentile < 100.0 ? percentile : 100.0;
const double cc = ((requested / 100) * (double) total_count) + 0.5;
if (!(cc >= 1.0)) return 1;
if (cc >= (double) total_count) return total_count;
return (int64_t) cc;
}

int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile)
{
double requested_percentile = percentile < 100.0 ? percentile : 100.0;
int64_t count_at_percentile =
(int64_t) (((requested_percentile / 100) * h->total_count) + 0.5);
int64_t value_from_idx = get_value_from_idx_up_to_count(h, count_at_percentile);
/* empty: the scan's not-found 0 must not be rounded up to highest_equivalent_value(0) */
if (HDR_UNLIKELY(h->total_count == 0))
{
return 0;
}
int64_t value_from_idx =
get_value_from_idx_up_to_count(h, count_at_percentile(h->total_count, percentile));
if (percentile == 0.0)
{
return lowest_equivalent_value(h, value_from_idx);
}
return highest_equivalent_value(h, value_from_idx);
}

/* p0 is the bucket's lowest value, matching hdr_value_at_percentile */
static int64_t percentile_bound(const struct hdr_histogram* h, double percentile, int64_t value)
{
return percentile == 0.0 ? lowest_equivalent_value(h, value) : highest_equivalent_value(h, value);
}

int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length)
{
if (NULL == percentiles || NULL == values)
{
return EINVAL;
}
if (HDR_UNLIKELY(h->total_count == 0))
{
for (size_t i = 0; i < length; i++)
{
values[i] = 0;
}
return 0;
}

struct hdr_iter iter;
const int64_t total_count = h->total_count;
// to avoid allocations we use the values array for intermediate computation
// i.e. to store the expected cumulative count at each percentile
for (size_t i = 0; i < length; i++)
{
const double requested_percentile = percentiles[i] < 100.0 ? percentiles[i] : 100.0;
const int64_t count_at_percentile =
(int64_t) (((requested_percentile / 100) * total_count) + 0.5);
values[i] = count_at_percentile > 1 ? count_at_percentile : 1;
values[i] = count_at_percentile(total_count, percentiles[i]);
}

uint64_t total = 0; /* unsigned: no signed-overflow UB when a hostile block sum is added at once */
Expand Down Expand Up @@ -974,7 +998,7 @@ int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percen
total += (uint64_t)counts[j];
while (at_pos < length && (int64_t)total >= values[at_pos])
{
values[at_pos] = highest_equivalent_value(h, hdr_value_at_index(h, j));
values[at_pos] = percentile_bound(h, percentiles[at_pos], hdr_value_at_index(h, j));
at_pos++;
}
}
Expand All @@ -990,7 +1014,7 @@ int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percen
total += (uint64_t)counts[idx];
while (at_pos < length && (int64_t)total >= values[at_pos])
{
values[at_pos] = highest_equivalent_value(h, hdr_value_at_index(h, idx));
values[at_pos] = percentile_bound(h, percentiles[at_pos], hdr_value_at_index(h, idx));
at_pos++;
}
}
Expand All @@ -1005,11 +1029,17 @@ int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percen
total += (uint64_t)iter.count;
while (at_pos < length && (int64_t)total >= values[at_pos])
{
values[at_pos] = highest_equivalent_value(h, iter.value);
values[at_pos] = percentile_bound(h, percentiles[at_pos], iter.value);
at_pos++;
}
}
}
/* unreached targets (counts below total_count) get the singular's not-found value */
for (; at_pos < length; at_pos++)
{
values[at_pos] = percentiles[at_pos] == 0.0 ?
lowest_equivalent_value(h, 0) : highest_equivalent_value(h, 0);
}
return 0;
}

Expand All @@ -1020,6 +1050,11 @@ double hdr_mean(const struct hdr_histogram* h)
int64_t count = 0;
int64_t total_count = h->total_count;

if (total_count == 0)
{
return 0.0;
}

hdr_iter_init(&iter, h);

while (hdr_iter_next(&iter) && count < total_count)
Expand All @@ -1037,6 +1072,11 @@ double hdr_mean(const struct hdr_histogram* h)

double hdr_stddev(const struct hdr_histogram* h)
{
if (h->total_count == 0)
{
return 0.0;
}

double mean = hdr_mean(h);
double geometric_dev_total = 0.0;

Expand Down
Loading