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