1LIBTRACECMD(3) libtracefs Manual LIBTRACECMD(3)
2
3
4
6 tracecmd_iterate_events, tracecmd_iterate_events_multi,
7 tracecmd_follow_event, tracecmd_follow_missed_events,
8 tracecmd_filter_add - Read events from a trace file
9
11 #include <trace-cmd.h>
12
13 int tracecmd_iterate_events(struct tracecmd_input *handle,
14 cpu_set_t *cpus, int cpu_size,
15 int (*callback)(struct tracecmd_input *,
16 struct tep_record *,
17 int, void *),
18 void *callback_data);
19 int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
20 int nr_handles,
21 int (*callback)(struct tracecmd_input *,
22 struct tep_record *,
23 int, void *),
24 void *callback_data);
25 int tracecmd_follow_event(struct tracecmd_input *handle,
26 const char *system, const char *event_name,
27 int (*callback)(struct tracecmd_input *,
28 struct tep_event *,
29 struct tep_record *,
30 int, void *),
31 void *callback_data);
32 int tracecmd_follow_missed_events(struct tracecmd_input *handle,
33 int (*callback)(struct tracecmd_input *,
34 struct tep_event *,
35 struct tep_record *,
36 int, void *),
37 void *callback_data);
38 struct tracecmd_filter *tracecmd_filter_add(struct tracecmd_input *handle,
39 const char *filter_str, bool neg);
40
42 This set of APIs can be used to iterate over events after opening a
43 trace file using one of the open functions like tracecmd_open(3) or
44 tracecmd_open_fd(3).
45
46 The function tracecmd_iterate_events() will iterate through all the
47 events in the trace file defined by handle, where handle is returned
48 from one of the tracecmd_open(3) functions. It will call the callback()
49 function on the events on the CPUs defined by cpus. The cpu_size must
50 be the size of cpus (see CPU_SET(3)). If cpus is NULL, then cpu_size is
51 ignored and callback() will be called for all events on all CPUs in the
52 trace file. The callback_data is passed to the callback() as its last
53 parameter. callback may be NULL, which is useful if
54 tracecmd_follow_event() is used, but note if callback is NULL, then
55 callback_data is ignored and not sent to the callback of
56 tracecmd_follow_event().
57
58 The function tracecmd_iterate_events_multi() is similar to
59 tracecmd_iterate_events() except that it allows to iterate over more
60 than one trace file. If tracecmd agent(1) is used to get a trace file
61 for both the host and guest, make sure that the host trace file is the
62 first entry in handles and tracecmd_iterate_events_multi() will do the
63 synchronization of the meta data for the guest files that come later in
64 handles. handles is an array of trace file descriptors that were opened
65 by tracecmd_open(3) and friends. Note, unlike
66 tracecmd_iterate_events(), tracecmd_iterate_events_multi() does not
67 filter on CPUs, as it will cause the API to become too complex in
68 knowing which handle to filter the CPUs on. If CPU filtering is
69 desired, then the callback should check the record→cpu to and return 0
70 if it is not the desired CPU to process. nr_handles denotes the number
71 of elements in handles. The callback_data is passed to the callback as
72 its last parameter. callback may be NULL, which is useful if
73 tracecmd_follow_event() is used, but note if callback is NULL, then
74 callback_data is ignored and not sent to the callback of
75 tracecmd_follow_event().
76
77 The callback() for both tracecmd_iterate_events() and
78 tracecmd_iterate_events_multi() is of the prototype:
79
80 int callback()(struct tracecmd_input *handle, struct tep_record
81 *record, int cpu, void *data);
82
83 The handle is the same handle passed to tracecmd_iterate_events() or
84 the current handle of handles passed to tracecmd_iterate_events_multi()
85 that the record belongs to. The record is the current event record. The
86 cpu is the current CPU being processed. Note, for
87 tracecmd_iterate_events_multi() it may not be the actual CPU of the
88 file, but the nth CPU of all the handles put together. Use record→cpu
89 to get the actual CPU that the event is on.
90
91 The tracecmd_follow_event() function will attach to a trace file
92 descriptor handle and call the callback when the event described by
93 system and name matches an event in the iteration of
94 tracecmd_iterate_events() or tracecmd_iterate_events_multi(). Note, the
95 cpu is the nth CPU for both tracecmd_iterate_events() and
96 tracecmd_iterate_events_multi(). If the actual CPU of the record is
97 needed, use record→cpu. For tracecmd_iterate_events_multi(), the
98 callback is only called if the handle matches the current trace file
99 descriptor within handles. The callback_data is passed as the last
100 parameter to the callback() function. Note, this callback() function
101 will be called before the callback() function of either
102 tracecmd_iterate_events() or tracecmd_iterate_events_multi().
103
104 The callback() prototype for *tracecmd_follow_event()_ is:
105
106 int callback()(struct tracecmd_input *handle, struct tep_event *event,
107 struct tep_record *_record, int cpu, void *data);
108
109 The tracecmd_follow_missed_events() function will attach to a trace
110 file descriptor handle and call the callback when missed events are
111 detected. The event will hold the type of event that the record is. The
112 record will hold the information of the missed events. The cpu is the
113 nth CPU for both tracecmd_iterate_events() and
114 tracecmd_iterate_events_multi(). If the CPU that the missed events are
115 for is needed, use record→cpu. If record→missed_events is a positive
116 number, then it holds the number of missed events since the last event
117 on its CPU, otherwise it will be negative, and that will mean that the
118 number of missed events is unknown but missed events exist since the
119 last event on the CPU. The callback and callback_data is the same
120 format as tracecmd_follow_event() above. The missed events callback is
121 called before any of the other callbacks and any filters that were
122 added by tracecmd_filter_add() are ignored. If callback returns a non
123 zero, it will stop the iterator before it calls any of the other
124 iterator callbacks for the given record.
125
126 The tracecmd_filter_add() function, adds a filter to handle that
127 affects both tracecmd_iterate_events() and
128 tracecmd_iterate_events_multi(). The filter_str is a character string
129 defining a filter in a format that is defined by
130 tep_filter_add_filter_str(3). If neg is true, then the events that
131 match the filter will be skipped, otherwise the events that match will
132 execute the callback() function in the iterators.
133
135 Both tracecmd_iterate_events() and tracecmd_iterate_events_multi()
136 return zero if they successfully iterated all events (handling the
137 follow and filters appropriately). Or an error value, which can include
138 returning a non-zero result from the callback() function.
139
141 #define _GNU_SOURCE
142 #include <sched.h>
143 #include <stdlib.h>
144 #include <getopt.h>
145 #include <trace-cmd.h>
146
147 struct private_data {
148 int cpu;
149 const char *file;
150 };
151
152 static int print_events(struct tracecmd_input *handle, struct tep_record *record, int cpu, void *data)
153 {
154 static struct trace_seq seq;
155 struct tep_handle *tep = tracecmd_get_tep(handle);
156 struct private_data *pdata = tracecmd_get_private(handle);
157
158 /* For multi handles we need this */
159 if (pdata->cpu >= 0 && pdata->cpu != record->cpu)
160 return 0;
161
162 if (!seq.buffer)
163 trace_seq_init(&seq);
164
165 trace_seq_reset(&seq);
166 trace_seq_printf(&seq, "%s: ", pdata->file);
167 tep_print_event(tep, &seq, record, "%6.1000d [%03d] %s-%d %s: %s\n",
168 TEP_PRINT_TIME, TEP_PRINT_CPU, TEP_PRINT_COMM, TEP_PRINT_PID,
169 TEP_PRINT_NAME, TEP_PRINT_INFO);
170 trace_seq_terminate(&seq);
171 trace_seq_do_printf(&seq);
172 return 0;
173 }
174
175 static int print_event(struct tracecmd_input *handle, struct tep_event *event,
176 struct tep_record *record, int cpu, void *data)
177 {
178 return print_events(handle, record, cpu, data);
179 }
180
181 static int missed_events(struct tracecmd_input *handle, struct tep_event *event,
182 struct tep_record *record, int cpu, void *data)
183 {
184 if (record->missed_events > 0)
185 printf("CPU [%03d] has %d missed events\n",
186 record->cpu, record->missed_events);
187 else
188 printf("CPU [%03d] has missed events\n", record->cpu);
189 return 0;
190 }
191
192 static void usage(const char *argv0)
193 {
194 printf("usage: [-c cpu][-f filter][-e event] %s trace.dat [trace.dat ...]\n",
195 argv0);
196 exit(-1);
197 }
198
199 int main(int argc, char **argv)
200 {
201 struct tracecmd_input **handles = NULL;
202 const char *filter_str = NULL;
203 const char *argv0 = argv[0];
204 struct private_data *priv;
205 cpu_set_t *cpuset = NULL;
206 char *event = NULL;
207 size_t cpusize = 0;
208 int nr_handles = 0;
209 int cpu = -1;
210 int i;
211 int c;
212
213 while ((c = getopt(argc, argv, "c:f:e:")) >= 0) {
214 switch (c) {
215 case 'c':
216 /* filter all trace data to this one CPU. */
217 cpu = atoi(optarg);
218 break;
219 case 'f':
220 filter_str = optarg;
221 break;
222 case 'e':
223 event = optarg;
224 break;
225 default:
226 usage(argv0);
227 }
228 }
229 argc -= optind;
230 argv += optind;
231
232 if (argc == 0)
233 usage(argv0);
234
235 for (i = 0; i < argc; i++) {
236 handles = realloc(handles, sizeof(*handles) * (nr_handles + 1));
237 if (!handles)
238 exit(-1);
239 handles[nr_handles] = tracecmd_open(argv[i], 0);
240 if (!handles[nr_handles]) {
241 perror(argv[i]);
242 exit(-1);
243 }
244 if (filter_str) {
245 if (tracecmd_filter_add(handles[nr_handles], filter_str, false) == NULL) {
246 perror("adding filter");
247 exit(-1);
248 }
249 }
250 priv = calloc(1, sizeof(*priv));
251 if (!priv)
252 exit(-1);
253 priv->file = argv[i];
254 priv->cpu = cpu;
255 tracecmd_set_private(handles[nr_handles], priv);
256 if (event) {
257 if (tracecmd_follow_event(handles[nr_handles], NULL, event, print_event, NULL) < 0) {
258 printf("Could not follow event %s for file %s\n", event, argv[i]);
259 exit(-1);
260 }
261 }
262 tracecmd_follow_missed_events(handles[nr_handles], missed_events, NULL);
263 nr_handles++;
264 }
265
266 /* Shortcut */
267 if (nr_handles == 1) {
268 if (cpu >= 0) {
269 cpuset = CPU_ALLOC(cpu + 1);
270 if (!cpuset)
271 exit(-1);
272 cpusize = CPU_ALLOC_SIZE(cpu + 1);
273 CPU_SET_S(cpu, cpusize, cpuset);
274 }
275 if (event)
276 tracecmd_iterate_events(handles[0], cpuset, cpusize, NULL, NULL);
277 else
278 tracecmd_iterate_events(handles[0], cpuset, cpusize, print_events, NULL);
279 } else {
280 if (event)
281 tracecmd_iterate_events_multi(handles, nr_handles, NULL, NULL);
282 else
283 tracecmd_iterate_events_multi(handles, nr_handles, print_events, NULL);
284 }
285
286 for (i = 0; i < nr_handles; i++) {
287 priv = tracecmd_get_private(handles[i]);
288 free(priv);
289 tracecmd_close(handles[i]);
290 }
291 free(handles);
292 }
293
295 trace-cmd.h
296 Header file to include in order to have access to the library APIs.
297 -ltracecmd
298 Linker switch to add when building a program that uses the library.
299
301 libtracefs(3), libtraceevent(3), trace-cmd(1) trace-cmd.dat(5)
302
304 Steven Rostedt <rostedt@goodmis.org[1]>
305 Tzvetomir Stoyanov <tz.stoyanov@gmail.com[2]>
306
308 Report bugs to <linux-trace-devel@vger.kernel.org[3]>
309
311 libtracecmd is Free Software licensed under the GNU LGPL 2.1
312
314 https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git/
315
317 Copyright (C) 2020 VMware, Inc. Free use of this software is granted
318 under the terms of the GNU Public License (GPL).
319
321 1. rostedt@goodmis.org
322 mailto:rostedt@goodmis.org
323
324 2. tz.stoyanov@gmail.com
325 mailto:tz.stoyanov@gmail.com
326
327 3. linux-trace-devel@vger.kernel.org
328 mailto:linux-trace-devel@vger.kernel.org
329
330
331
332libtracefs 07/20/2023 LIBTRACECMD(3)