From: "Steven Rostedt (Google)" <rostedt@xxxxxxxxxxx> Add man pages for the following iterator functions: tracecmd_iterate_events() tracecmd_iterate_events_multi() tracecmd_follow_event() tracecmd_filter_add() Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx> --- .../libtracecmd/libtracecmd-iterate.txt | 291 ++++++++++++++++++ Documentation/libtracecmd/libtracecmd.txt | 23 ++ 2 files changed, 314 insertions(+) create mode 100644 Documentation/libtracecmd/libtracecmd-iterate.txt diff --git a/Documentation/libtracecmd/libtracecmd-iterate.txt b/Documentation/libtracecmd/libtracecmd-iterate.txt new file mode 100644 index 000000000000..c0a99f3087c2 --- /dev/null +++ b/Documentation/libtracecmd/libtracecmd-iterate.txt @@ -0,0 +1,291 @@ +libtracecmd(3) +============= + +NAME +---- +tracecmd_iterate_events, tracecmd_iterate_events_multi, tracecmd_follow_event, +tracecmd_filter_add - Read events from a trace file + +SYNOPSIS +-------- +[verse] +-- +*#include <trace-cmd.h>* + +int *tracecmd_iterate_events*(struct tracecmd_input pass:[*]_handle_, + cpu_set_t pass:[*]_cpus_, int _cpu_size_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); +int *tracecmd_iterate_events_multi*(struct tracecmd_input pass:[**]_handles_, + int _nr_handles_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); +int *tracecmd_follow_event*(struct tracecmd_input pass:[*]_handle_, + const char pass:[*]_system_, const char pass:[*]_event_name_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_event pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); +struct tracecmd_filter pass:[*]*tracecmd_filter_add*(struct tracecmd_input *_handle_, + const char pass:[*]_filter_str_, bool _neg_); +-- + +DESCRIPTION +----------- +This set of APIs can be used to iterate over events after opening a trace file +using one of the open functions like *tracecmd_open(3)* or *tracecmd_open_fd(3)*. + +The function *tracecmd_iterate_events()* will iterate through all the +events in the trace file defined by _handle_, where _handle_ is returned from +one of the *tracecmd_open(3)* functions. It will call the _callback_() function +on the events on the CPUs defined by _cpus_. The _cpu_size_ must be the size of +_cpus_ (see *CPU_SET(3)*). If _cpus_ is NULL, then _cpu_size_ is ignored and _callback()_ +will be called for all events on all CPUs in the trace file. The _callback_data_ +is passed to the _callback()_ as its last parameter. _callback_ may be NULL, which +is useful if *tracecmd_follow_event()* is used, but note if _callback_ is NULL, then +_callback_data_ is ignored and not sent to the _callback_ of *tracecmd_follow_event()*. + +The function *tracecmd_iterate_events_multi()* is similar to *tracecmd_iterate_events()* +except that it allows to iterate over more than one trace file. If *tracecmd agent(1)* +is used to get a trace file for both the host and guest, make sure that the host trace +file is the first entry in _handles_ and *tracecmd_iterate_events_multi()* will do +the synchronization of the meta data for the guest files that come later in _handles_. +_handles_ is an array of trace file descriptors that were opened by *tracecmd_open(3)* +and friends. Note, unlike *tracecmd_iterate_events()*, *tracecmd_iterate_events_multi()* +does not filter on CPUs, as it will cause the API to become too complex in knowing which +handle to filter the CPUs on. If CPU filtering is desired, then the _callback_ should check +the _record_->cpu to and return 0 if it is not the desired CPU to process. _nr_handles_ +denotes the number of elements in _handles_. The _callback_data_ is passed to the _callback_ +as its last parameter. _callback_ may be NULL, which is useful if *tracecmd_follow_event()* +is used, but note if _callback_ is NULL, then _callback_data_ is ignored and not sent to the +_callback_ of *tracecmd_follow_event()*. + +The _callback()_ for both *tracecmd_iterate_events()* and *tracecmd_iterate_events_multi()* is of the prototype: + +int _callback()_(struct tracecmd_input pass:[*]_handle_, struct tep_record pass:[*]_record_, + int _cpu_, void pass:[*]_data_); + +The _handle_ is the same _handle_ passed to *tracecmd_iterate_events()* or the current +handle of _handles_ passed to *tracecmd_iterate_events_multi()* that the _record_ belongs to. +The _record_ is the current event record. The _cpu_ is the current CPU being processed. Note, for +*tracecmd_iterate_events_multi()* it may not be the actual CPU of the file, but the nth +CPU of all the _handles_ put together. Use _record_->cpu to get the actual CPU that the +event is on. + +The *tracecmd_follow_event()* function will attach to a trace file descriptor _handle_ +and call the _callback_ when the event described by _system_ and _name_ matches an event +in the iteration of *tracecmd_iterate_events()* or *tracecmd_iterate_events_multi()*. +For *tracecmd_iterate_events_multi()*, the _callback_ is only called if the _handle_ +matches the current trace file descriptor within _handles_. The _callback_data_ is +passed as the last parameter to the _callback()_ function. Note, this _callback()_ +function will be called before the _callback()_ function of either *tracecmd_iterate_events()* or *tracecmd_iterate_events_multi()*. + +The _callback()_ prototype for *tracecmd_follow_event()_ is: + +int _callback()_(struct tracecmd_input pass:[*]_handle_, struct tep_event pass:[*]_event, + struct tep_record pass:[*]_record_, int _cpu_, void pass:[*]_data_); + +The *tracecmd_filter_add()* function, adds a filter to _handle_ that affects +both *tracecmd_iterate_events()* and *tracecmd_iterate_events_multi()*. +The _filter_str_ is a character string defining a filter in a format that +is defined by *tep_filter_add_filter_str(3)*. If _neg_ is true, then the events +that match the filter will be skipped, otherwise the events that match will execute +the _callback()_ function in the iterators. + +RETURN VALUE +------------ +Both *tracecmd_iterate_events()* and *tracecmd_iterate_events_multi()* return zero +if they successfully iterated all events (handling the follow and filters appropriately). +Or an error value, which can include returning a non-zero result from the _callback()_ +function. + +EXAMPLE +------- +[source,c] +-- +#define _GNU_SOURCE +#include <sched.h> +#include <stdlib.h> +#include <getopt.h> +#include <trace-cmd.h> + +struct private_data { + int cpu; + const char *file; +}; + +static int print_events(struct tracecmd_input *handle, struct tep_record *record, int cpu, void *data) +{ + static struct trace_seq seq; + struct tep_handle *tep = tracecmd_get_tep(handle); + struct private_data *pdata = tracecmd_get_private(handle); + + /* For multi handles we need this */ + if (pdata->cpu >= 0 && pdata->cpu != record->cpu) + return 0; + + if (!seq.buffer) + trace_seq_init(&seq); + + trace_seq_reset(&seq); + trace_seq_printf(&seq, "%s: ", pdata->file); + tep_print_event(tep, &seq, record, "%6.1000d [%03d] %s-%d %s: %s\n", + TEP_PRINT_TIME, TEP_PRINT_CPU, TEP_PRINT_COMM, TEP_PRINT_PID, + TEP_PRINT_NAME, TEP_PRINT_INFO); + trace_seq_terminate(&seq); + trace_seq_do_printf(&seq); + return 0; +} + +static int print_event(struct tracecmd_input *handle, struct tep_event *event, + struct tep_record *record, int cpu, void *data) +{ + return print_events(handle, record, cpu, data); +} + +static void usage(const char *argv0) +{ + printf("usage: [-c cpu][-f filter][-e event] %s trace.dat [trace.dat ...]\n", + argv0); + exit(-1); +} + +int main(int argc, char **argv) +{ + struct tracecmd_input **handles = NULL; + const char *filter_str = NULL; + const char *argv0 = argv[0]; + struct private_data *priv; + cpu_set_t *cpuset = NULL; + char *event = NULL; + size_t cpusize = 0; + int nr_handles = 0; + int cpu = -1; + int i; + int c; + + while ((c = getopt(argc, argv, "c:f:e:")) >= 0) { + switch (c) { + case 'c': + /* filter all trace data to this one CPU. */ + cpu = atoi(optarg); + break; + case 'f': + filter_str = optarg; + break; + case 'e': + event = optarg; + break; + default: + usage(argv0); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(argv0); + + for (i = 0; i < argc; i++) { + handles = realloc(handles, sizeof(*handles) * (nr_handles + 1)); + if (!handles) + exit(-1); + handles[nr_handles] = tracecmd_open(argv[i], 0); + if (!handles[nr_handles]) { + perror(argv[i]); + exit(-1); + } + if (filter_str) { + if (tracecmd_filter_add(handles[nr_handles], filter_str, false) == NULL) { + perror("adding filter"); + exit(-1); + } + } + priv = calloc(1, sizeof(*priv)); + if (!priv) + exit(-1); + priv->file = argv[i]; + priv->cpu = cpu; + tracecmd_set_private(handles[nr_handles], priv); + if (event) { + if (tracecmd_follow_event(handles[nr_handles], NULL, event, print_event, NULL) < 0) { + printf("Could not follow event %s for file %s\n", event, argv[i]); + exit(-1); + } + } + nr_handles++; + } + + /* Shortcut */ + if (nr_handles == 1) { + if (cpu >= 0) { + cpuset = CPU_ALLOC(cpu + 1); + if (!cpuset) + exit(-1); + cpusize = CPU_ALLOC_SIZE(cpu + 1); + CPU_SET_S(cpu, cpusize, cpuset); + } + if (event) + tracecmd_iterate_events(handles[0], cpuset, cpusize, NULL, NULL); + else + tracecmd_iterate_events(handles[0], cpuset, cpusize, print_events, NULL); + } else { + if (event) + tracecmd_iterate_events_multi(handles, nr_handles, NULL, NULL); + else + tracecmd_iterate_events_multi(handles, nr_handles, print_events, NULL); + } + + for (i = 0; i < nr_handles; i++) { + priv = tracecmd_get_private(handles[i]); + free(priv); + tracecmd_close(handles[i]); + } + free(handles); +} +-- +FILES +----- +[verse] +-- +*trace-cmd.h* + Header file to include in order to have access to the library APIs. +*-ltracecmd* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +*libtracefs(3)*, +*libtraceevent(3)*, +*trace-cmd(1)* +*trace-cmd.dat(5)* + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* <rostedt@xxxxxxxxxxx> +*Tzvetomir Stoyanov* <tz.stoyanov@xxxxxxxxx> +-- +REPORTING BUGS +-------------- +Report bugs to <linux-trace-devel@xxxxxxxxxxxxxxx> + +LICENSE +------- +libtracecmd is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git/ + +COPYING +------- +Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under +the terms of the GNU Public License (GPL). diff --git a/Documentation/libtracecmd/libtracecmd.txt b/Documentation/libtracecmd/libtracecmd.txt index 141fec5d379c..d2d17f7cbaba 100644 --- a/Documentation/libtracecmd/libtracecmd.txt +++ b/Documentation/libtracecmd/libtracecmd.txt @@ -27,6 +27,29 @@ Read tracing records from a trace file: void *tracecmd_free_record*(struct tep_record pass:[*]_record_); struct tep_handle pass:[*]*tracecmd_get_tep*(struct tracecmd_input pass:[*]_handle_); +Iterating over events in a trace file: + int *tracecmd_iterate_events*(struct tracecmd_input pass:[*]_handle_, + cpu_set_t pass:[*]_cpus_, int _cpu_size_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); + int *tracecmd_iterate_events_multi*(struct tracecmd_input pass:[**]_handles_, + int _nr_handles_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); + int *tracecmd_follow_event*(struct tracecmd_input pass:[*]_handle_, + const char pass:[*]_system_, const char pass:[*]_event_name_, + int (pass:[*]_callback_)(struct tracecmd_input pass:[*], + struct tep_event pass:[*], + struct tep_record pass:[*], + int, void pass:[*]), + void pass:[*]_callback_data_); + struct tracecmd_filter pass:[*]*tracecmd_filter_add*(struct tracecmd_input *_handle_, + const char pass:[*]_filter_str_, bool _neg_); + Read tracing instances from a trace file: int *tracecmd_buffer_instances*(struct tracecmd_input pass:[*]_handle_); const char pass:[*]*tracecmd_buffer_instance_name*(struct tracecmd_input pass:[*]_handle_, int _indx_); -- 2.35.1