| 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). |