GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/algorithm.cc
Date: 2026-10-25 02:40:14
Exec Total Coverage
Lines: 57 164 34.8%
Branches: 21 164 12.8%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Some common functions.
5 */
6
7 #include "util/algorithm.h"
8
9 #include <sys/time.h>
10
11 #include <algorithm>
12 #include <atomic>
13 #include <cassert>
14 #include <cmath>
15 #include <cstdint>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include "util/string.h"
24
25
26 #ifdef CVMFS_NAMESPACE_GUARD
27 namespace CVMFS_NAMESPACE_GUARD {
28 #endif
29
30 bool HighPrecisionTimer::g_is_enabled = false;
31
32
33 131 double DiffTimeSeconds(struct timeval start, struct timeval end) {
34 // Time subtraction, from GCC documentation
35
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 93 times.
131 if (end.tv_usec < start.tv_usec) {
36 38 const int64_t nsec = (end.tv_usec - start.tv_usec) / 1000000 + 1;
37 38 start.tv_usec -= 1000000 * nsec;
38 38 start.tv_sec += nsec;
39 }
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (end.tv_usec - start.tv_usec > 1000000) {
41 ✗ const int64_t nsec = (end.tv_usec - start.tv_usec) / 1000000;
42 ✗ start.tv_usec += 1000000 * nsec;
43 ✗ start.tv_sec -= nsec;
44 }
45
46 // Compute the time remaining to wait in microseconds.
47 // tv_usec is certainly positive.
48 131 const uint64_t elapsed_usec = ((end.tv_sec - start.tv_sec) * 1000000)
49 131 + (end.tv_usec - start.tv_usec);
50 131 return static_cast<double>(elapsed_usec) / 1000000.0;
51 }
52
53
54 40 void StopWatch::Start() {
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 assert(!running_);
56
57 40 gettimeofday(&start_, NULL);
58 40 running_ = true;
59 40 }
60
61
62 39 void StopWatch::Stop() {
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 assert(running_);
64
65 39 gettimeofday(&end_, NULL);
66 39 running_ = false;
67 39 }
68
69
70 19 void StopWatch::Reset() {
71 19 start_ = timeval();
72 19 end_ = timeval();
73 19 running_ = false;
74 19 }
75
76
77 77 double StopWatch::GetTime() const {
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 assert(!running_);
79
80 77 return DiffTimeSeconds(start_, end_);
81 }
82
83 namespace {
84
85 ✗ static unsigned int CountDigits(uint64_t n) {
86 ✗ if (n == 0) {
87 ✗ return 1;
88 }
89 ✗ return static_cast<unsigned int>(floor(log10(static_cast<double>(n)))) + 1;
90 }
91
92 ✗ static std::string GenerateStars(unsigned int n) { return std::string(n, '*'); }
93
94 } // anonymous namespace
95
96 30312 Log2Histogram::Log2Histogram(unsigned int nbins) {
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30312 times.
30312 assert(nbins != 0);
98
1/2
✓ Branch 1 taken 30312 times.
✗ Branch 2 not taken.
30312 this->bins_.reserve(nbins + 1); // +1 for overflow bin.
99
1/2
✓ Branch 1 taken 30312 times.
✗ Branch 2 not taken.
30312 this->boundary_values_.assign(nbins + 1, 0); // +1 to avoid big if statement
100
101
2/2
✓ Branch 0 taken 938712 times.
✓ Branch 1 taken 30312 times.
969024 for (size_t i = 0; i <= nbins; ++i) {
102
1/2
✓ Branch 1 taken 938712 times.
✗ Branch 2 not taken.
938712 bins_.emplace_back(
103
1/2
✓ Branch 1 taken 938712 times.
✗ Branch 2 not taken.
1877424 std::unique_ptr<std::atomic<int32_t> >(new std::atomic<int32_t>(0)));
104 }
105
106 unsigned int i;
107
2/2
✓ Branch 0 taken 908400 times.
✓ Branch 1 taken 30312 times.
938712 for (i = 1; i <= nbins; i++) {
108 908400 this->boundary_values_[i] = (1 << ((i - 1) + 1));
109 }
110 30312 }
111
112 const std::vector<std::unique_ptr<std::atomic<int32_t> > > &
113 30 UTLog2Histogram::GetBins(const Log2Histogram &h) {
114 30 return h.bins_;
115 }
116
117 130 unsigned int Log2Histogram::GetQuantile(float n) {
118 130 const uint64_t total = this->N();
119 // pivot is the index of the element corresponding to the requested quantile
120 130 uint64_t pivot = static_cast<uint64_t>(static_cast<float>(total) * n);
121 130 float normalized_pivot = 0.0;
122 // now we iterate through all the bins
123 // note that we _exclude_ the overflow bin
124 130 unsigned int i = 0;
125
2/2
✓ Branch 1 taken 1880 times.
✓ Branch 2 taken 10 times.
1890 for (i = 1; i <= this->bins_.size() - 1; i++) {
126 const unsigned int bin_value = static_cast<unsigned int>(
127 1880 (this->bins_[i]->load()));
128
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 1760 times.
1880 if (pivot <= bin_value) {
129 120 normalized_pivot = static_cast<float>(pivot)
130 120 / static_cast<float>(bin_value);
131 120 break;
132 }
133 1760 pivot -= bin_value;
134 }
135
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 120 times.
130 if (i >= this->bins_.size()) {
136 10 return this->boundary_values_[this->bins_.size() - 1];
137 }
138 // now i stores the index of the bin corresponding to the requested quantile
139 // and normalized_pivot is the element we want inside the bin
140 120 const unsigned int min_value = this->boundary_values_[i - 1];
141 120 const unsigned int max_value = this->boundary_values_[i];
142 // and we return the linear interpolation
143 return min_value
144 120 + static_cast<unsigned int>(static_cast<float>(max_value - min_value)
145 120 * normalized_pivot);
146 }
147
148 ✗ std::string Log2Histogram::ToString() {
149 ✗ unsigned int i = 0;
150
151 ✗ unsigned int max_left_boundary_count = 1;
152 ✗ unsigned int max_right_boundary_count = 1;
153 ✗ unsigned int max_value_count = 1;
154 ✗ unsigned int max_stars = 0;
155 ✗ unsigned int max_bins = 0;
156 ✗ const unsigned int total_stars = 38;
157 ✗ uint64_t total_sum_of_bins = 0;
158
159 ✗ for (i = 1; i <= this->bins_.size() - 1; i++) {
160 ✗ max_left_boundary_count = std::max(max_left_boundary_count,
161 ✗ CountDigits(boundary_values_[i] / 2));
162 ✗ max_right_boundary_count = std::max(max_right_boundary_count,
163 ✗ CountDigits(boundary_values_[i] - 1));
164 ✗ max_value_count = std::max(max_value_count,
165 ✗ CountDigits((this->bins_[i]->load())));
166 ✗ max_bins = std::max(max_bins,
167 ✗ static_cast<unsigned int>((this->bins_[i]->load())));
168 ✗ total_sum_of_bins += static_cast<unsigned int>((this->bins_[i]->load()));
169 }
170
171 ✗ max_bins = std::max(max_bins,
172 ✗ static_cast<unsigned int>((this->bins_[0]->load())));
173 ✗ total_sum_of_bins += static_cast<unsigned int>((this->bins_[0]->load()));
174
175 ✗ if (total_sum_of_bins != 0) {
176 ✗ max_stars = max_bins * total_stars / total_sum_of_bins;
177 }
178
179 const std::string format = " %"
180 ✗ + StringifyUint(max_left_boundary_count < 2
181 ✗ ? 2
182 : max_left_boundary_count)
183 ✗ + "d -> %"
184 ✗ + StringifyUint(max_right_boundary_count)
185 ✗ + "d : %" + StringifyUint(max_value_count)
186 ✗ + "d | %"
187 ✗ + StringifyUint(max_stars < 12 ? 12 : max_stars)
188 ✗ + "s |\n";
189
190 const std::string title_format = " %"
191 ✗ + StringifyUint(
192 (max_left_boundary_count < 2
193 ✗ ? 2
194 : max_left_boundary_count)
195 ✗ + max_right_boundary_count + 4)
196 ✗ + "s | %"
197 ✗ + StringifyUint(max_value_count + 4)
198 ✗ + "s | %"
199 ✗ + StringifyUint(max_stars < 12 ? 12
200 : max_stars)
201 ✗ + "s |\n";
202
203 const std::string overflow_format = "%"
204 ✗ + StringifyUint(max_left_boundary_count
205 ✗ + max_right_boundary_count
206 ✗ + 5)
207 ✗ + "s : %"
208 ✗ + StringifyUint(max_value_count + 4)
209 ✗ + "d | %"
210 ✗ + StringifyUint(
211 ✗ max_stars < 12 ? 12 : max_stars)
212 ✗ + "s |\n";
213
214 const std::string total_format = "%"
215 ✗ + StringifyUint(
216 max_left_boundary_count
217 ✗ + max_right_boundary_count
218 ✗ + 5
219 < 8
220 ✗ ? 8
221 : max_left_boundary_count
222 + max_right_boundary_count + 5)
223 ✗ + "s : %"
224 ✗ + StringifyUint(max_value_count + 4)
225 ✗ + "lld\n";
226
227 ✗ std::string result_string = "";
228
229 ✗ const unsigned int kBufSize = 300;
230 char buffer[kBufSize];
231 ✗ memset(buffer, 0, sizeof(buffer));
232
233 ✗ snprintf(buffer, kBufSize, title_format.c_str(), "nsec", "count",
234 "distribution");
235 ✗ result_string += buffer;
236 ✗ memset(buffer, 0, sizeof(buffer));
237
238 ✗ for (i = 1; i <= this->bins_.size() - 1; i++) {
239 ✗ unsigned int n_of_stars = 0;
240 ✗ if (total_sum_of_bins != 0) {
241 ✗ n_of_stars = static_cast<unsigned int>((this->bins_[i]->load()))
242 ✗ * total_stars / total_sum_of_bins;
243 }
244
245 ✗ snprintf(buffer,
246 kBufSize,
247 format.c_str(),
248 ✗ boundary_values_[i - 1],
249 ✗ boundary_values_[i] - 1,
250 ✗ static_cast<unsigned int>(this->bins_[i]->load()),
251 ✗ GenerateStars(n_of_stars).c_str());
252 ✗ result_string += buffer;
253 ✗ memset(buffer, 0, sizeof(buffer));
254 }
255
256 ✗ unsigned int n_of_stars = 0;
257 ✗ if (total_sum_of_bins != 0) {
258 ✗ n_of_stars = static_cast<unsigned int>((this->bins_[0]->load()))
259 ✗ * total_stars / total_sum_of_bins;
260 }
261
262 ✗ snprintf(buffer,
263 kBufSize,
264 overflow_format.c_str(),
265 "overflow",
266 ✗ static_cast<unsigned int>((this->bins_[0]->load())),
267 ✗ GenerateStars(n_of_stars).c_str());
268 ✗ result_string += buffer;
269 ✗ memset(buffer, 0, sizeof(buffer));
270
271 ✗ snprintf(buffer, kBufSize, total_format.c_str(), "total", total_sum_of_bins);
272 ✗ result_string += buffer;
273 ✗ memset(buffer, 0, sizeof(buffer));
274
275 const float qs[15] = {.1, .2, .25, .3, .4, .5, .6, .7,
276 .75, .8, .9, .95, .99, .995, .999};
277 ✗ snprintf(buffer, kBufSize,
278 "\n\nQuantiles\n"
279 "%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,%0.4f,"
280 "%0.4f,%0.4f,%0.4f,%0.4f\n"
281 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n"
282 "End Quantiles"
283 "\n-----------------------\n",
284 ✗ qs[0], qs[1], qs[2], qs[3], qs[4], qs[5], qs[6], qs[7], qs[8], qs[9],
285 ✗ qs[10], qs[11], qs[12], qs[13], qs[14], GetQuantile(qs[0]),
286 ✗ GetQuantile(qs[1]), GetQuantile(qs[2]), GetQuantile(qs[3]),
287 ✗ GetQuantile(qs[4]), GetQuantile(qs[5]), GetQuantile(qs[6]),
288 ✗ GetQuantile(qs[7]), GetQuantile(qs[8]), GetQuantile(qs[9]),
289 ✗ GetQuantile(qs[10]), GetQuantile(qs[11]), GetQuantile(qs[12]),
290 ✗ GetQuantile(qs[13]), GetQuantile(qs[14]));
291
292 ✗ result_string += buffer;
293 ✗ memset(buffer, 0, sizeof(buffer));
294
295 ✗ return result_string;
296 }
297
298 ✗ void Log2Histogram::PrintLog2Histogram() {
299 ✗ printf("%s", this->ToString().c_str());
300 }
301
302 #ifdef CVMFS_NAMESPACE_GUARD
303 } // namespace CVMFS_NAMESPACE_GUARD
304 #endif
305
306