'\" t
.\" Title: libtracefs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot
.\" Date: 07/25/2024
.\" Manual: libtracefs Manual
.\" Source: libtracefs 1.8.1
.\" Language: English
.\"
.TH "LIBTRACEFS" "3" "07/25/2024" "libtracefs 1\&.8\&.1" "libtracefs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "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
.SH "SYNOPSIS"
.sp
.nf
\fB#include \fR
struct tracefs_synth *\fBtracefs_synth_alloc\fR(struct tep_handle *\fItep\fR,
const char *\fIname\fR,
const char *\fIstart_system\fR,
const char *\fIstart_event\fR,
const char *\fIend_system\fR,
const char *\fIend_event\fR,
const char *\fIstart_match_field\fR,
const char *\fIend_match_field\fR,
const char *\fImatch_name\fR);
int \fBtracefs_synth_add_match_field\fR(struct tracefs_synth *\fIsynth\fR,
const char *\fIstart_match_field\fR,
const char *\fIend_match_field\fR,
const char *\fIname\fR);
int \fBtracefs_synth_add_compare_field\fR(struct tracefs_synth *\fIsynth\fR,
const char *\fIstart_compare_field\fR,
const char *\fIend_compare_field\fR,
enum tracefs_synth_calc \fIcalc\fR,
const char *\fIname\fR);
int \fBtracefs_synth_add_start_field\fR(struct tracefs_synth *\fIsynth\fR,
const char *\fIstart_field\fR,
const char *\fIname\fR);
int \fBtracefs_synth_add_end_field\fR(struct tracefs_synth *\fIsynth\fR,
const char *\fIend_field\fR,
const char *\fIname\fR);
int \fBtracefs_synth_append_start_filter\fR(struct tracefs_synth *\fIsynth\fR,
struct tracefs_filter \fItype\fR,
const char *\fIfield\fR,
enum tracefs_synth_compare \fIcompare\fR,
const char *\fIval\fR);
int \fBtracefs_synth_append_end_filter\fR(struct tracefs_synth *\fIsynth\fR,
struct tracefs_filter \fItype\fR,
const char *\fIfield\fR,
enum tracefs_synth_compare \fIcompare\fR,
const char *\fIval\fR);
void \fBtracefs_synth_free\fR(struct tracefs_synth *\fIsynth\fR);
.fi
.SH "DESCRIPTION"
.sp
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\(cqs 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\&.
.sp
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 \fBTRACEFS_TIMESTAMP\fR 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\&.
.sp
\fBtracefs_synth_alloc\fR() allocates and initializes a synthetic event\&. It does not create the synthetic event, but supplies the minimal information to do so\&. See \fBtracefs_synth_create\fR(3) for how to create the synthetic event in the system\&. It requires a \fItep\fR handler that can be created by \fBtracefs_local_events\fR(3) for more information\&. The \fIname\fR holds the name of the synthetic event that will be created\&. The \fIstart_system\fR is the name of the system for the starting event\&. It may be NULL and the first event with the name of \fIstart_event\fR will be chosen\&. The \fIend_system\fR is the name of the system for theh ending event\&. It may be NULL and the first event with the name of \fIend_event\fR will be chosen as the ending event\&. If \fImatch_name\fR is given, then this will be the field of the created synthetic event that holds the matching keys of the starting event\(cqs \fIstart_match_field\fR and the ending event\(cqs \fIend_match_field\fR\&. If \fImatch_name\fR is NULL, then it will not be recorded in the created synthetic event\&.
.sp
\fBtracefs_synth_add_match_field\fR() will add a second key to match between the starting event and the ending event\&. If \fIname\fR is given, then the content of the matching field will be saved by this \fIname\fR in the synthetic event\&. The \fIstart_match_field\fR is the field of the starting event to mach with the ending event\(cqs \fIend_match_field\fR\&.
.sp
\fBtracefs_synth_add_compare_field\fR() is used to compare the \fIstart_compare_field\fR of the starting event with the \fIend_compare_field\fR of the ending event\&. The \fIname\fR 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 \fIcalc\fR parameter can be one of:
.sp
\fBTRACEFS_SYNTH_DELTA_END\fR \- calculate the difference between the content in the \fIend_compare_field\fR from the content of the \fIstart_compare_field\fR\&.
.sp
\fIname\fR = \fIend_compare_field\fR \- \fIstart_compare_field\fR
.sp
\fBTRACEFS_SYNTH_DELTA_START\fR \- calculate the difference between the content in the \fIstart_compare_field\fR from the content of the \fIend_compare_field\fR\&.
.sp
\fIname\fR = \fIstart_compare_field\fR \- \fIend_compare_field\fR
.sp
\fBTRACEFS_SYNTH_ADD\fR \- Add the content of the \fIstart_compare_field\fR to the content of the \fIend_compare_field\fR\&.
.sp
\fIname\fR = \fIstart_compare_field\fR + \fIend_compare_field\fR
.sp
\fBtracefs_synth_add_start_field\fR() \- Records the \fIstart_field\fR of the starting event as \fIname\fR in the synthetic event\&. If \fIname\fR is NULL, then the name used will be the same as \fIstart_field\fR\&.
.sp
\fBtracefs_synth_add_end_field\fR() \- Records the \fIend_field\fR of the ending event as \fIname\fR in the synthetic event\&. If \fIname\fR is NULL, then the name used will be the same as \fIend_field\fR\&.
.sp
\fBtracefs_synth_append_start_filter\fR() creates a filter or appends to it for the starting event\&. Depending on \fItype\fR, it will build a string of tokens for parenthesis or logic statements, or it may add a comparison of \fIfield\fR to \fIval\fR based on \fIcompare\fR\&.
.sp
If \fItype\fR is: \fBTRACEFS_FILTER_COMPARE\fR \- See below \fBTRACEFS_FILTER_AND\fR \- Append "&&" to the filter \fBTRACEFS_FILTER_OR\fR \- Append "||" to the filter \fBTRACEFS_FILTER_NOT\fR \- Append "!" to the filter \fBTRACEFS_FILTER_OPEN_PAREN\fR \- Append "(" to the filter \fBTRACEFS_FILTER_CLOSE_PAREN\fR \- Append ")" to the filter
.sp
\fIfield\fR, \fIcompare\fR, and \fIval\fR are ignored unless \fItype\fR is equal to \fBTRACEFS_FILTER_COMPARE\fR, then _compare will be used for the following:
.sp
\fBTRACEFS_COMPARE_EQ\fR \- \fIfield\fR == \fIval\fR
.sp
\fBTRACEFS_COMPARE_NE\fR \- \fIfield\fR != \fIval\fR
.sp
\fBTRACEFS_COMPARE_GT\fR \- \fIfield\fR > \fIval\fR
.sp
\fBTRACEFS_COMPARE_GE\fR \- \fIfield\fR >= \fIval\fR
.sp
\fBTRACEFS_COMPARE_LT\fR \- \fIfield\fR < \fIval\fR
.sp
\fBTRACEFS_COMPARE_LE\fR \- \fIfield\fR <= \fIval\fR
.sp
\fBTRACEFS_COMPARE_RE\fR \- \fIfield\fR ~ "\fIval\fR" : where \fIfield\fR is a string\&.
.sp
\fBTRACEFS_COMPARE_AND\fR \- \fIfield\fR & \fIval\fR : where \fIfield\fR is a flags field\&.
.sp
\fBtracefs_synth_append_end_filter\fR() is the same as \fBtracefs_synth_append_start_filter\fR but filters on the ending event\&.
.sp
\fBtracefs_synth_free\fR() frees the allocated descriptor returned by \fBtracefs_synth_alloc\fR()\&.
.SH "RETURN VALUE"
.sp
\fBtracefs_synth_alloc\fR() returns an allocated struct tracefs_synth descriptor on success or NULL on error\&.
.sp
All other functions that return an integer returns zero on success or \-1 on error\&.
.SH "ERRORS"
.sp
The following errors are for all the above calls:
.sp
\fBEPERM\fR Not run as root user when required\&.
.sp
\fBEINVAL\fR Either a parameter is not valid (NULL when it should not be) or a field that is not compatible for calculations\&.
.sp
\fBENODEV\fR An event or one of its fields is not found\&.
.sp
\fBEBADE\fR The fields of the start and end events are not compatible for either matching or comparing\&.
.sp
\fBENOMEM\fR not enough memory is available\&.
.sp
And more errors may have happened from the system calls to the system\&.
.SH "EXAMPLE"
.sp
.if n \{\
.RS 4
.\}
.nf
#include
#include
#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\*(Aqs 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\*(Aqs 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]\en", argv[0]);
exit(\-1);
}
} else
show_event();
tracefs_synth_free(synth);
return 0;
}
.fi
.if n \{\
.RE
.\}
.SH "FILES"
.sp
.if n \{\
.RS 4
.\}
.nf
\fBtracefs\&.h\fR
Header file to include in order to have access to the library APIs\&.
\fB\-ltracefs\fR
Linker switch to add when building a program that uses the library\&.
.fi
.if n \{\
.RE
.\}
.SH "SEE ALSO"
.sp
\fBtracefs_synth_create\fR(3), \fBtracefs_synth_destroy\fR(3), \fBtracfes_synth_echo_cmd\fR(3), \fBlibtracefs\fR(3), \fBlibtraceevent\fR(3), \fBtrace\-cmd\fR(1), \fBtracefs_hist_alloc\fR(3), \fBtracefs_hist_alloc_2d\fR(3), \fBtracefs_hist_alloc_nd\fR(3), \fBtracefs_hist_free\fR(3), \fBtracefs_hist_add_key\fR(3), \fBtracefs_hist_add_value\fR(3), \fBtracefs_hist_add_name\fR(3), \fBtracefs_hist_start\fR(3), \fBtracefs_hist_destory\fR(3), \fBtracefs_hist_add_sort_key\fR(3), \fBtracefs_hist_sort_key_direction\fR(3), \fBtracefs_synth_create\fR(3), \fBtracefs_synth_destroy\fR(3), \fBtracefs_synth_complete\fR(3), \fBtracefs_synth_trace\fR(3), \fBtracefs_synth_snapshot\fR(3), \fBtracefs_synth_save\fR(3), \fBtracefs_synth_echo_cmd\fR(3), \fBtracefs_synth_get_start_hist\fR(3), \fBtracefs_synth_get_name\fR(3), \fBtracefs_synth_raw_fmt\fR(3), \fBtracefs_synth_show_event\fR(3), \fBtracefs_synth_show_start_hist\fR(3), \fBtracefs_synth_show_end_hist\fR(3), \fBtracefs_synth_get_event\fR(3),
.SH "AUTHOR"
.sp
.if n \{\
.RS 4
.\}
.nf
\fBSteven Rostedt\fR <\m[blue]\fBrostedt@goodmis\&.org\fR\m[]\&\s-2\u[1]\d\s+2>
\fBTzvetomir Stoyanov\fR <\m[blue]\fBtz\&.stoyanov@gmail\&.com\fR\m[]\&\s-2\u[2]\d\s+2>
\fBsameeruddin shaik\fR <\m[blue]\fBsameeruddin\&.shaik8@gmail\&.com\fR\m[]\&\s-2\u[3]\d\s+2>
.fi
.if n \{\
.RE
.\}
.SH "REPORTING BUGS"
.sp
Report bugs to <\m[blue]\fBlinux\-trace\-devel@vger\&.kernel\&.org\fR\m[]\&\s-2\u[4]\d\s+2>
.SH "LICENSE"
.sp
libtracefs is Free Software licensed under the GNU LGPL 2\&.1
.SH "RESOURCES"
.sp
\m[blue]\fBhttps://git\&.kernel\&.org/pub/scm/libs/libtrace/libtracefs\&.git/\fR\m[]
.SH "COPYING"
.sp
Copyright (C) 2020 VMware, Inc\&. Free use of this software is granted under the terms of the GNU Public License (GPL)\&.
.SH "NOTES"
.IP " 1." 4
rostedt@goodmis.org
.RS 4
\%mailto:rostedt@goodmis.org
.RE
.IP " 2." 4
tz.stoyanov@gmail.com
.RS 4
\%mailto:tz.stoyanov@gmail.com
.RE
.IP " 3." 4
sameeruddin.shaik8@gmail.com
.RS 4
\%mailto:sameeruddin.shaik8@gmail.com
.RE
.IP " 4." 4
linux-trace-devel@vger.kernel.org
.RS 4
\%mailto:linux-trace-devel@vger.kernel.org
.RE