GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/statistics.h
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 43 44 97.7%
Branches: 39 78 50.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_STATISTICS_H_
6 #define CVMFS_STATISTICS_H_
7
8 #include <pthread.h>
9 #include <stdint.h>
10
11 #include <map>
12 #include <string>
13 #include <vector>
14
15 #include "util/atomic.h"
16
17 #ifdef CVMFS_NAMESPACE_GUARD
18 namespace CVMFS_NAMESPACE_GUARD {
19 #endif
20
21
22 namespace perf {
23
24 /**
25 * A wrapper around an atomic 64bit signed integer.
26 */
27 class Counter {
28 public:
29 8247 Counter() { atomic_init64(&counter_); }
30 98009 void Inc() { atomic_inc64(&counter_); }
31 39 void Dec() { atomic_dec64(&counter_); }
32 61 int64_t Get() { return atomic_read64(&counter_); }
33 460 void Set(const int64_t val) { atomic_write64(&counter_, val); }
34 1266 int64_t Xadd(const int64_t delta) { return atomic_xadd64(&counter_, delta); }
35
36 std::string Print();
37 std::string PrintK();
38 std::string PrintKi();
39 std::string PrintM();
40 std::string PrintMi();
41 std::string PrintRatio(Counter divider);
42 std::string ToString();
43
44 private:
45 atomic_int64 counter_;
46 };
47
48 // perf::Func(Counter) is more clear to read in the code
49 37 inline void Dec(class Counter *counter) { counter->Dec(); }
50 98008 inline void Inc(class Counter *counter) { counter->Inc(); }
51 1265 inline int64_t Xadd(class Counter *counter, const int64_t delta) {
52 1265 return counter->Xadd(delta);
53 }
54
55
56 /**
57 * A collection of Counter objects with a name and a description. Counters in
58 * a Statistics class have a name and a description. Thread-safe.
59 */
60 class Statistics {
61 public:
62 enum PrintOptions {
63 kPrintSimple = 0,
64 kPrintHeader
65 };
66
67 Statistics();
68 ~Statistics();
69 Statistics *Fork();
70 Counter *Register(const std::string &name, const std::string &desc);
71 Counter *Lookup(const std::string &name) const;
72 std::string LookupDesc(const std::string &name);
73 std::string PrintList(const PrintOptions print_options);
74 std::string PrintJSON();
75 void SnapshotCounters(std::map<std::string, int64_t> *counters,
76 uint64_t *timestamp_ns);
77
78 private:
79 Statistics(const Statistics &other);
80 Statistics& operator=(const Statistics &other);
81 struct CounterInfo {
82 8245 explicit CounterInfo(const std::string &desc) : desc(desc) {
83 8245 atomic_init32(&refcnt);
84 8245 atomic_inc32(&refcnt);
85 8245 }
86 atomic_int32 refcnt;
87 Counter counter;
88 std::string desc;
89 };
90 std::map<std::string, CounterInfo *> counters_;
91 mutable pthread_mutex_t *lock_;
92 };
93
94
95 /**
96 * Allows multiple instance of the same class to use the same Statistics
97 * instance. The "name_major" part is used to construct counter names in the
98 * form name_major.<provided name>
99 */
100 class StatisticsTemplate {
101 public:
102 347 StatisticsTemplate(const std::string &name_major, Statistics *statistics)
103 347 : name_major_(name_major), statistics_(statistics)
104 347 { }
105 122 StatisticsTemplate(const std::string &name_sub,
106 const StatisticsTemplate &statistics)
107
1/2
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
122 : name_major_(statistics.name_major_ + "." + name_sub)
108 122 , statistics_(statistics.statistics_)
109 122 { }
110
111 3875 Counter *RegisterTemplated(const std::string &name_minor,
112 const std::string &desc)
113 {
114
2/4
✓ Branch 2 taken 3875 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3875 times.
✗ Branch 6 not taken.
3875 return statistics_->Register(name_major_ + "." + name_minor, desc);
115 }
116
117 10 Counter *RegisterOrLookupTemplated(const std::string &name_minor,
118 const std::string &desc)
119 {
120
2/4
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
10 Counter *result = statistics_->Lookup(name_major_ + "." + name_minor);
121
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (result == NULL) {
122 10 return RegisterTemplated(name_minor, desc);
123 }
124 return result;
125 }
126
127 Statistics *statistics() { return statistics_; }
128
129 private:
130 std::string name_major_;
131 Statistics *statistics_;
132 };
133
134
135 struct FsCounters {
136 perf::Counter *n_files_added;
137 perf::Counter *n_files_removed;
138 perf::Counter *n_files_changed;
139 perf::Counter *n_directories_added;
140 perf::Counter *n_directories_removed;
141 perf::Counter *n_directories_changed;
142 perf::Counter *n_symlinks_added;
143 perf::Counter *n_symlinks_removed;
144 perf::Counter *n_symlinks_changed;
145 perf::Counter *sz_added_bytes;
146 perf::Counter *sz_removed_bytes;
147
148 2 explicit FsCounters(StatisticsTemplate statistics) {
149
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_files_added = statistics.RegisterTemplated("n_files_added",
150 "Number of files added");
151
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_files_removed = statistics.RegisterTemplated("n_files_removed",
152 "Number of files removed");
153
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_files_changed = statistics.RegisterTemplated("n_files_changed",
154 "Number of files changed");
155
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_directories_added = statistics.RegisterTemplated("n_directories_added",
156 "Number of directories added");
157 2 n_directories_removed =
158
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 statistics.RegisterTemplated("n_directories_removed",
159 "Number of directories removed");
160 2 n_directories_changed =
161
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 statistics.RegisterTemplated("n_directories_changed",
162 "Number of directories changed");
163
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_symlinks_added = statistics.RegisterTemplated("n_symlinks_added",
164 "Number of symlinks added");
165
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_symlinks_removed = statistics.RegisterTemplated("n_symlinks_removed",
166 "Number of symlinks removed");
167
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 n_symlinks_changed = statistics.RegisterTemplated("n_symlinks_changed",
168 "Number of symlinks changed");
169
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 sz_added_bytes = statistics.RegisterTemplated("sz_added_bytes",
170 "Number of bytes added");
171
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 sz_removed_bytes = statistics.RegisterTemplated("sz_removed_bytes",
172 "Number of bytes removed");
173 2 }
174 }; // FsCounters
175
176
177 /**
178 * Keeps track of events over time. Can be used to query the number of events
179 * between now and a point in time in the past. The time range should be
180 * smaller than capacity_s seconds. Uses a monotonic clock. Not thread-safe.
181 */
182 class Recorder {
183 public:
184 Recorder(uint32_t resolution_s, uint32_t capacity_s);
185
186 void Tick();
187 void TickAt(uint64_t timestamp);
188 uint64_t GetNoTicks(uint32_t retrospect_s) const;
189
190 13 uint32_t capacity_s() const { return capacity_s_; }
191 uint32_t resolution_s() const { return resolution_s_; }
192
193 private:
194 /**
195 * Records number of ticks (events) per unit of resolution. A ring buffer.
196 * Entries older than capacity_s get overwritten by new events.
197 */
198 std::vector<uint32_t> bins_;
199
200 /**
201 * When the most recent tick occurred.
202 */
203 uint64_t last_timestamp_;
204
205 /**
206 * Time window in seconds that the recorder is supposed to remember.
207 */
208 uint32_t capacity_s_;
209
210 /**
211 * Size of the bins for the tick counters.
212 */
213 uint32_t resolution_s_;
214
215 /**
216 * Shorthand for bins_.size(), constant during lifetime of the recorder.
217 */
218 unsigned no_bins_;
219 };
220
221
222 /**
223 * Writes to multiple recorders. Recorders with coarsed-grained resolution and
224 * a large capacity are combined with precise recorders with shorter capacity.
225 * Preferred recorders should be added first because GetNoTicks will use the
226 * first recorder with a capacity >= retrospect_s (or the last recorder).
227 */
228 class MultiRecorder {
229 public:
230 void Tick();
231 void TickAt(uint64_t timestamp);
232 uint64_t GetNoTicks(uint32_t retrospect_s) const;
233
234 void AddRecorder(uint32_t resolution_s, uint32_t capacity_s);
235
236 private:
237 std::vector<Recorder> recorders_;
238 };
239
240 } // namespace perf
241
242 #ifdef CVMFS_NAMESPACE_GUARD
243 } // namespace CVMFS_NAMESPACE_GUARD
244 #endif
245
246 #endif // CVMFS_STATISTICS_H_
247