GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/algorithm.h
Date: 2025-07-21 10:50:29
Exec Total Coverage
Lines: 42 50 84.0%
Branches: 27 41 65.9%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_UTIL_ALGORITHM_H_
6 #define CVMFS_UTIL_ALGORITHM_H_
7
8 #include <sys/time.h>
9
10 #include <algorithm>
11 #include <cassert>
12 #include <cstddef>
13 #include <cstdint>
14 #include <string>
15 #include <utility>
16 #include <vector>
17
18 #include "util/atomic.h"
19 #include "util/export.h"
20 #include "util/murmur.hxx"
21 #include "util/platform.h"
22 #include "util/prng.h"
23 #include "util/single_copy.h"
24
25 #ifdef CVMFS_NAMESPACE_GUARD
26 namespace CVMFS_NAMESPACE_GUARD {
27 #endif
28
29
30 CVMFS_EXPORT double DiffTimeSeconds(struct timeval start, struct timeval end);
31
32 // Bitfield manipulation for different integer types T
33 template<typename T>
34 312 inline void SetBit(unsigned int bit, T *field) {
35 312 *field |= static_cast<T>(1) << bit;
36 312 }
37
38 template<typename T>
39 312 inline void ClearBit(unsigned int bit, T *field) {
40 312 *field &= ~(static_cast<T>(1) << bit);
41 312 }
42
43 template<typename T>
44 468 inline bool TestBit(unsigned int bit, const T field) {
45 468 return field & (static_cast<T>(1) << bit);
46 }
47
48
49 /**
50 * Knuth's random shuffle algorithm.
51 */
52 template<typename T>
53 219 std::vector<T> Shuffle(const std::vector<T> &input, Prng *prng) {
54 219 std::vector<T> shuffled(input);
55 219 unsigned N = shuffled.size();
56 // No shuffling for the last element
57
2/2
✓ Branch 0 taken 2450250 times.
✓ Branch 1 taken 125 times.
3396485 for (unsigned i = 0; i < N; ++i) {
58 3396266 const unsigned swap_idx = i + prng->Next(N - i);
59 3396266 std::swap(shuffled[i], shuffled[swap_idx]);
60 }
61 219 return shuffled;
62 }
63
64
65 /**
66 * Sorts the vector tractor and applies the same permutation to towed. Both
67 * vectors have to be of the same size. Type T must be sortable (< operator).
68 * Uses insertion sort (n^2), only efficient for small vectors.
69 */
70 template<typename T, typename U>
71 456 void SortTeam(std::vector<T> *tractor, std::vector<U> *towed) {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
456 assert(tractor);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
456 assert(towed);
74
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 456 times.
456 assert(tractor->size() == towed->size());
75 456 int N = tractor->size();
76
77 // Insertion sort on both, tractor and towed
78
3/4
✓ Branch 0 taken 3558 times.
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
4189 for (int i = 1; i < N; ++i) {
79
1/2
✓ Branch 2 taken 3558 times.
✗ Branch 3 not taken.
3733 T val_tractor = (*tractor)[i];
80
1/2
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
3733 U val_towed = (*towed)[i];
81 int pos;
82
7/7
✓ Branch 0 taken 44932 times.
✓ Branch 1 taken 193 times.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 41392 times.
✓ Branch 5 taken 3540 times.
✓ Branch 6 taken 41462 times.
✓ Branch 7 taken 3558 times.
45125 for (pos = i - 1; (pos >= 0) && ((*tractor)[pos] > val_tractor); --pos) {
83
1/2
✓ Branch 3 taken 41287 times.
✗ Branch 4 not taken.
41392 (*tractor)[pos + 1] = (*tractor)[pos];
84
1/2
✓ Branch 3 taken 105 times.
✗ Branch 4 not taken.
41392 (*towed)[pos + 1] = (*towed)[pos];
85 }
86
1/2
✓ Branch 2 taken 3558 times.
✗ Branch 3 not taken.
3733 (*tractor)[pos + 1] = val_tractor;
87
1/2
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
3733 (*towed)[pos + 1] = val_towed;
88 }
89 456 }
90
91
92 template<typename hashed_type>
93 struct hash_murmur {
94 size_t operator()(const hashed_type key) const {
95 #ifdef __x86_64__
96 return MurmurHash64A(&key, sizeof(key), 0x9ce603115bba659bLLU);
97 #else
98 return MurmurHash2(&key, sizeof(key), 0x07387a4f);
99 #endif
100 }
101 };
102
103
104 /**
105 * Very simple StopWatch implementation. Currently the implementation does not
106 * allow a restart of a stopped watch. You should always reset the clock before
107 * you reuse it.
108 *
109 * Stopwatch watch();
110 * watch.Start();
111 * // do nasty thing
112 * watch.Stop();
113 * printf("%f", watch.GetTime());
114 */
115 class CVMFS_EXPORT StopWatch : SingleCopy {
116 public:
117 79 StopWatch() : running_(false) { }
118
119 void Start();
120 void Stop();
121 void Reset();
122
123 double GetTime() const;
124
125 private:
126 bool running_;
127 timeval start_, end_;
128 };
129
130
131 /**
132 * Log2Histogram is a simple implementation of
133 * log2 histogram data structure which stores
134 * and prints log2 histogram. It is used for
135 * getting and printing latency metrics of
136 * CVMFS fuse calls.
137 *
138 * Log2Histogram hist(2);
139 * hist.Add(1);
140 * hist.Add(2);
141 * hist.PrintLog2Histogram();
142 */
143
144 class CVMFS_EXPORT Log2Histogram {
145 friend class UTLog2Histogram;
146
147 public:
148 explicit Log2Histogram(unsigned int nbins);
149
150 31457940 void Add(uint64_t value) {
151 unsigned int i;
152 31457940 const unsigned int n = this->bins_.size() - 1;
153
154
2/2
✓ Branch 0 taken 471852750 times.
✓ Branch 1 taken 150 times.
471852900 for (i = 1; i <= n; i++) {
155
2/2
✓ Branch 1 taken 31457790 times.
✓ Branch 2 taken 440394960 times.
471852750 if (value < this->boundary_values_[i]) {
156 31457790 atomic_inc32(&(this->bins_[i]));
157 31457790 return;
158 }
159 }
160
161 150 atomic_inc32(&(this->bins_[0])); // add to overflow bin.
162 }
163
164 /**
165 * Returns the total number of elements in the histogram
166 */
167 390 inline uint64_t N() {
168 390 uint64_t n = 0;
169 unsigned int i;
170
2/2
✓ Branch 1 taken 6570 times.
✓ Branch 2 taken 390 times.
6960 for (i = 0; i <= this->bins_.size() - 1; i++) {
171 6570 n += static_cast<unsigned int>(atomic_read32(&(this->bins_[i])));
172 }
173 390 return n;
174 }
175
176 /**
177 * compute the quantile of order n
178 */
179 unsigned int GetQuantile(float n);
180
181 std::string ToString();
182
183 void PrintLog2Histogram();
184
185 private:
186 std::vector<atomic_int32> bins_;
187 // boundary_values_ handle the largest value a certain
188 // bin can store in itself.
189 std::vector<unsigned int> boundary_values_;
190 };
191
192 /**
193 * UTLog2Histogram class is a helper for the unit tests
194 * to extract internals from Log2Histogram.
195 */
196 class CVMFS_EXPORT UTLog2Histogram {
197 public:
198 std::vector<atomic_int32> GetBins(const Log2Histogram &h);
199 };
200
201
202 class CVMFS_EXPORT HighPrecisionTimer : SingleCopy {
203 public:
204 static bool g_is_enabled; // false by default
205
206 explicit HighPrecisionTimer(Log2Histogram *recorder)
207 : timestamp_start_(g_is_enabled ? platform_monotonic_time_ns() : 0)
208 , recorder_(recorder) { }
209
210 ~HighPrecisionTimer() {
211 if (g_is_enabled)
212 recorder_->Add(platform_monotonic_time_ns() - timestamp_start_);
213 }
214
215 private:
216 uint64_t timestamp_start_;
217 Log2Histogram *recorder_;
218 };
219
220 #ifdef CVMFS_NAMESPACE_GUARD
221 } // namespace CVMFS_NAMESPACE_GUARD
222 #endif
223
224 #endif // CVMFS_UTIL_ALGORITHM_H_
225