GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/statistics.h
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 39 40 97.5%
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 364807 Counter() { atomic_init64(&counter_); }
30 4413765 void Inc() { atomic_inc64(&counter_); }
31 1739 void Dec() { atomic_dec64(&counter_); }
32 1958 int64_t Get() { return atomic_read64(&counter_); }
33 19489 void Set(const int64_t val) { atomic_write64(&counter_, val); }
34 52915 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 1659 inline void Dec(class Counter *counter) { counter->Dec(); }
50 4413725 inline void Inc(class Counter *counter) { counter->Inc(); }
51 52875 inline int64_t Xadd(class Counter *counter, const int64_t delta) {
52 52875 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 364727 explicit CounterInfo(const std::string &desc) : desc(desc) {
83 364727 atomic_init32(&refcnt);
84 364727 atomic_inc32(&refcnt);
85 364727 }
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 13956 StatisticsTemplate(const std::string &name_major, Statistics *statistics)
103 13956 : name_major_(name_major), statistics_(statistics) { }
104 5882 StatisticsTemplate(const std::string &name_sub,
105 const StatisticsTemplate &statistics)
106
1/2
✓ Branch 2 taken 5882 times.
✗ Branch 3 not taken.
5882 : name_major_(statistics.name_major_ + "." + name_sub)
107 5882 , statistics_(statistics.statistics_) { }
108
109 178404 Counter *RegisterTemplated(const std::string &name_minor,
110 const std::string &desc) {
111
2/4
✓ Branch 2 taken 178404 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 178404 times.
✗ Branch 6 not taken.
178404 return statistics_->Register(name_major_ + "." + name_minor, desc);
112 }
113
114 490 Counter *RegisterOrLookupTemplated(const std::string &name_minor,
115 const std::string &desc) {
116
2/4
✓ Branch 2 taken 490 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 490 times.
✗ Branch 6 not taken.
490 Counter *result = statistics_->Lookup(name_major_ + "." + name_minor);
117
1/2
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
490 if (result == NULL) {
118 490 return RegisterTemplated(name_minor, desc);
119 }
120 return result;
121 }
122
123 Statistics *statistics() { return statistics_; }
124
125 private:
126 std::string name_major_;
127 Statistics *statistics_;
128 };
129
130
131 struct FsCounters {
132 perf::Counter *n_files_added;
133 perf::Counter *n_files_removed;
134 perf::Counter *n_files_changed;
135 perf::Counter *n_directories_added;
136 perf::Counter *n_directories_removed;
137 perf::Counter *n_directories_changed;
138 perf::Counter *n_symlinks_added;
139 perf::Counter *n_symlinks_removed;
140 perf::Counter *n_symlinks_changed;
141 perf::Counter *sz_added_bytes;
142 perf::Counter *sz_removed_bytes;
143
144 98 explicit FsCounters(StatisticsTemplate statistics) {
145
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_files_added = statistics.RegisterTemplated("n_files_added",
146 "Number of files added");
147
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_files_removed = statistics.RegisterTemplated("n_files_removed",
148 "Number of files removed");
149
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_files_changed = statistics.RegisterTemplated("n_files_changed",
150 "Number of files changed");
151
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_directories_added = statistics.RegisterTemplated(
152 "n_directories_added", "Number of directories added");
153
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_directories_removed = statistics.RegisterTemplated(
154 "n_directories_removed", "Number of directories removed");
155
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_directories_changed = statistics.RegisterTemplated(
156 "n_directories_changed", "Number of directories changed");
157
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_symlinks_added = statistics.RegisterTemplated("n_symlinks_added",
158 "Number of symlinks added");
159
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_symlinks_removed = statistics.RegisterTemplated(
160 "n_symlinks_removed", "Number of symlinks removed");
161
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 n_symlinks_changed = statistics.RegisterTemplated(
162 "n_symlinks_changed", "Number of symlinks changed");
163
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 sz_added_bytes = statistics.RegisterTemplated("sz_added_bytes",
164 "Number of bytes added");
165
3/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
98 sz_removed_bytes = statistics.RegisterTemplated("sz_removed_bytes",
166 "Number of bytes removed");
167 98 }
168 }; // FsCounters
169
170
171 /**
172 * Keeps track of events over time. Can be used to query the number of events
173 * between now and a point in time in the past. The time range should be
174 * smaller than capacity_s seconds. Uses a monotonic clock. Not thread-safe.
175 */
176 class Recorder {
177 public:
178 Recorder(uint32_t resolution_s, uint32_t capacity_s);
179
180 void Tick();
181 void TickAt(uint64_t timestamp);
182 uint64_t GetNoTicks(uint32_t retrospect_s) const;
183
184 424 uint32_t capacity_s() const { return capacity_s_; }
185 uint32_t resolution_s() const { return resolution_s_; }
186
187 private:
188 /**
189 * Records number of ticks (events) per unit of resolution. A ring buffer.
190 * Entries older than capacity_s get overwritten by new events.
191 */
192 std::vector<uint32_t> bins_;
193
194 /**
195 * When the most recent tick occurred.
196 */
197 uint64_t last_timestamp_;
198
199 /**
200 * Time window in seconds that the recorder is supposed to remember.
201 */
202 uint32_t capacity_s_;
203
204 /**
205 * Size of the bins for the tick counters.
206 */
207 uint32_t resolution_s_;
208
209 /**
210 * Shorthand for bins_.size(), constant during lifetime of the recorder.
211 */
212 unsigned no_bins_;
213 };
214
215
216 /**
217 * Writes to multiple recorders. Recorders with coarsed-grained resolution and
218 * a large capacity are combined with precise recorders with shorter capacity.
219 * Preferred recorders should be added first because GetNoTicks will use the
220 * first recorder with a capacity >= retrospect_s (or the last recorder).
221 */
222 class MultiRecorder {
223 public:
224 void Tick();
225 void TickAt(uint64_t timestamp);
226 uint64_t GetNoTicks(uint32_t retrospect_s) const;
227
228 void AddRecorder(uint32_t resolution_s, uint32_t capacity_s);
229
230 private:
231 std::vector<Recorder> recorders_;
232 };
233
234 } // namespace perf
235
236 #ifdef CVMFS_NAMESPACE_GUARD
237 } // namespace CVMFS_NAMESPACE_GUARD
238 #endif
239
240 #endif // CVMFS_STATISTICS_H_
241