| Server IP : 216.92.14.13 / Your IP : 216.73.216.171 Web Server : Apache System : Linux vps4089.pairvps.com 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 User : rmlac2fmr ( 1040637) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/include/isc/ |
Upload File : |
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
#include <sys/types.h>
#include <isc/mem.h>
/*
* An `isc_histo_t` is a thread-safe histogram of `uint64_t` values.
* It keeps a count of how many values land in each bucket. Use the
* `isc_histo_inc()`, `isc_histo_acc()`, and `isc_histo_put()`
* functions to add values to the histogram.
*
* Values are mapped to buckets by rounding them according to a
* configurable precision, expressed as a number of significant bits.
* The bits <-> digits functions convert betwen decimal significant
* digits (as in scientific notation) and binary significant bits.
*
* You can use the `isc_histo_get()` function to export data from the
* histogram. The range of a bucket is returned as its minimum and
* maximum values, inclusive, i.e. a closed interval. We use closed
* intervals so we are able to express the maximum of the last bucket,
* UINT64_MAX, although half-open intervals are more common in C.
*
* You can calculate some basic statistics directly from a histogram.
* The `isc_histo_quantiles()` function can get a histogram's median,
* 99th percentile, etc. The `isc_histo_moments()` function gets a
* histogram's population, mean, and standard deviation.
*
* The size of a histogram depends on the range of values in the
* stream of samples, not the number of samples. Bucket counters are
* 64 bits each, and are allocated in chunks of `1 << sigbits` where
* `sigbits` is the histogram's configured precision. There are at
* most 64 chunks, one for each bit of a 64 bit value. Histograms with
* greater precision have larger chunks.
*
* At the low end (values near zero) there is one value per bucket,
* then two values, four, eight, etc. The number of values that map to
* a bucket is the same in each chunk. Chunks 0 and 1 have one value
* per bucket, (see `ISC_HISTO_UNITBUCKETS()` below), chunk 2 has 2
* values per bucket, chunk 3 has 4, etc.
*
* The update cost is roughly constant and very small (not much more
* than an atomic increment). It mostly depends on cache locality and
* thread contention.
*
* There is no overflow checking for the 64 bit bucket counters. It
* takes a few nanoseconds to add a sample to the histogram, so it
* would take at least a few CPU-centuries to cause an overflow.
* Aggregate statistics from a quarter of a million CPUs might
* overflow in a day. (Provided that in both examples the CPUs are
* doing nothing apart from repeatedly adding 1 to histogram buckets.)
*/
typedef struct isc_histo isc_histo_t;
typedef struct isc_histomulti isc_histomulti_t;
#define ISC_HISTO_MINBITS 1
#define ISC_HISTO_MAXBITS 18
#define ISC_HISTO_MINDIGITS 1
#define ISC_HISTO_MAXDIGITS 6
#define ISC_HISTO_MAXQUANTILES 101 /* enough for all the percentiles */
/*
* How many values map 1:1 to buckets for a given number of sigbits?
* These are the buckets at the low end, starting from zero.
*/
#define ISC_HISTO_UNITBUCKETS(sigbits) (2 << (sigbits))
void
isc_histo_create(isc_mem_t *mctx, uint sigbits, isc_histo_t **hgp);
/*%<
* Create a histogram.
*
* The relative error of values stored in the histogram is less than
* `pow(2.0, -sigbits)`.
*
* Requires:
*\li `sigbits >= ISC_HISTO_MINBITS`
*\li `sigbits <= ISC_HISTO_MAXBITS`
*\li `hgp != NULL`
*\li `*hgp == NULL`
*
* Ensures:
*\li `*hgp` is a pointer to a histogram.
*/
void
isc_histo_destroy(isc_histo_t **hgp);
/*%<
* Destroy a histogram
*
* Requires:
*\li `hgp != NULL`
*\li `*hgp` is a pointer to a valid histogram
*
* Ensures:
*\li all memory allocated by the histogram has been released
*\li `*hgp` is NULL
*/
uint
isc_histo_sigbits(isc_histo_t *hg);
/*%<
* Get the histogram's `sigbits` setting
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*/
uint
isc_histo_bits_to_digits(uint bits);
/*%<
* Convert binary significant figures to decimal significant figures,
* rounding down, i.e. get the decimal precision you can expect from a
* given number of significant bits.
*
* Requires:
*\li `bits >= ISC_HISTO_MINBITS`
*\li `bits <= ISC_HISTO_MAXBITS`
*/
uint
isc_histo_digits_to_bits(uint digits);
/*%<
* Convert decimal significant figures to binary significant figures,
* rounding up, i.e. get the number of significant bits required to
* achieve the given decimal precision.
*
* Requires:
*\li `digits >= ISC_HISTO_MINDIGS`
*\li `digits <= ISC_HISTO_MAXDIGS`
*/
/**********************************************************************/
void
isc_histo_inc(isc_histo_t *hg, uint64_t value);
/*%<
* Add 1 to the value's bucket
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*/
void
isc_histo_add(isc_histo_t *hg, uint64_t value, uint64_t inc);
/*%<
* Add an arbitrary increment to the value's bucket
*
* Note: there is no counter overflow checking
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*/
void
isc_histo_put(isc_histo_t *hg, uint64_t min, uint64_t max, uint64_t count);
/*
* Import a collection of samples, where values between `min` and
* `max` inclusive occurred `count` times. This function is a
* counterpart to `isc_histo_get()`.
*
* Note: there is no counter overflow checking
*
* Requires:
*\li `min <= max`
*\li `hg` is a pointer to a valid histogram
*/
isc_result_t
isc_histo_get(const isc_histo_t *hg, uint key, uint64_t *minp, uint64_t *maxp,
uint64_t *countp);
/*%<
* Export information about a bucket.
*
* This can be used as an iterator, by initializing `key` to zero
* and incrementing by one or using `isc_histo_next()` until
* `isc_histo_get()` returns ISC_R_RANGE. The number of iterations is
* less than `64 << sigbits`. (64 for the maximum number of chunks,
* multiplied by the size of each chunk.)
*
* It is also a counterpart to `isc_histo_put()`.
*
* If `minp` is non-NULL it is set to the minimum inclusive value
* that maps to this bucket.
*
* If `maxp` is non-NULL it is set to the maximum inclusive value
* that maps to this bucket.
*
* If `countp` is non-NULL it is set to the bucket's counter,
* which can be zero.
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*
* Returns:
*\li ISC_R_SUCCESS, if `key` is valid
*\li ISC_R_RANGE, otherwise
*/
void
isc_histo_next(const isc_histo_t *hg, uint *keyp);
/*%<
* Skip to the next key, omitting chunks of unallocated buckets.
*
* This function does not skip buckets that have been allocated but
* are zero. A chunk contains `1 << sigbits` buckets, and buckets
* are created in bulk one chunk at a time.
*
* Example:
*
* uint64_t min, max, count;
* for (uint key = 0;
* isc_histo_get(hg, key, &min, &max, &count) == ISC_R_SUCCESS;
* isc_histo_next(hg, &key))
* {
* // do something with the bucket
* }
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*\li `keyp != NULL`
*/
void
isc_histo_merge(isc_histo_t **targetp, const isc_histo_t *source);
/*%<
* Increase the counts in `*ptarget` by the counts recorded in `source`
*
* If `*targetp == NULL` then `*ptarget` is set to point to a new
* histogram with the same `sigbits` as the `source`.
*
* This function uses `isc_histo_get()` and `isc_histo_next()` to
* export the data from `source`, and `isc_histo_put()` to import it
* into `*ptarget`.
*
* Requires:
*\li `targetp != NULL`
*\li `*targetp` is NULL or a pointer to a valid histogram
*\li `source` is a pointer to a valid histogram
*
* Ensures:
*\li `*targetp` is a pointer to a valid histogram
*/
/**********************************************************************/
void
isc_histomulti_create(isc_mem_t *mctx, uint sigbits, isc_histomulti_t **hmp);
/*%<
* Create a multithreaded sharded histogram.
*
* Although an `isc_histo_t` is thread-safe, it can suffer
* from cache contention under heavy load. To avoid this,
* an `isc_histomulti_t` contains a histogram per thread,
* so updates are local and low-contention.
*
* Requires:
*\li `sigbits >= ISC_HISTO_MINBITS`
*\li `sigbits <= ISC_HISTO_MAXBITS`
*\li `hmp != NULL`
*\li `*hmp == NULL`
*
* Ensures:
*\li `*hmp` is a pointer to a multithreaded sharded histogram.
*/
void
isc_histomulti_destroy(isc_histomulti_t **hmp);
/*%<
* Destroy a multithreaded sharded histogram
*
* Requires:
*\li `hmp != NULL`
*\li `*hmp` is a pointer to a valid multithreaded sharded histogram
*
* Ensures:
*\li all memory allocated by the histogram has been released
*\li `*hmp == NULL`
*/
void
isc_histomulti_merge(isc_histo_t **targetp, const isc_histomulti_t *source);
/*%<
* Increase the counts in `*targetp` by the counts recorded in `source`
*
* The target histogram is created if `*targetp` is NULL.
*
* Requires:
*\li `targetp != NULL`
*\li `*targetp` is NULL or a pointer to a valid histogram
*\li `source` is a pointer to a valid multithreaded sharded histogram
*
* Ensures:
*\li `*targetp` is a pointer to a valid histogram
*/
void
isc_histomulti_inc(isc_histomulti_t *hm, uint64_t value);
/*%<
* Add 1 to the value's bucket
*
* Requires:
*\li `hm` is a pointer to a valid histomulti
*/
void
isc_histomulti_add(isc_histomulti_t *hm, uint64_t value, uint64_t inc);
/*%<
* Add an arbitrary increment to the value's bucket
*
* Requires:
*\li `hm` is a pointer to a valid histomulti
*/
/**********************************************************************/
void
isc_histo_moments(const isc_histo_t *hg, double *pm0, double *pm1, double *pm2);
/*%<
* Get the population, mean, and standard deviation of a histogram.
*
* If `pm0` is non-NULL it is set to the population of the histogram.
* (Strictly speaking, the zeroth moment is `pop / pop == 1`.)
*
* If `pm1` is non-NULL it is set to the mean (first moment) of the
* recorded data.
*
* If `pm2` is non-NULL it is set to the standard deviation of the
* recorded data. The standard deviation is the square root of the
* variance, which is the second moment about the mean.
*
* It is safe if the histogram is concurrently modified.
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*/
isc_result_t
isc_histo_quantiles(const isc_histo_t *hg, uint size, const double *fraction,
uint64_t *value);
/*%<
* The quantile function (aka inverse cumulative distribution function)
* of the histogram. What value is greater than the given fraction of
* the population?
*
* A fraction of 0.5 gets the median value: it is greater than half
* the population. 0.75 gets the third quartile value, and 0.99 gets
* the 99th percentile value. The fraction must be between 0.0 and 1.0
* inclusive.
*
* https://enwp.org/Quantile_function
*
* This implementation allows you to query quantile values for
* multiple fractions in one function call. Internally, it makes one
* linear scan over the histogram's buckets to find all the fractions.
* Buckets are scanned from high to low, so that querying large
* quantiles is more efficient. The `fraction` array must be sorted in
* decreasing order. The results are stored in the `value` array. Both
* arrays have `size` elements.
*
* The results may be nonsense if the histogram is concurrently
* modified. To get a stable copy you can call `isc_histo_merge()`.
*
* Requires:
*\li `hg` is a pointer to a valid histogram
*\li `0 < size && size <= ISC_HISTO_MAXQUANTILES`
*\li `fraction != NULL`
*\li `value != NULL`
*\li `0.0 <= fraction[i] && fraction[i] <= 1.0` for every element
*\li `fraction[i - 1] > fraction[i]` for every pair of elements
*
* Returns:
*\li ISC_R_SUCCESS, if results were stored in the `value` array
*\li ISC_R_UNSET, if the histogram is empty
*/
/**********************************************************************/