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