• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 18679017918

21 Oct 2025 09:15AM UTC coverage: 69.743% (+2.0%) from 67.713%
18679017918

Pull #16307

github

web-flow
Merge ba88af487 into da98764c6
Pull Request #16307: rec: explicit disabling/enabling of tls-gnutls for full and least configs and packages

26192 of 45526 branches covered (57.53%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

2282 existing lines in 57 files now uncovered.

86265 of 115719 relevant lines covered (74.55%)

4323875.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.54
/pdns/histogram.hh
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
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.
8
 *
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.
12
 *
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.
17
 *
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.
21
 */
22
#pragma once
23

24
#include <cassert>
25
#include <algorithm>
26
#include <limits>
27
#include <stdexcept>
28
#include <string>
29
#include <vector>
30

31
#include "stat_t.hh"
32

33
namespace pdns
34
{
35

36
// By convention, we are using microsecond units
37
struct Bucket
38
{
39
  Bucket(std::string name, uint64_t boundary, uint64_t val) :
UNCOV
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};
44

45
  Bucket(const Bucket&) = default;
46
  Bucket& operator=(const Bucket& rhs)
UNCOV
47
  {
×
UNCOV
48
    assert(d_name == rhs.d_name);
×
49
    assert(d_boundary == rhs.d_boundary);
×
50
    d_count = rhs.d_count;
×
UNCOV
51
    return *this;
×
UNCOV
52
  }
×
53
};
54

55
struct AtomicBucket
56
{
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) {}
94,335✔
61
  AtomicBucket(const AtomicBucket& rhs) :
UNCOV
62
    d_name(rhs.d_name), d_boundary(rhs.d_boundary), d_count(rhs.d_count.load()) {}
×
63

64
  const std::string d_name;
65
  const uint64_t d_boundary{0};
66
  mutable stat_t d_count{0};
67
};
68

69
template <class B, class SumType>
70
class BaseHistogram
71
{
72
public:
73
  BaseHistogram(const std::string& prefix, const std::vector<uint64_t>& boundaries) :
74
    d_name(prefix)
75
  {
285✔
76
    if (!std::is_sorted(boundaries.cbegin(), boundaries.cend())) {
285!
77
      throw std::invalid_argument("boundary array must be sorted");
×
78
    }
×
79
    if (boundaries.size() == 0) {
285!
80
      throw std::invalid_argument("boundary array must not be empty");
×
81
    }
×
82
    if (boundaries[0] == 0) {
285!
83
      throw std::invalid_argument("boundary array's first element should not be zero");
×
84
    }
×
85
    d_buckets.reserve(boundaries.size() + 1);
285✔
86
    uint64_t prev = 0;
285✔
87
    for (auto b : boundaries) {
94,050✔
88
      if (prev == b) {
94,050!
89
        throw std::invalid_argument("boundary array's elements should be distinct");
×
90
      }
×
91
      std::string str = prefix + "le-" + std::to_string(b);
94,050✔
92
      d_buckets.emplace_back(str, b, 0);
94,050✔
93
      prev = b;
94,050✔
94
    }
94,050✔
95

96
    // everything above last boundary
97
    d_buckets.emplace_back(prefix + "le-max", std::numeric_limits<uint64_t>::max(), 0);
285✔
98
  }
285✔
99

100
  BaseHistogram(const std::string& prefix, uint64_t start, int num) :
101
    BaseHistogram(prefix, to125(start, num))
102
  {
103
  }
104

105
  std::string getName() const
106
  {
107
    return d_name;
108
  }
109

110
  uint64_t getSum() const
111
  {
112
    return d_sum;
113
  }
114

115
  const std::vector<B>& getRawData() const
116
  {
4✔
117
    return d_buckets;
4✔
118
  }
4✔
119

120
  uint64_t getCount(size_t i) const
121
  {
122
    return d_buckets[i].d_count;
123
  }
124

125
  std::vector<B> getCumulativeBuckets() const
126
  {
127
    std::vector<B> ret;
128
    ret.reserve(d_buckets.size());
129
    uint64_t c{0};
130
    for (const auto& b : d_buckets) {
131
      c += b.d_count;
132
      ret.emplace_back(b.d_name, b.d_boundary, c);
133
    }
134
    return ret;
135
  }
136

137
  std::vector<uint64_t> getCumulativeCounts() const
138
  {
139
    std::vector<uint64_t> ret;
140
    ret.reserve(d_buckets.size());
141
    uint64_t c = 0;
142
    for (const auto& b : d_buckets) {
143
      c += b.d_count;
144
      ret.emplace_back(c);
145
    }
146
    return ret;
147
  }
148

149
  static bool lessOrEqual(uint64_t b, const B& bu)
150
  {
1,465,740✔
151
    return b <= bu.d_boundary;
1,465,740✔
152
  }
1,465,740✔
153

154
  inline void operator()(uint64_t d) const
155
  {
168,209✔
156
    auto index = std::upper_bound(d_buckets.begin(), d_buckets.end(), d, lessOrEqual);
168,209✔
157
    // our index is always valid
158
    ++index->d_count;
168,209✔
159
    d_sum += d;
168,209✔
160
  }
168,209✔
161

162
  BaseHistogram& operator+=(const BaseHistogram& rhs)
163
  {
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;
170
    }
171
    d_sum += rhs.d_sum;
172
    return *this;
173
  }
174

175
private:
176
  std::vector<B> d_buckets;
177
  std::string d_name;
178
  mutable SumType d_sum{0};
179

180
  std::vector<uint64_t> to125(uint64_t start, int num)
181
  {
182
    std::vector<uint64_t> boundaries;
183
    boundaries.reserve(num);
184
    boundaries.emplace_back(start);
185
    int i = 0;
186
    while (true) {
187
      if (++i >= num) {
188
        break;
189
      }
190
      boundaries.push_back(2 * start);
191
      if (++i >= num) {
192
        break;
193
      }
194
      boundaries.push_back(5 * start);
195
      if (++i >= num) {
196
        break;
197
      }
198
      boundaries.push_back(10 * start);
199
      start *= 10;
200
    }
201
    return boundaries;
202
  }
203
};
204

205
using Histogram = BaseHistogram<Bucket, uint64_t>;
206

207
using AtomicHistogram = BaseHistogram<AtomicBucket, pdns::stat_t>;
208

209
} // namespace pdns
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc