GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/tracer.cc
Date: 2025-11-30 02:35:17
Exec Total Coverage
Lines: 159 165 96.4%
Branches: 103 162 63.6%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "tracer.h"
7
8 #include <pthread.h>
9
10 #include <cassert>
11 #include <cerrno>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <string>
16
17 #include "util/atomic.h"
18 #include "util/concurrency.h"
19 #include "util/posix.h"
20 #include "util/string.h"
21
22 using namespace std; // NOLINT
23
24
25 644 void Tracer::Activate(const int buffer_size,
26 const int flush_threshold,
27 const string &trace_file) {
28 644 trace_file_ = trace_file;
29 644 buffer_size_ = buffer_size;
30 644 flush_threshold_ = flush_threshold;
31
3/6
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 644 times.
✗ Branch 5 not taken.
644 assert(buffer_size_ > 1 && flush_threshold_ >= 0
32 && flush_threshold_ < buffer_size_);
33
34
4/8
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 192924 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 192924 times.
✓ Branch 7 taken 644 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
193568 ring_buffer_ = new BufferEntry[buffer_size_];
35
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 commit_buffer_ = new atomic_int32[buffer_size_];
36
2/2
✓ Branch 0 taken 192924 times.
✓ Branch 1 taken 644 times.
193568 for (int i = 0; i < buffer_size_; i++)
37 192924 atomic_init32(&commit_buffer_[i]);
38
39 int retval;
40 644 retval = pthread_cond_init(&sig_continue_trace_, NULL);
41 644 retval |= pthread_mutex_init(&sig_continue_trace_mutex_, NULL);
42 644 retval |= pthread_cond_init(&sig_flush_, NULL);
43 644 retval |= pthread_mutex_init(&sig_flush_mutex_, NULL);
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
45
46 644 active_ = true;
47 644 }
48
49
50 /**
51 * Trace a message. This is usually a lock-free procedure that just
52 * requires two fetch_and_add operations and a gettimeofday syscall.
53 * There are two exceptions:
54 * -# If the ring buffer is full, the function blocks until the flush
55 * thread made some space. Avoid that by carefully choosing size
56 * and threshold.
57 * -# If this message reaches the threshold, the flush thread gets
58 * signaled.
59 *
60 * \param[in] event Arbitrary code, for consistency applications should use one
61 * of the TraceEvents constants. Negative codes are reserved
62 * for internal use.
63 * \param[in] id Arbitrary id, for example file name or module name which is
64 * doing the trace.
65 * \return The sequence number which was used to trace the record
66 */
67 15761256 int32_t Tracer::DoTrace(const int event,
68 const PathString &path,
69 const string &msg) {
70 15761256 const int32_t my_seq_no = atomic_xadd32(&seq_no_, 1);
71 timeval now;
72 16482812 gettimeofday(&now, NULL);
73 16405440 const int pos = my_seq_no % buffer_size_;
74
75
2/2
✓ Branch 1 taken 5360288 times.
✓ Branch 2 taken 16515978 times.
22027054 while (my_seq_no - atomic_read32(&flushed_) >= buffer_size_) {
76 timespec timeout;
77 int retval;
78 5360288 GetTimespecRel(25, &timeout);
79 5316220 retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
80
1/2
✓ Branch 1 taken 5720422 times.
✗ Branch 2 not taken.
5720422 retval |= pthread_cond_timedwait(&sig_continue_trace_,
81 &sig_continue_trace_mutex_, &timeout);
82 5720422 retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
83
2/4
✓ Branch 0 taken 5626536 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5626536 times.
5621614 assert(retval == ETIMEDOUT || retval == 0);
84 }
85
86 16515978 ring_buffer_[pos].time_stamp = now;
87 16515978 ring_buffer_[pos].code = event;
88
1/2
✓ Branch 1 taken 15883202 times.
✗ Branch 2 not taken.
16515978 ring_buffer_[pos].path = path;
89
1/2
✓ Branch 1 taken 16097010 times.
✗ Branch 2 not taken.
15883202 ring_buffer_[pos].msg = msg;
90 16097010 atomic_inc32(&commit_buffer_[pos]);
91
92
2/2
✓ Branch 1 taken 1706554 times.
✓ Branch 2 taken 14615120 times.
16519198 if (my_seq_no - atomic_read32(&flushed_) == flush_threshold_) {
93 1706554 const MutexLockGuard m(&sig_flush_mutex_);
94 const int err_code
95 1706600 __attribute__((unused)) = pthread_cond_signal(&sig_flush_);
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1706600 times.
1706600 assert(err_code == 0 && "Could not signal flush thread");
97 1706600 }
98
99 16317948 return my_seq_no;
100 }
101
102
103 66838 void Tracer::Flush() {
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66838 times.
66838 if (!active_)
105 return;
106
107
3/6
✓ Branch 2 taken 66838 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 67850 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 67758 times.
✗ Branch 9 not taken.
66838 const int32_t save_seq_no = DoTrace(kEventFlush, PathString("Tracer", 6),
108 "flushed ring buffer");
109
2/2
✓ Branch 1 taken 59064 times.
✓ Branch 2 taken 67574 times.
127328 while (atomic_read32(&flushed_) <= save_seq_no) {
110 timespec timeout;
111 int retval;
112
113 59064 atomic_cas32(&flush_immediately_, 0, 1);
114 {
115 59156 const MutexLockGuard m(&sig_flush_mutex_);
116 60122 retval = pthread_cond_signal(&sig_flush_);
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60122 times.
60122 assert(retval == 0);
118 60122 }
119
120 59984 GetTimespecRel(250, &timeout);
121 59846 retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
122
1/2
✓ Branch 1 taken 60122 times.
✗ Branch 2 not taken.
60122 retval |= pthread_cond_timedwait(&sig_continue_trace_,
123 &sig_continue_trace_mutex_, &timeout);
124 60122 retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
125
3/4
✓ Branch 0 taken 56488 times.
✓ Branch 1 taken 3036 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 56488 times.
59524 assert(retval == ETIMEDOUT || retval == 0);
126 }
127 }
128
129
130 6755054 void Tracer::GetTimespecRel(const int64_t ms, timespec *ts) {
131 timeval now;
132 6755054 gettimeofday(&now, NULL);
133 6734216 int64_t nsecs = now.tv_usec * 1000 + (ms % 1000) * 1000 * 1000;
134 6734216 int carry = 0;
135
2/2
✓ Branch 0 taken 60996 times.
✓ Branch 1 taken 6673220 times.
6734216 if (nsecs >= 1000 * 1000 * 1000) {
136 60996 carry = 1;
137 60996 nsecs -= 1000 * 1000 * 1000;
138 }
139 6734216 ts->tv_sec = now.tv_sec + ms / 1000 + carry;
140 6734216 ts->tv_nsec = nsecs;
141 6734216 }
142
143
144 644 void *Tracer::MainFlush(void *data) {
145 644 Tracer *tracer = reinterpret_cast<Tracer *>(data);
146 int retval;
147 644 const MutexLockGuard m(&tracer->sig_flush_mutex_);
148
1/2
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
644 FILE *f = fopen(tracer->trace_file_.c_str(), "a");
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(f != NULL && "Could not open trace file");
150 struct timespec timeout;
151
152 do {
153 4123118 while (
154 5540976 (atomic_read32(&tracer->terminate_flush_thread_) == 0)
155
2/2
✓ Branch 1 taken 5521932 times.
✓ Branch 2 taken 18400 times.
5540332 && (atomic_read32(&tracer->flush_immediately_) == 0)
156
4/4
✓ Branch 0 taken 5540332 times.
✓ Branch 1 taken 644 times.
✓ Branch 4 taken 1417858 times.
✓ Branch 5 taken 4123118 times.
16603240 && (atomic_read32(&tracer->seq_no_) - atomic_read32(&tracer->flushed_)
157
2/2
✓ Branch 0 taken 1417858 times.
✓ Branch 1 taken 4104074 times.
5521932 <= tracer->flush_threshold_)) {
158 1417858 tracer->GetTimespecRel(2000, &timeout);
159
1/2
✓ Branch 1 taken 1417858 times.
✗ Branch 2 not taken.
1417858 retval = pthread_cond_timedwait(&tracer->sig_flush_,
160 &tracer->sig_flush_mutex_, &timeout);
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1417858 times.
1417858 assert(retval != EINVAL);
162 }
163
164 4123118 const int base = atomic_read32(&tracer->flushed_) % tracer->buffer_size_;
165 4123118 int pos, i = 0;
166 4123118 while ((i <= tracer->flush_threshold_)
167
6/6
✓ Branch 0 taken 18725312 times.
✓ Branch 1 taken 2538740 times.
✓ Branch 2 taken 17140934 times.
✓ Branch 3 taken 1584378 times.
✓ Branch 4 taken 17140934 times.
✓ Branch 5 taken 4123118 times.
39989364 && (atomic_read32(
168 18725312 &tracer->commit_buffer_[pos = ((base + i)
169 18725312 % tracer->buffer_size_)])
170 == 1)) {
171 17140934 string tmp;
172
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 tmp = StringifyTimeval(tracer->ring_buffer_[pos].time_stamp);
173
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval = tracer->WriteCsvFile(f, tmp);
174
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval |= fputc(',', f) - ',';
175
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 tmp = StringifyInt(tracer->ring_buffer_[pos].code);
176
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval = tracer->WriteCsvFile(f, tmp);
177
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval |= fputc(',', f) - ',';
178
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval |= tracer->WriteCsvFile(f,
179
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
34281868 tracer->ring_buffer_[pos].path.ToString());
180
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval |= fputc(',', f) - ',';
181
1/2
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
17140934 retval |= tracer->WriteCsvFile(f, tracer->ring_buffer_[pos].msg);
182
2/4
✓ Branch 1 taken 17140934 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17140934 times.
✗ Branch 5 not taken.
17140934 retval |= (fputc(13, f) - 13) | (fputc(10, f) - 10);
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17140934 times.
17140934 assert(retval == 0);
184
185 17140934 atomic_dec32(&tracer->commit_buffer_[pos]);
186 17140934 ++i;
187 17140934 }
188
1/2
✓ Branch 1 taken 4123118 times.
✗ Branch 2 not taken.
4123118 retval = fflush(f);
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4123118 times.
4123118 assert(retval == 0);
190 4123118 atomic_xadd32(&tracer->flushed_, i);
191 4123118 atomic_cas32(&tracer->flush_immediately_, 1, 0);
192
193 {
194 4123118 const MutexLockGuard l(&tracer->sig_continue_trace_mutex_);
195 4123118 retval = pthread_cond_broadcast(&tracer->sig_continue_trace_);
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4123118 times.
4123118 assert(retval == 0);
197 4123118 }
198 } while (
199 4123118 (atomic_read32(&tracer->terminate_flush_thread_) == 0)
200
6/6
✓ Branch 0 taken 736 times.
✓ Branch 1 taken 4122382 times.
✓ Branch 4 taken 92 times.
✓ Branch 5 taken 644 times.
✓ Branch 6 taken 4122474 times.
✓ Branch 7 taken 644 times.
4123118 || (atomic_read32(&tracer->flushed_) < atomic_read32(&tracer->seq_no_)));
201
202
1/2
✓ Branch 1 taken 644 times.
✗ Branch 2 not taken.
644 retval = fclose(f);
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
204 644 return NULL;
205 644 }
206
207
208 690 void Tracer::Spawn() {
209
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 46 times.
690 if (active_) {
210 644 const int retval = pthread_create(&thread_flush_, NULL, MainFlush, this);
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
212
213 644 spawned_ = true;
214
3/6
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 644 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 644 times.
✗ Branch 9 not taken.
644 DoTrace(kEventStart, PathString("Tracer", 6), "Trace buffer created");
215 }
216 690 }
217
218
219 1035 Tracer::Tracer()
220 1035 : active_(false)
221 1035 , spawned_(false)
222 1035 , buffer_size_(0)
223 1035 , flush_threshold_(0)
224 1035 , ring_buffer_(NULL)
225 1035 , commit_buffer_(NULL) {
226 1035 memset(&thread_flush_, 0, sizeof(thread_flush_));
227 1035 atomic_init32(&seq_no_);
228 1035 atomic_init32(&flushed_);
229 1035 atomic_init32(&terminate_flush_thread_);
230 1035 atomic_init32(&flush_immediately_);
231 1035 }
232
233
234 1679 Tracer::~Tracer() {
235
2/2
✓ Branch 0 taken 391 times.
✓ Branch 1 taken 644 times.
1035 if (!active_)
236 391 return;
237 int retval;
238
239
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 if (spawned_) {
240 644 DoTrace(kEventStop, PathString("Tracer", 6), "Destroying trace buffer...");
241
242 // Trigger flushing and wait for it
243 644 atomic_inc32(&terminate_flush_thread_);
244 {
245 644 const MutexLockGuard m(&sig_flush_mutex_);
246 644 retval = pthread_cond_signal(&sig_flush_);
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
248 644 }
249 644 retval = pthread_join(thread_flush_, NULL);
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
251 }
252
253 644 retval = pthread_cond_destroy(&sig_continue_trace_);
254 644 retval |= pthread_mutex_destroy(&sig_continue_trace_mutex_);
255 644 retval |= pthread_cond_destroy(&sig_flush_);
256 644 retval |= pthread_mutex_destroy(&sig_flush_mutex_);
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
644 assert(retval == 0);
258
259
3/4
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192924 times.
✓ Branch 3 taken 644 times.
193568 delete[] ring_buffer_;
260
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 delete[] commit_buffer_;
261
2/2
✓ Branch 1 taken 644 times.
✓ Branch 2 taken 391 times.
1035 }
262
263
264 68563736 int Tracer::WriteCsvFile(FILE *fp, const string &field) {
265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68563736 times.
68563736 if (fp == NULL)
266 return 0;
267
268 int retval;
269
270
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68563736 times.
68563736 if ((retval = fputc('"', fp)) != '"')
271 return retval;
272
273
2/2
✓ Branch 1 taken 988516448 times.
✓ Branch 2 taken 68563736 times.
1057080184 for (unsigned i = 0, l = field.length(); i < l; ++i) {
274
2/2
✓ Branch 1 taken 12006000 times.
✓ Branch 2 taken 976510448 times.
988516448 if (field[i] == '"') {
275
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12006000 times.
12006000 if ((retval = fputc('"', fp)) != '"')
276 return retval;
277 }
278
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 988516448 times.
988516448 if ((retval = fputc(field[i], fp)) != field[i])
279 return retval;
280 }
281
282
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68563736 times.
68563736 if ((retval = fputc('"', fp)) != '"')
283 return retval;
284
285 68563736 return 0;
286 }
287