14
14
#include "xcapture.skel.h"
15
15
#include <syscall_names.h>
16
16
17
+ // global, set once during startup arg checking
18
+ bool output_csv = false;
19
+
17
20
18
21
// handle CTRL+C and sigpipe etc
19
22
static volatile bool exiting = false;
@@ -72,8 +75,9 @@ static const char *safe_syscall_name(__s32 syscall_nr)
72
75
73
76
74
77
// ns is signed as sometimes there's small negative durations reported due to
75
- // concurrency of BPF task iterator vs event capture probes running on different CPUs
76
- struct timespec subtract_ns_from_timespec (struct timespec ts , __s64 ns ) {
78
+ // concurrency of BPF task iterator vs event capture probes running on different CPUs (?)
79
+ struct timespec subtract_ns_from_timespec (struct timespec ts , __s64 ns )
80
+ {
77
81
struct timespec result = ts ;
78
82
79
83
if (result .tv_nsec < (long )(ns % 1000000000 )) {
@@ -87,12 +91,44 @@ struct timespec subtract_ns_from_timespec(struct timespec ts, __s64 ns) {
87
91
return result ;
88
92
}
89
93
94
+ // handle ringbuf completion events, don't bother trying to format
95
+ // wallclock time as these are ktime timestamps
96
+ static int handle_event (void * ctx , void * data , size_t data_sz )
97
+ {
98
+ const struct sc_completion_event * e = data ;
99
+
100
+ // Calculate duration in microseconds
101
+ __u64 duration_us = (e -> completed_sc_exit_time - e -> completed_sc_enter_time ) / 1000 ;
102
+
103
+ if (output_csv ) {
104
+ printf ("SC_END,%d,%d,%d,%llu,%llu,%llu,%llu\n" ,
105
+ e -> pid ,
106
+ e -> tgid ,
107
+ e -> completed_syscall_nr ,
108
+ e -> completed_sc_sequence_nr ,
109
+ e -> completed_sc_enter_time ,
110
+ e -> completed_sc_exit_time ,
111
+ duration_us );
112
+ } else {
113
+ printf ("SC_END %7d %7d %-20s %12llu %26llu %26llu %'16llu\n" ,
114
+ e -> pid ,
115
+ e -> tgid ,
116
+ safe_syscall_name (e -> completed_syscall_nr ),
117
+ e -> completed_sc_sequence_nr ,
118
+ e -> completed_sc_enter_time ,
119
+ e -> completed_sc_exit_time ,
120
+ duration_us );
121
+ }
122
+
123
+ return 0 ;
124
+ }
125
+
126
+
90
127
91
128
int main (int argc , char * * argv )
92
129
{
93
130
// super simple check to avoid proper argument handling for now
94
131
// if any args are given to xcapture, output CSV
95
- bool output_csv = false;
96
132
if (argc > 1 )
97
133
output_csv = true;
98
134
@@ -124,6 +160,16 @@ int main(int argc, char **argv)
124
160
goto cleanup ;
125
161
}
126
162
163
+
164
+ /* Set up ring buffer polling */
165
+ struct ring_buffer * rb = NULL ;
166
+ rb = ring_buffer__new (bpf_map__fd (skel -> maps .completion_events ), handle_event , NULL , NULL );
167
+ if (!rb ) {
168
+ fprintf (stderr , "Failed to create ring buffer\n" );
169
+ goto cleanup ;
170
+ }
171
+
172
+
127
173
struct timespec sample_ts ; // sample timestamp
128
174
char timestamp [64 ];
129
175
@@ -143,13 +189,13 @@ int main(int argc, char **argv)
143
189
// Print output (kernel pid printed as TID in userspace and kernel tgid as PID)
144
190
if (output_csv ) {
145
191
if (!header_printed ) {
146
- printf ("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" ,
147
- "TIMESTAMP" , "TID" , "TGID" , "STATE" , "USER" , "EXE" , "COMM" ,
192
+ printf ("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s \n" ,
193
+ "TYPE" , " TIMESTAMP" , "TID" , "TGID" , "STATE" , "USER" , "EXE" , "COMM" ,
148
194
"SYSCALL_PASSIVE" , "SYSCALL_ACTIVE" , "SC_ENTRY_TIME" , "SC_US_SO_FAR" , "SC_SEQ_NUM" , "ARG0" , "FILENAME" );
149
195
}
150
196
} else {
151
- printf ("%-26s %7s %7s %-6s %-16s %-20s %-16s %-20s %-20s %-26s %16s %12s %-16s %s\n" ,
152
- "TIMESTAMP" , "TID" , "TGID" , "STATE" , "USER" , "EXE" , "COMM" ,
197
+ printf ("%-6s %- 26s %7s %7s %-6s %-16s %-20s %-16s %-20s %-20s %-26s %16s %12s %-16s %s\n" ,
198
+ "TYPE" , " TIMESTAMP" , "TID" , "TGID" , "STATE" , "USER" , "EXE" , "COMM" ,
153
199
"SYSCALL_PASSIVE" , "SYSCALL_ACTIVE" , "SC_ENTRY_TIME" , "SC_US_SO_FAR" , "SC_SEQ_NUM" , "ARG0" , "FILENAME" );
154
200
}
155
201
@@ -174,6 +220,7 @@ int main(int argc, char **argv)
174
220
if (ret == 0 )
175
221
break ;
176
222
223
+
177
224
__s64 duration_ns = 0 ; // event duration so far, from its start to sampling point
178
225
if (buf .storage .sc_enter_time )
179
226
duration_ns = buf .storage .sample_ktime - buf .storage .sc_enter_time ;
@@ -188,7 +235,8 @@ int main(int argc, char **argv)
188
235
snprintf (sc_start_time_str + 19 , sizeof (sc_start_time_str ) - 19 , ".%06ld" , sc_start_timespec .tv_nsec / 1000 );
189
236
190
237
if (output_csv ) {
191
- printf ("%s,%d,%d,%s,\"%s\",\"%s\",\"%s\",%s,%s,%s,%lld,%lld,%llx,\"%s\"\n" ,
238
+ printf ("%s,%s,%d,%d,%s,\"%s\",\"%s\",\"%s\",%s,%s,%s,%lld,%lld,%llx,\"%s\"\n" ,
239
+ "SAMPLE" ,
192
240
timestamp ,
193
241
buf .pid ,
194
242
buf .tgid ,
@@ -208,7 +256,8 @@ int main(int argc, char **argv)
208
256
);
209
257
}
210
258
else {
211
- printf ("%-26s %7d %7d %-6s %-16s %-20s %-16s %-20s %-20s %-26s %'16lld %12lld %-16llx %s\n" ,
259
+ printf ("%-6s %-26s %7d %7d %-6s %-16s %-20s %-16s %-20s %-20s %-26s %'16lld %12lld %-16llx %s\n" ,
260
+ "SAMPLE" ,
212
261
timestamp ,
213
262
buf .pid ,
214
263
buf .tgid ,
@@ -227,7 +276,14 @@ int main(int argc, char **argv)
227
276
buf .filename [0 ] ? buf .filename : "-"
228
277
);
229
278
}
279
+ }
230
280
281
+
282
+ /* Ring buffer poll for event completions */
283
+ err = ring_buffer__poll (rb , 100 /* timeout, ms */ );
284
+ if (err < 0 ) {
285
+ fprintf (stderr , "Error polling ring buffer: %d\n" , err );
286
+ goto cleanup ;
231
287
}
232
288
233
289
@@ -249,7 +305,13 @@ int main(int argc, char **argv)
249
305
cleanup :
250
306
/* Clean up */
251
307
fflush (stdout );
252
- close (iter_fd ); // the fd might already be closed above, but this would just return an EBADF then
308
+ close (iter_fd ); /* the fd might already be closed above, but this would just return an EBADF then */
309
+
310
+ /* Release event completion ring buffer */
311
+ if (rb ) {
312
+ ring_buffer__free (rb );
313
+ }
314
+
253
315
xcapture_bpf__destroy (skel );
254
316
255
317
return err < 0 ? - err : 0 ;
0 commit comments