From fbb4b3775d3afcb340298d920362e834cb57f9f6 Mon Sep 17 00:00:00 2001 From: Marco Ippolito Date: Thu, 27 Apr 2023 11:56:48 +0200 Subject: [PATCH] deps: update histogram to 0.11.7 PR-URL: https://github.com/nodejs/node/pull/47742 Reviewed-By: Rafael Gonzaga --- deps/histogram/histogram.gyp | 4 +- .../{src => include/hdr}/hdr_histogram.h | 44 +++--- .../include/hdr/hdr_histogram_version.h | 11 ++ deps/histogram/src/hdr_histogram.c | 134 +++++++++++++----- deps/histogram/src/hdr_malloc.h | 19 +++ deps/histogram/src/hdr_tests.h | 2 +- src/histogram.h | 4 +- 7 files changed, 165 insertions(+), 53 deletions(-) rename deps/histogram/{src => include/hdr}/hdr_histogram.h (90%) create mode 100644 deps/histogram/include/hdr/hdr_histogram_version.h create mode 100644 deps/histogram/src/hdr_malloc.h diff --git a/deps/histogram/histogram.gyp b/deps/histogram/histogram.gyp index e3f5fd7a46bb72..3ac86758e72006 100644 --- a/deps/histogram/histogram.gyp +++ b/deps/histogram/histogram.gyp @@ -7,9 +7,9 @@ 'xcode_settings': { 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden }, - 'include_dirs': ['src'], + 'include_dirs': ['src', 'include'], 'direct_dependent_settings': { - 'include_dirs': [ 'src' ] + 'include_dirs': [ 'src', 'include' ] }, 'sources': [ 'src/hdr_histogram.c', diff --git a/deps/histogram/src/hdr_histogram.h b/deps/histogram/include/hdr/hdr_histogram.h similarity index 90% rename from deps/histogram/src/hdr_histogram.h rename to deps/histogram/include/hdr/hdr_histogram.h index aff51f1c11526a..59ffe54d5cdd1d 100644 --- a/deps/histogram/src/hdr_histogram.h +++ b/deps/histogram/include/hdr/hdr_histogram.h @@ -16,7 +16,7 @@ struct hdr_histogram { - int64_t lowest_trackable_value; + int64_t lowest_discernible_value; int64_t highest_trackable_value; int32_t unit_magnitude; int32_t significant_figures; @@ -45,8 +45,8 @@ extern "C" { * involved math on the input parameters this function it is tricky to stack allocate. * The histogram should be released with hdr_close * - * @param lowest_trackable_value The smallest possible value to be put into the - * histogram. + * @param lowest_discernible_value The smallest possible value that is distinguishable from 0. + * Must be a positive integer that is >= 1. May be internally rounded down to nearest power of 2. * @param highest_trackable_value The largest possible value to be put into the * histogram. * @param significant_figures The level of precision for this histogram, i.e. the number @@ -54,12 +54,12 @@ extern "C" { * the results from the histogram will be accurate up to the first three digits. Must * be a value between 1 and 5 (inclusive). * @param result Output parameter to capture allocated histogram. - * @return 0 on success, EINVAL if lowest_trackable_value is < 1 or the + * @return 0 on success, EINVAL if lowest_discernible_value is < 1 or the * significant_figure value is outside of the allowed range, ENOMEM if malloc * failed. */ int hdr_init( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result); @@ -159,10 +159,10 @@ bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t co * Record a value in the histogram and backfill based on an expected interval. * * Records a value in the histogram, will round this value of to a precision at or better - * than the significant_figure specified at contruction time. This is specifically used + * than the significant_figure specified at construction time. This is specifically used * for recording latency. If the value is larger than the expected_interval then the * latency recording system has experienced co-ordinated omission. This method fills in the - * values that would have occured had the client providing the load not been blocked. + * values that would have occurred had the client providing the load not been blocked. * @param h "This" pointer * @param value Value to add to the histogram @@ -170,16 +170,16 @@ bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t co * @return false if the value is larger than the highest_trackable_value and can't be recorded, * true otherwise. */ -bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval); +bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval); /** * Record a value in the histogram and backfill based on an expected interval. * * Records a value in the histogram, will round this value of to a precision at or better - * than the significant_figure specified at contruction time. This is specifically used + * than the significant_figure specified at construction time. This is specifically used * for recording latency. If the value is larger than the expected_interval then the * latency recording system has experienced co-ordinated omission. This method fills in the - * values that would have occured had the client providing the load not been blocked. + * values that would have occurred had the client providing the load not been blocked. * * Will record this value atomically, however the whole structure may appear inconsistent * when read concurrently with this update. Do NOT mix calls to this method with calls @@ -191,7 +191,7 @@ bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t * @return false if the value is larger than the highest_trackable_value and can't be recorded, * true otherwise. */ -bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval); +bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval); /** * Record a value in the histogram 'count' times. Applies the same correcting logic @@ -226,7 +226,7 @@ bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, /** * Adds all of the values from 'from' to 'this' histogram. Will return the * number of values that are dropped when copying. Values will be dropped - * if they around outside of h.lowest_trackable_value and + * if they around outside of h.lowest_discernible_value and * h.highest_trackable_value. * * @param h "This" pointer @@ -238,7 +238,7 @@ int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from); /** * Adds all of the values from 'from' to 'this' histogram. Will return the * number of values that are dropped when copying. Values will be dropped - * if they around outside of h.lowest_trackable_value and + * if they around outside of h.lowest_discernible_value and * h.highest_trackable_value. * * @param h "This" pointer @@ -272,6 +272,18 @@ int64_t hdr_max(const struct hdr_histogram* h); */ 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 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. + */ +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. * @@ -465,7 +477,7 @@ int hdr_percentiles_print( */ struct hdr_histogram_bucket_config { - int64_t lowest_trackable_value; + int64_t lowest_discernible_value; int64_t highest_trackable_value; int64_t unit_magnitude; int64_t significant_figures; @@ -478,7 +490,7 @@ struct hdr_histogram_bucket_config }; int hdr_calculate_bucket_config( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram_bucket_config* cfg); @@ -492,7 +504,7 @@ int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t val int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value); /** - * Used to reset counters after importing data manuallying into the histogram, used by the logging code + * Used to reset counters after importing data manually into the histogram, used by the logging code * and other custom serialisation tools. */ void hdr_reset_internal_counters(struct hdr_histogram* h); diff --git a/deps/histogram/include/hdr/hdr_histogram_version.h b/deps/histogram/include/hdr/hdr_histogram_version.h new file mode 100644 index 00000000000000..7724d7579b4b5b --- /dev/null +++ b/deps/histogram/include/hdr/hdr_histogram_version.h @@ -0,0 +1,11 @@ +/** + * @file hdr_histogram_version.h + * @brief Definitions for HdrHistogram's version number. + */ + +#ifndef HDR_HISTOGRAM_VERSION_H +#define HDR_HISTOGRAM_VERSION_H + +#define HDR_HISTOGRAM_VERSION "0.11.7" + +#endif // HDR_HISTOGRAM_VERSION_H \ No newline at end of file diff --git a/deps/histogram/src/hdr_histogram.c b/deps/histogram/src/hdr_histogram.c index 0132cbeba7c84e..7a4c4fdfa30ff6 100644 --- a/deps/histogram/src/hdr_histogram.c +++ b/deps/histogram/src/hdr_histogram.c @@ -13,10 +13,16 @@ #include #include -#include "hdr_histogram.h" +#include #include "hdr_tests.h" #include "hdr_atomic.h" +#ifndef HDR_MALLOC_INCLUDE +#define HDR_MALLOC_INCLUDE "hdr_malloc.h" +#endif + +#include HDR_MALLOC_INCLUDE + /* ###### ####### ## ## ## ## ######## ###### */ /* ## ## ## ## ## ## ### ## ## ## ## */ /* ## ## ## ## ## #### ## ## ## */ @@ -216,6 +222,15 @@ int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_ return INT64_C(1) << (h->unit_magnitude + adjusted_bucket); } +static int64_t size_of_equivalent_value_range_given_bucket_indices( + const struct hdr_histogram *h, + int32_t bucket_index, + int32_t sub_bucket_index) +{ + const int32_t adjusted_bucket = (sub_bucket_index >= h->sub_bucket_count) ? (bucket_index + 1) : bucket_index; + return INT64_C(1) << (h->unit_magnitude + adjusted_bucket); +} + static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t value) { int32_t bucket_index = get_bucket_index(h, value); @@ -223,6 +238,14 @@ static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t va return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude); } +static int64_t lowest_equivalent_value_given_bucket_indices( + const struct hdr_histogram *h, + int32_t bucket_index, + int32_t sub_bucket_index) +{ + return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude); +} + int64_t hdr_next_non_equivalent_value(const struct hdr_histogram *h, int64_t value) { return lowest_equivalent_value(h, value) + hdr_size_of_equivalent_value_range(h, value); @@ -318,7 +341,7 @@ static int32_t buckets_needed_to_cover_value(int64_t value, int32_t sub_bucket_c /* ## ## ######## ## ## ####### ## ## ## */ int hdr_calculate_bucket_config( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram_bucket_config* cfg) @@ -326,14 +349,14 @@ int hdr_calculate_bucket_config( int32_t sub_bucket_count_magnitude; int64_t largest_value_with_single_unit_resolution; - if (lowest_trackable_value < 1 || + if (lowest_discernible_value < 1 || significant_figures < 1 || 5 < significant_figures || - lowest_trackable_value * 2 > highest_trackable_value) + lowest_discernible_value * 2 > highest_trackable_value) { return EINVAL; } - cfg->lowest_trackable_value = lowest_trackable_value; + cfg->lowest_discernible_value = lowest_discernible_value; cfg->significant_figures = significant_figures; cfg->highest_trackable_value = highest_trackable_value; @@ -341,7 +364,7 @@ int hdr_calculate_bucket_config( sub_bucket_count_magnitude = (int32_t) ceil(log((double)largest_value_with_single_unit_resolution) / log(2)); cfg->sub_bucket_half_count_magnitude = ((sub_bucket_count_magnitude > 1) ? sub_bucket_count_magnitude : 1) - 1; - double unit_magnitude = log((double)lowest_trackable_value) / log(2); + double unit_magnitude = log((double)lowest_discernible_value) / log(2); if (INT32_MAX < unit_magnitude) { return EINVAL; @@ -365,7 +388,7 @@ int hdr_calculate_bucket_config( void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg) { - h->lowest_trackable_value = cfg->lowest_trackable_value; + h->lowest_discernible_value = cfg->lowest_discernible_value; h->highest_trackable_value = cfg->highest_trackable_value; h->unit_magnitude = (int32_t)cfg->unit_magnitude; h->significant_figures = (int32_t)cfg->significant_figures; @@ -383,7 +406,7 @@ void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_ } int hdr_init( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result) @@ -392,22 +415,22 @@ int hdr_init( struct hdr_histogram_bucket_config cfg; struct hdr_histogram* histogram; - int r = hdr_calculate_bucket_config(lowest_trackable_value, highest_trackable_value, significant_figures, &cfg); + int r = hdr_calculate_bucket_config(lowest_discernible_value, highest_trackable_value, significant_figures, &cfg); if (r) { return r; } - counts = (int64_t*) calloc((size_t) cfg.counts_len, sizeof(int64_t)); + counts = (int64_t*) hdr_calloc((size_t) cfg.counts_len, sizeof(int64_t)); if (!counts) { return ENOMEM; } - histogram = (struct hdr_histogram*) calloc(1, sizeof(struct hdr_histogram)); + histogram = (struct hdr_histogram*) hdr_calloc(1, sizeof(struct hdr_histogram)); if (!histogram) { - free(counts); + hdr_free(counts); return ENOMEM; } @@ -422,8 +445,8 @@ int hdr_init( void hdr_close(struct hdr_histogram* h) { if (h) { - free(h->counts); - free(h); + hdr_free(h->counts); + hdr_free(h); } } @@ -643,47 +666,89 @@ int64_t hdr_min(const struct hdr_histogram* h) return non_zero_min(h); } +static int64_t get_value_from_idx_up_to_count(const struct hdr_histogram* h, int64_t count_at_percentile) +{ + int64_t count_to_idx = 0; + + count_at_percentile = 0 < count_at_percentile ? count_at_percentile : 1; + for (int32_t idx = 0; idx < h->counts_len; idx++) + { + count_to_idx += h->counts[idx]; + if (count_to_idx >= count_at_percentile) + { + return hdr_value_at_index(h, idx); + } + } + + return 0; +} + + int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile) { - struct hdr_iter iter; - int64_t total = 0; double requested_percentile = percentile < 100.0 ? percentile : 100.0; int64_t count_at_percentile = (int64_t) (((requested_percentile / 100) * h->total_count) + 0.5); - count_at_percentile = count_at_percentile > 1 ? count_at_percentile : 1; + int64_t value_from_idx = get_value_from_idx_up_to_count(h, count_at_percentile); + if (percentile == 0.0) + { + return lowest_equivalent_value(h, value_from_idx); + } + return highest_equivalent_value(h, value_from_idx); +} - hdr_iter_init(&iter, h); +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; + } - while (hdr_iter_next(&iter)) + 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++) { - total += iter.count; + 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; + } - if (total >= count_at_percentile) + hdr_iter_init(&iter, h); + int64_t total = 0; + size_t at_pos = 0; + while (hdr_iter_next(&iter) && at_pos < length) + { + total += iter.count; + while (at_pos < length && total >= values[at_pos]) { - int64_t value_from_index = iter.value; - return highest_equivalent_value(h, value_from_index); + values[at_pos] = highest_equivalent_value(h, iter.value); + at_pos++; } } - return 0; } double hdr_mean(const struct hdr_histogram* h) { struct hdr_iter iter; - int64_t total = 0; + int64_t total = 0, count = 0; + int64_t total_count = h->total_count; hdr_iter_init(&iter, h); - while (hdr_iter_next(&iter)) + while (hdr_iter_next(&iter) && count < total_count) { if (0 != iter.count) { + count += iter.count; total += iter.count * hdr_median_equivalent_value(h, iter.value); } } - return (total * 1.0) / h->total_count; + return (total * 1.0) / total_count; } double hdr_stddev(const struct hdr_histogram* h) @@ -757,11 +822,16 @@ static bool move_next(struct hdr_iter* iter) iter->count = counts_get_normalised(iter->h, iter->counts_index); iter->cumulative_count += iter->count; - - iter->value = hdr_value_at_index(iter->h, iter->counts_index); - iter->highest_equivalent_value = highest_equivalent_value(iter->h, iter->value); - iter->lowest_equivalent_value = lowest_equivalent_value(iter->h, iter->value); - iter->median_equivalent_value = hdr_median_equivalent_value(iter->h, iter->value); + const int64_t value = hdr_value_at_index(iter->h, iter->counts_index); + const int32_t bucket_index = get_bucket_index(iter->h, value); + const int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, iter->h->unit_magnitude); + const int64_t leq = lowest_equivalent_value_given_bucket_indices(iter->h, bucket_index, sub_bucket_index); + const int64_t size_of_equivalent_value_range = size_of_equivalent_value_range_given_bucket_indices( + iter->h, bucket_index, sub_bucket_index); + iter->lowest_equivalent_value = leq; + iter->value = value; + iter->highest_equivalent_value = leq + size_of_equivalent_value_range - 1; + iter->median_equivalent_value = leq + (size_of_equivalent_value_range >> 1); return true; } diff --git a/deps/histogram/src/hdr_malloc.h b/deps/histogram/src/hdr_malloc.h new file mode 100644 index 00000000000000..6fefc6881b1df8 --- /dev/null +++ b/deps/histogram/src/hdr_malloc.h @@ -0,0 +1,19 @@ +/** + * hdr_malloc.h + * Written by Filipe Oliveira and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + * + * Allocator selection. + * + * This file is used in order to change the HdrHistogram allocator at compile time. + * Just define the following defines to what you want to use. Also add + * the include of your alternate allocator if needed (not needed in order + * to use the default libc allocator). */ + +#ifndef HDR_MALLOC_H__ +#define HDR_MALLOC_H__ +#define hdr_malloc malloc +#define hdr_calloc calloc +#define hdr_realloc realloc +#define hdr_free free +#endif diff --git a/deps/histogram/src/hdr_tests.h b/deps/histogram/src/hdr_tests.h index c016d3a6de09aa..5cc65a0c71d008 100644 --- a/deps/histogram/src/hdr_tests.h +++ b/deps/histogram/src/hdr_tests.h @@ -3,7 +3,7 @@ /* These are functions used in tests and are not intended for normal usage. */ -#include "hdr_histogram.h" +#include #ifdef __cplusplus extern "C" { diff --git a/src/histogram.h b/src/histogram.h index d526bba8a1b797..166a11063334e9 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -3,13 +3,13 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "hdr_histogram.h" +#include #include "base_object.h" #include "memory_tracker.h" #include "node_messaging.h" #include "util.h" -#include "v8.h" #include "uv.h" +#include "v8.h" #include #include