summaryrefslogtreecommitdiffstats
path: root/Documentation/libtracefs-synth.txt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:26:15 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:26:15 +0000
commitc72e01b9ea891fa5cbbbe9876bdfb49079b55be7 (patch)
tree44c55a81a281a6c211745c0abc68352aeaf0180f /Documentation/libtracefs-synth.txt
parentInitial commit. (diff)
downloadlibtracefs-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.txt368
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).