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