Line data Source code
1 : #include "source/common/stats/histogram_impl.h"
2 :
3 : #include <algorithm>
4 : #include <string>
5 :
6 : #include "source/common/common/utility.h"
7 :
8 : #include "absl/strings/str_join.h"
9 :
10 : namespace Envoy {
11 : namespace Stats {
12 :
13 : namespace {
14 : const ConstSupportedBuckets default_buckets{};
15 : }
16 :
17 : HistogramStatisticsImpl::HistogramStatisticsImpl()
18 0 : : supported_buckets_(default_buckets), computed_quantiles_(supportedQuantiles().size(), 0.0) {}
19 :
20 : HistogramStatisticsImpl::HistogramStatisticsImpl(const histogram_t* histogram_ptr,
21 : Histogram::Unit unit,
22 : ConstSupportedBuckets& supported_buckets)
23 : : supported_buckets_(supported_buckets),
24 3086 : computed_quantiles_(HistogramStatisticsImpl::supportedQuantiles().size(), 0.0), unit_(unit) {
25 3086 : refresh(histogram_ptr);
26 3086 : }
27 :
28 9258 : const std::vector<double>& HistogramStatisticsImpl::supportedQuantiles() const {
29 9258 : CONSTRUCT_ON_FIRST_USE(std::vector<double>,
30 9258 : {0, 0.25, 0.5, 0.75, 0.90, 0.95, 0.99, 0.995, 0.999, 1});
31 9258 : }
32 :
33 0 : std::vector<uint64_t> HistogramStatisticsImpl::computeDisjointBuckets() const {
34 0 : std::vector<uint64_t> buckets;
35 0 : buckets.reserve(computed_buckets_.size());
36 0 : uint64_t previous_computed_bucket = 0;
37 0 : for (uint64_t computed_bucket : computed_buckets_) {
38 0 : buckets.push_back(computed_bucket - previous_computed_bucket);
39 0 : previous_computed_bucket = computed_bucket;
40 0 : }
41 0 : return buckets;
42 0 : }
43 :
44 0 : std::string HistogramStatisticsImpl::quantileSummary() const {
45 0 : std::vector<std::string> summary;
46 0 : const std::vector<double>& supported_quantiles = supportedQuantiles();
47 0 : summary.reserve(supported_quantiles.size());
48 0 : for (size_t i = 0; i < supported_quantiles.size(); ++i) {
49 0 : summary.push_back(
50 0 : fmt::format("P{:g}: {:g}", 100 * supported_quantiles[i], computed_quantiles_[i]));
51 0 : }
52 0 : return absl::StrJoin(summary, ", ");
53 0 : }
54 :
55 0 : std::string HistogramStatisticsImpl::bucketSummary() const {
56 0 : std::vector<std::string> bucket_summary;
57 0 : ConstSupportedBuckets& supported_buckets = supportedBuckets();
58 0 : bucket_summary.reserve(supported_buckets.size());
59 0 : for (size_t i = 0; i < supported_buckets.size(); ++i) {
60 0 : bucket_summary.push_back(fmt::format("B{:g}: {}", supported_buckets[i], computed_buckets_[i]));
61 0 : }
62 0 : return absl::StrJoin(bucket_summary, ", ");
63 0 : }
64 :
65 : /**
66 : * Clears the old computed values and refreshes it with values computed from passed histogram.
67 : */
68 3086 : void HistogramStatisticsImpl::refresh(const histogram_t* new_histogram_ptr) {
69 : // Convert to double once to avoid needing to cast it on every use. Use a double
70 : // to ensure the compiler doesn't try to convert the expression to integer math.
71 3086 : constexpr double percent_scale = Histogram::PercentScale;
72 :
73 3086 : std::fill(computed_quantiles_.begin(), computed_quantiles_.end(), 0.0);
74 3086 : ASSERT(supportedQuantiles().size() == computed_quantiles_.size());
75 3086 : hist_approx_quantile(new_histogram_ptr, supportedQuantiles().data(), supportedQuantiles().size(),
76 3086 : computed_quantiles_.data());
77 3086 : if (unit_ == Histogram::Unit::Percent) {
78 0 : for (double& val : computed_quantiles_) {
79 0 : val /= percent_scale;
80 0 : }
81 0 : }
82 :
83 3086 : sample_count_ = hist_sample_count(new_histogram_ptr);
84 3086 : sample_sum_ = hist_approx_sum(new_histogram_ptr);
85 3086 : if (unit_ == Histogram::Unit::Percent) {
86 0 : sample_sum_ /= percent_scale;
87 0 : }
88 :
89 3086 : computed_buckets_.clear();
90 3086 : ConstSupportedBuckets& supported_buckets = supportedBuckets();
91 3086 : computed_buckets_.reserve(supported_buckets.size());
92 58634 : for (auto bucket : supported_buckets) {
93 58634 : if (unit_ == Histogram::Unit::Percent) {
94 0 : bucket *= percent_scale;
95 0 : }
96 58634 : computed_buckets_.emplace_back(hist_approx_count_below(new_histogram_ptr, bucket));
97 58634 : }
98 :
99 3086 : out_of_bound_count_ = hist_approx_count_above(new_histogram_ptr, supported_buckets.back());
100 3086 : }
101 :
102 : HistogramSettingsImpl::HistogramSettingsImpl(const envoy::config::metrics::v3::StatsConfig& config)
103 134 : : configs_([&config]() {
104 134 : std::vector<Config> configs;
105 134 : for (const auto& matcher : config.histogram_bucket_settings()) {
106 0 : std::vector<double> buckets{matcher.buckets().begin(), matcher.buckets().end()};
107 0 : std::sort(buckets.begin(), buckets.end());
108 0 : configs.emplace_back(matcher.match(), std::move(buckets));
109 0 : }
110 :
111 134 : return configs;
112 134 : }()) {}
113 :
114 1659 : const ConstSupportedBuckets& HistogramSettingsImpl::buckets(absl::string_view stat_name) const {
115 1659 : for (const auto& config : configs_) {
116 0 : if (config.first.match(stat_name)) {
117 0 : return config.second;
118 0 : }
119 0 : }
120 1659 : return defaultBuckets();
121 1659 : }
122 :
123 1659 : const ConstSupportedBuckets& HistogramSettingsImpl::defaultBuckets() {
124 1659 : CONSTRUCT_ON_FIRST_USE(ConstSupportedBuckets,
125 1659 : {0.5, 1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000,
126 1659 : 60000, 300000, 600000, 1800000, 3600000});
127 1659 : }
128 :
129 : } // namespace Stats
130 : } // namespace Envoy
|