2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 // By convention, we are using microsecond units
39 Bucket(std::string name, uint64_t boundary, uint64_t val) :
40 d_name(std::move(name)), d_boundary(boundary), d_count(val) {}
41 const std::string d_name;
42 const uint64_t d_boundary;
43 mutable uint64_t d_count{0};
45 Bucket(const Bucket&) = default;
46 Bucket& operator=(const Bucket& rhs)
48 assert(d_name == rhs.d_name);
49 assert(d_boundary == rhs.d_boundary);
50 d_count = rhs.d_count;
57 // We need the constructors in this case, since atomics have a disabled copy constructor.
58 AtomicBucket() = default;
59 AtomicBucket(std::string name, uint64_t boundary, uint64_t val) :
60 d_name(std::move(name)), d_boundary(boundary), d_count(val) {}
61 AtomicBucket(const AtomicBucket& rhs) :
62 d_name(rhs.d_name), d_boundary(rhs.d_boundary), d_count(rhs.d_count.load()) {}
64 const std::string d_name;
65 const uint64_t d_boundary{0};
66 mutable stat_t d_count{0};
69 template <class B, class SumType>
73 BaseHistogram(const std::string& prefix, const std::vector<uint64_t>& boundaries) :
76 if (!std::is_sorted(boundaries.cbegin(), boundaries.cend())) {
77 throw std::invalid_argument("boundary array must be sorted");
79 if (boundaries.size() == 0) {
80 throw std::invalid_argument("boundary array must not be empty");
82 if (boundaries[0] == 0) {
83 throw std::invalid_argument("boundary array's first element should not be zero");
85 d_buckets.reserve(boundaries.size() + 1);
87 for (auto b : boundaries) {
89 throw std::invalid_argument("boundary array's elements should be distinct");
91 std::string str = prefix + "le-" + std::to_string(b);
92 d_buckets.emplace_back(str, b, 0);
96 // everything above last boundary
97 d_buckets.emplace_back(prefix + "le-max", std::numeric_limits<uint64_t>::max(), 0);
100 BaseHistogram(const std::string& prefix, uint64_t start, int num) :
101 BaseHistogram(prefix, to125(start, num))
105 std::string getName() const
110 uint64_t getSum() const
115 const std::vector<B>& getRawData() const
120 uint64_t getCount(size_t i) const
122 return d_buckets[i].d_count;
125 std::vector<B> getCumulativeBuckets() const
128 ret.reserve(d_buckets.size());
130 for (const auto& b : d_buckets) {
132 ret.emplace_back(b.d_name, b.d_boundary, c);
137 std::vector<uint64_t> getCumulativeCounts() const
139 std::vector<uint64_t> ret;
140 ret.reserve(d_buckets.size());
142 for (const auto& b : d_buckets) {
149 static bool lessOrEqual(uint64_t b, const B& bu)
151 return b <= bu.d_boundary;
154 inline void operator()(uint64_t d) const
156 auto index = std::upper_bound(d_buckets.begin(), d_buckets.end(), d, lessOrEqual);
157 // our index is always valid
162 BaseHistogram& operator+=(const BaseHistogram& rhs)
164 assert(d_name == rhs.d_name);
165 assert(d_buckets.size() == rhs.d_buckets.size());
166 for (size_t bucket = 0; bucket < d_buckets.size(); ++bucket) {
167 assert(d_buckets[bucket].d_name == rhs.d_buckets[bucket].d_name);
168 assert(d_buckets[bucket].d_boundary == rhs.d_buckets[bucket].d_boundary);
169 d_buckets[bucket].d_count += rhs.d_buckets[bucket].d_count;
176 std::vector<B> d_buckets;
178 mutable SumType d_sum{0};
180 std::vector<uint64_t> to125(uint64_t start, int num)
182 std::vector<uint64_t> boundaries;
183 boundaries.reserve(num);
184 boundaries.emplace_back(start);
190 boundaries.push_back(2 * start);
194 boundaries.push_back(5 * start);
198 boundaries.push_back(10 * start);
205 using Histogram = BaseHistogram<Bucket, uint64_t>;
207 using AtomicHistogram = BaseHistogram<AtomicBucket, pdns::stat_t>;