GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/algorithm.cc
Date: 2025-06-29 02:35:41
Exec Total Coverage
Lines: 54 163 33.1%
Branches: 17 158 10.8%

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