userver: userver/utils/statistics/histogram.hpp Source File
Loading...
Searching...
No Matches
histogram.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/statistics/histogram.hpp
4/// @brief @copybrief utils::statistics::Histogram
5
6#include <cstdint>
7#include <memory>
8
9#include <userver/utils/span.hpp>
10#include <userver/utils/statistics/fwd.hpp>
11#include <userver/utils/statistics/histogram_view.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils::statistics {
16
17namespace impl::histogram {
18struct BoundsBlock;
19} // namespace impl::histogram
20
21/// @brief A histogram with a dynamically-allocated array of buckets.
22///
23/// ## Histogram metrics
24///
25/// * A histogram metric is a list of counters ("buckets") with specified bounds
26/// * The implicit lowest bound is always 0
27/// * Bucket bounds must follow the ascending order
28/// * Values on the bucket borders fall into the lower bucket
29/// * Besides normal buckets, there is also a special "infinity" bucket,
30/// which contains values that are greater than the greatest bucket bound
31/// * Each individual counter has the semantics of utils::statistics::Rate
32/// * For best portability, there should be no more than 50 buckets
33///
34/// ## Histograms vs utils::statistics::Percentile
35///
36/// @see utils::statistics::Percentile is a related metric type
37///
38/// The trade-offs of histograms with `Percentile` are:
39///
40/// 1. `Percentile` metrics are fundamentally non-summable across multiple
41/// hosts. `Histogram`, on the other hand, are summable
42/// 2. A `Histogram` takes up more storage space on the statistics server,
43/// as there are typically 20-50 buckets in a `Histogram`, but only a few
44/// required percentiles in a `Percentile`
45/// 3. `Percentile` metrics have almost infinite precision, limited only
46/// by the number of allocated atomic counters. The precision of `Histogram`
47/// metrics is limited by the initially set bounds
48///
49/// ## Usage of Histogram
50///
51/// Usage example:
52/// @snippet utils/statistics/histogram_test.cpp sample
53///
54/// Contents of a Histogram are read using utils::statistics::HistogramView.
55/// This can be useful for writing custom metric serialization formats or
56/// for testing.
57///
58/// Histogram metrics can be summed using
59/// utils::statistics::HistogramAggregator.
60///
61/// Histogram can be used in utils::statistics::MetricTag:
62/// @snippet utils/statistics/histogram_test.cpp metric tag
63class Histogram final {
64public:
65 /// @brief Sets upper bounds for each non-"infinite" bucket. The lowest bound is
66 /// always 0.
67 ///
68 /// @param upper_bounds is copied inside and is not required to be kept alive after the constructor completes.
69 explicit Histogram(utils::span<const double> upper_bounds);
70
71 /// Copies an existing histogram.
72 explicit Histogram(HistogramView other);
73
74 Histogram(Histogram&&) noexcept;
75 Histogram(const Histogram&);
76 Histogram& operator=(Histogram&&) noexcept;
77 Histogram& operator=(const Histogram&);
78 ~Histogram();
79
80 /// Atomically increment the bucket corresponding to the given value.
81 void Account(double value, std::uint64_t count = 1) noexcept;
82
83 /// Atomically reset all counters to zero.
84 friend void ResetMetric(Histogram& histogram) noexcept;
85
86 /// Allows reading the histogram.
87 HistogramView GetView() const& noexcept;
88
89 /// @cond
90 // Store Histogram in a variable before taking a view on it.
91 HistogramView GetView() && noexcept = delete;
92 /// @endcond
93
94private:
95 void UpdateBounds();
96
97 std::unique_ptr<impl::histogram::Bucket[]> buckets_;
98 // B+ tree of bucket bounds for optimization of Account.
99 std::unique_ptr<impl::histogram::BoundsBlock[]> bounds_;
100 // Duplicate size here to avoid loading an extra cache line in Account.
101 std::size_t bucket_count_;
102};
103
104/// Metric serialization support for Histogram.
105void DumpMetric(Writer& writer, const Histogram& histogram);
106
107} // namespace utils::statistics
108
109USERVER_NAMESPACE_END