'\" 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_create, tracefs_synth_destroy, tracefs_synth_complete, tracefs_synth_trace, tracefs_synth_snapshot, tracefs_synth_save, tracefs_synth_set_instance, \- Creation of synthetic events .SH "SYNOPSIS" .sp .nf \fB#include \fR int \fBtracefs_synth_create\fR(struct tracefs_synth *\fIsynth\fR); int \fBtracefs_synth_destroy\fR(struct tracefs_synth *\fIsynth\fR); bool \fBtracefs_synth_complete\fR(struct tracefs_synth *\fIsynth\fR); int \fBtracefs_synth_set_instance\fR(struct tracefs_synth *\fIsynth\fR, struct tracefs_instance *\fIinstance\fR); int \fBtracefs_synth_trace\fR(struct tracefs_synth *\fIsynth\fR, enum tracefs_synth_handler \fItype\fR, const char *\fIvar\fR); int \fBtracefs_synth_snapshot\fR(struct tracefs_synth *\fIsynth\fR, enum tracefs_synth_handler \fItype\fR, const char *\fIvar\fR); int \fBtracefs_synth_save\fR(struct tracefs_synth *\fIsynth\fR, enum tracefs_synth_handler \fItype\fR, const char *\fIvar\fR, char **\fIsave_fields\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 \fBTRACEFS_TIMESTAMP_USECS\fR as the compare fields for both events to calculate the delta in microseconds\&. This is used as the example below\&. .sp \fBtracefs_synth_create\fR() creates the synthetic event in the system\&. By default, the histogram triggers are created in the top trace instance, as any synthetic event can be used globally across all instances\&. In case an application wants to keep the histogram triggers out of the top level instance, it can use \fBtracefs_synth_set_instance()\fR to have the histograms used for creating the synthetic event in an instance other than the top level\&. A synthetic event descriptor must be created with \fBtracefs_synth_alloc\fR(3) before this can be used to create it on the system\&. .sp \fBtracefs_synth_destroy\fR() destroys the synthetic event\&. It will attempt to stop the running of it in its instance (top by default), but if its running in another instance this may fail as busy\&. .sp \fBtracefs_synth_complete\fR() returns true if the synthetic event \fIsynth\fR has both a starting and ending event\&. .sp \fBtracefs_synth_trace\fR() Instead of doing just a trace on matching of the start and end events, do the \fItype\fR handler where \fBTRACEFS_SYNTH_HANDLE_MAX\fR will do a trace when the given variable \fIvar\fR hits a new max for the matching keys\&. Or \fBTRACEFS_SYNTH_HANDLE_CHANGE\fR for when the \fIvar\fR changes\&. \fIvar\fR must be one of the \fIname\fR elements used in \fBtracefs_synth_add_end_field\fR(3)\&. .sp \fBtracefs_synth_snapshot\fR() When the given variable \fIvar\fR is either a new max if \fIhandler\fR is \fBTRACEFS_SYNTH_HANDLE_MAX\fR or simply changed if \fBTRACEFS_SYNTH_HANDLE_CHANGE\fR then take a "snapshot" of the buffer\&. The snapshot moves the normal "trace" buffer into a "snapshot" buffer, that can be accessed via the "snapshot" file in the top level tracefs directory, or one of the instances\&. \fIvar\fR changes\&. \fIvar\fR must be one of the \fIname\fR elements used in \fBtracefs_synth_add_end_field\fR(3)\&. .sp \fBtracefs_synth_save\fR() When the given variable \fIvar\fR is either a new max if \fIhandler\fR is \fBTRACEFS_SYNTH_HANDLE_MAX\fR or simpy changed if \fBTRACEFS_SYNTH_HANDLE_CHANGE\fR then save the given \fIsave_fields\fR list\&. The fields will be stored in the histogram "hist" file of the event that can be retrieved with \fBtracefs_event_file_read\fR(3)\&. \fIvar\fR must be one of the \fIname\fR elements used in \fBtracefs_synth_add_end_field\fR(3)\&. .sp \fBtracefs_synth_set_instance()\fR Set the trace instance, where the histogram triggers that create the synthetic event will be created\&. By default, the top instance is used\&. This API must be called before the call to \fBtracefs_synth_create()\fR, in order to use the new instance when creating the event\&. Note, that even if the synthetic event is created in an instance, it is still visible by all other instances including the top level\&. That is, other instances can enable the created synthetic event and have it traced in the buffers that belong to the instance that enabled it\&. .SH "RETURN VALUE" .sp All functions return 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 See \fBtracefs_sql\fR(3) for a more indepth use of some of this code\&. .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 \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_alloc\fR(3), \fBtracefs_synth_add_match_field\fR(3), \fBtracefs_synth_add_compare_field\fR(3), \fBtracefs_synth_add_start_field\fR(3), \fBtracefs_synth_add_end_field\fR(3), \fBtracefs_synth_append_start_filter\fR(3), \fBtracefs_synth_append_end_filter\fR(3), \fBtracefs_synth_free\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