diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:26:15 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:26:15 +0000 |
commit | c72e01b9ea891fa5cbbbe9876bdfb49079b55be7 (patch) | |
tree | 44c55a81a281a6c211745c0abc68352aeaf0180f /Documentation/libtracefs-synth.txt | |
parent | Initial commit. (diff) | |
download | libtracefs-803ed2a4230ec919f62a7b6fee2f054699f753a7.tar.xz libtracefs-803ed2a4230ec919f62a7b6fee2f054699f753a7.zip |
Adding upstream version 1.6.4.upstream/1.6.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'Documentation/libtracefs-synth.txt')
-rw-r--r-- | Documentation/libtracefs-synth.txt | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/Documentation/libtracefs-synth.txt b/Documentation/libtracefs-synth.txt new file mode 100644 index 0000000..c57725d --- /dev/null +++ b/Documentation/libtracefs-synth.txt @@ -0,0 +1,368 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_synth_alloc, tracefs_synth_add_match_field, tracefs_synth_add_compare_field, tracefs_synth_add_start_field, +tracefs_synth_add_end_field, tracefs_synth_append_start_filter, tracefs_synth_append_end_filter, tracefs_synth_free, +- Creation of a synthetic event descriptor + +SYNOPSIS +-------- +[verse] +-- +*#include <tracefs.h>* + +struct tracefs_synth pass:[*]*tracefs_synth_alloc*(struct tep_handle pass:[*]_tep_, + const char pass:[*]_name_, + const char pass:[*]_start_system_, + const char pass:[*]_start_event_, + const char pass:[*]_end_system_, + const char pass:[*]_end_event_, + const char pass:[*]_start_match_field_, + const char pass:[*]_end_match_field_, + const char pass:[*]_match_name_); +int *tracefs_synth_add_match_field*(struct tracefs_synth pass:[*]_synth_, + const char pass:[*]_start_match_field_, + const char pass:[*]_end_match_field_, + const char pass:[*]_name_); +int *tracefs_synth_add_compare_field*(struct tracefs_synth pass:[*]_synth_, + const char pass:[*]_start_compare_field_, + const char pass:[*]_end_compare_field_, + enum tracefs_synth_calc _calc_, + const char pass:[*]_name_); +int *tracefs_synth_add_start_field*(struct tracefs_synth pass:[*]_synth_, + const char pass:[*]_start_field_, + const char pass:[*]_name_); +int *tracefs_synth_add_end_field*(struct tracefs_synth pass:[*]_synth_, + const char pass:[*]_end_field_, + const char pass:[*]_name_); +int *tracefs_synth_append_start_filter*(struct tracefs_synth pass:[*]_synth_, + struct tracefs_filter _type_, + const char pass:[*]_field_, + enum tracefs_synth_compare _compare_, + const char pass:[*]_val_); +int *tracefs_synth_append_end_filter*(struct tracefs_synth pass:[*]_synth_, + struct tracefs_filter _type_, + const char pass:[*]_field_, + enum tracefs_synth_compare _compare_, + const char pass:[*]_val_); +void *tracefs_synth_free*(struct tracefs_synth pass:[*]_synth_); +-- + +DESCRIPTION +----------- +Synthetic events are dynamic events that are created by matching +two other events which triggers a synthetic event. One event is the starting +event which some field is recorded, and when the second event is executed, +if it has a field (or fields) that matches the starting event's field (or fields) +then it will trigger the synthetic event. The field values other than the matching +fields may be passed from the starting event to the end event to perform calculations +on, or to simply pass as a parameter to the synthetic event. + +One common use case is to set "sched_waking" as the starting event. This event is +triggered when a process is awoken. Then set "sched_switch" as the ending event. +This event is triggered when a new task is scheduled on the CPU. By setting +the "common_pid" of both events as the matching fields, the time between the +two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP* +as a field for both events to calculate the delta in nanoseconds, or use +*TRACEFS_TIMESTAMP_USECS" as the compare fields for both events to calculate the +delta in microseconds. This is used as the example below. + +*tracefs_synth_alloc*() allocates and initializes a synthetic event. +It does not create the synthetic event, but supplies the minimal information +to do so. See *tracefs_synth_create*(3) for how to create the synthetic +event in the system. It requires a _tep_ handler that can be created by +*tracefs_local_events*(3) for more information. The _name_ holds the name +of the synthetic event that will be created. The _start_system_ is the name +of the system for the starting event. It may be NULL and the first event +with the name of _start_event_ will be chosen. The _end_system_ is the +name of the system for theh ending event. It may be NULL and the first event +with the name of _end_event_ will be chosen as the ending event. If _match_name_ +is given, then this will be the field of the created synthetic event that +holds the matching keys of the starting event's _start_match_field_ and +the ending event's _end_match_field_. If _match_name_ is NULL, then it will +not be recorded in the created synthetic event. + +*tracefs_synth_add_match_field*() will add a second key to match between the +starting event and the ending event. If _name_ is given, then the content +of the matching field will be saved by this _name_ in the synthetic event. +The _start_match_field_ is the field of the starting event to mach with the +ending event's _end_match_field_. + +*tracefs_synth_add_compare_field*() is used to compare the _start_compare_field_ +of the starting event with the _end_compare_field_ of the ending event. The _name_ +must be given so that the result will be saved by the synthetic event. It makes +no sense to not pass this to the synthetic event after doing the work of +the compared fields, as it serves no other purpose. The _calc_ parameter +can be one of: + +*TRACEFS_SYNTH_DELTA_END* - calculate the difference between the content in + the _end_compare_field_ from the content of the _start_compare_field_. + +_name_ = _end_compare_field_ - _start_compare_field_ + +*TRACEFS_SYNTH_DELTA_START* - calculate the difference between the content in + the _start_compare_field_ from the content of the _end_compare_field_. + +_name_ = _start_compare_field_ - _end_compare_field_ + +*TRACEFS_SYNTH_ADD* - Add the content of the _start_compare_field_ to the + content of the _end_compare_field_. + +_name_ = _start_compare_field_ + _end_compare_field_ + +*tracefs_synth_add_start_field*() - Records the _start_field_ of the starting +event as _name_ in the synthetic event. If _name_ is NULL, then the name used +will be the same as _start_field_. + +*tracefs_synth_add_end_field*() - Records the _end_field_ of the ending +event as _name_ in the synthetic event. If _name_ is NULL, then the name used +will be the same as _end_field_. + +*tracefs_synth_append_start_filter*() creates a filter or appends to it for the +starting event. Depending on _type_, it will build a string of tokens for +parenthesis or logic statements, or it may add a comparison of _field_ +to _val_ based on _compare_. + +If _type_ is: +*TRACEFS_FILTER_COMPARE* - See below +*TRACEFS_FILTER_AND* - Append "&&" to the filter +*TRACEFS_FILTER_OR* - Append "||" to the filter +*TRACEFS_FILTER_NOT* - Append "!" to the filter +*TRACEFS_FILTER_OPEN_PAREN* - Append "(" to the filter +*TRACEFS_FILTER_CLOSE_PAREN* - Append ")" to the filter + +_field_, _compare_, and _val_ are ignored unless _type_ is equal to +*TRACEFS_FILTER_COMPARE*, then _compare will be used for the following: + +*TRACEFS_COMPARE_EQ* - _field_ == _val_ + +*TRACEFS_COMPARE_NE* - _field_ != _val_ + +*TRACEFS_COMPARE_GT* - _field_ > _val_ + +*TRACEFS_COMPARE_GE* - _field_ >= _val_ + +*TRACEFS_COMPARE_LT* - _field_ < _val_ + +*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_ + +*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string. + +*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field. + +*tracefs_synth_append_end_filter*() is the same as *tracefs_synth_append_start_filter* but +filters on the ending event. + +*tracefs_synth_free*() frees the allocated descriptor returned by +*tracefs_synth_alloc*(). + +RETURN VALUE +------------ +*tracefs_synth_alloc*() returns an allocated struct tracefs_synth descriptor +on success or NULL on error. + +All other functions that return an integer returns zero on success or -1 +on error. + +ERRORS +------ +The following errors are for all the above calls: + +*EPERM* Not run as root user when required. + +*EINVAL* Either a parameter is not valid (NULL when it should not be) + or a field that is not compatible for calculations. + +*ENODEV* An event or one of its fields is not found. + +*EBADE* The fields of the start and end events are not compatible for + either matching or comparing. + +*ENOMEM* not enough memory is available. + +And more errors may have happened from the system calls to the system. + +EXAMPLE +------- +[source,c] +-- +#include <stdlib.h> +#include <tracefs.h> + +#define start_event "sched_waking" +#define start_field "pid" + +#define end_event "sched_switch" +#define end_field "next_pid" + +#define match_name "pid" + +static struct tracefs_synth *synth; + +static void make_event(void) +{ + struct tep_handle *tep; + + /* Load all events from the system */ + tep = tracefs_local_events(NULL); + + /* Initialize the synthetic event */ + synth = tracefs_synth_alloc(tep, "wakeup_lat", + NULL, start_event, + NULL, end_event, + start_field, end_field, + match_name); + + /* The tep is no longer needed */ + tep_free(tep); + + + /* Save the "prio" field as "prio" from the start event */ + tracefs_synth_add_start_field(synth, "prio", NULL); + + /* Save the "next_comm" as "comm" from the end event */ + tracefs_synth_add_end_field(synth, "next_comm", "comm"); + + /* Save the "prev_prio" as "prev_prio" from the end event */ + tracefs_synth_add_end_field(synth, "prev_prio", NULL); + + /* + * Take a microsecond time difference between end and start + * and record as "delta" + */ + tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS, + TRACEFS_TIMESTAMP_USECS, + TRACEFS_SYNTH_DELTA_END, "delta"); + + /* Only record if start event "prio" is less than 100 */ + tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE, + "prio", TRACEFS_COMPARE_LT, "100"); + + /* + * Only record if end event "next_prio" is less than 50 + * or the previous task's prio was not greater than or equal to 100. + * next_prio < 50 || !(prev_prio >= 100) + */ + tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, + "next_prio", TRACEFS_COMPARE_LT, "50"); + tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL); + tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL); + tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL); + tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, + "prev_prio", TRACEFS_COMPARE_GE, "100"); + /* + * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100" + * That's because, when the synth is executed, the remaining close parenthesis + * will be added. That is, the string will end up being: + * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create() + * or tracefs_sync_echo_cmd() is run. + */ +} + +/* Display how to create the synthetic event */ +static void show_event(void) +{ + struct trace_seq s; + + trace_seq_init(&s); + + tracefs_synth_echo_cmd(&s, synth); + trace_seq_terminate(&s); + trace_seq_do_printf(&s); + trace_seq_destroy(&s); +} + +int main (int argc, char **argv) +{ + make_event(); + + if (argc > 1) { + if (!strcmp(argv[1], "create")) { + /* Create the synthetic event */ + tracefs_synth_create(synth); + } else if (!strcmp(argv[1], "delete")) { + /* Delete the synthetic event */ + tracefs_synth_destroy(synth); + } else { + printf("usage: %s [create|delete]\n", argv[0]); + exit(-1); + } + } else + show_event(); + + tracefs_synth_free(synth); + + return 0; +} +-- + +FILES +----- +[verse] +-- +*tracefs.h* + Header file to include in order to have access to the library APIs. +*-ltracefs* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +*tracefs_synth_create*(3), +*tracefs_synth_destroy*(3), +*tracfes_synth_echo_cmd*(3), +*libtracefs*(3), +*libtraceevent*(3), +*trace-cmd*(1), +*tracefs_hist_alloc*(3), +*tracefs_hist_alloc_2d*(3), +*tracefs_hist_alloc_nd*(3), +*tracefs_hist_free*(3), +*tracefs_hist_add_key*(3), +*tracefs_hist_add_value*(3), +*tracefs_hist_add_name*(3), +*tracefs_hist_start*(3), +*tracefs_hist_destory*(3), +*tracefs_hist_add_sort_key*(3), +*tracefs_hist_sort_key_direction*(3), +*tracefs_synth_create*(3), +*tracefs_synth_destroy*(3), +*tracefs_synth_complete*(3), +*tracefs_synth_trace*(3), +*tracefs_synth_snapshot*(3), +*tracefs_synth_save*(3), +*tracefs_synth_echo_cmd*(3), +*tracefs_synth_get_start_hist*(3), +*tracefs_synth_get_name*(3), +*tracefs_synth_raw_fmt*(3), +*tracefs_synth_show_event*(3), +*tracefs_synth_show_start_hist*(3), +*tracefs_synth_show_end_hist*(3), +*tracefs_synth_get_event*(3), + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* <rostedt@goodmis.org> +*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com> +*sameeruddin shaik* <sameeruddin.shaik8@gmail.com> +-- +REPORTING BUGS +-------------- +Report bugs to <linux-trace-devel@vger.kernel.org> + +LICENSE +------- +libtracefs is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ + +COPYING +------- +Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under +the terms of the GNU Public License (GPL). |