1libtracefs(3) 2============= 3 4NAME 5---- 6tracefs_synth_create, tracefs_synth_destroy, tracefs_synth_complete, 7tracefs_synth_trace, tracefs_synth_snapshot, tracefs_synth_save 8- Creation of synthetic events 9 10SYNOPSIS 11-------- 12[verse] 13-- 14*#include <tracefs.h>* 15 16int *tracefs_synth_create*(struct tracefs_synth pass:[*]_synth_); 17int *tracefs_synth_destroy*(struct tracefs_synth pass:[*]_synth_); 18bool *tracefs_synth_complete*(struct tracefs_synth pass:[*]_synth_); 19 20int *tracefs_synth_trace*(struct tracefs_synth pass:[*]_synth_, 21 enum tracefs_synth_handler _type_, const char pass:[*]_var_); 22int *tracefs_synth_snapshot*(struct tracefs_synth pass:[*]_synth_, 23 enum tracefs_synth_handler _type_, const char pass:[*]_var_); 24int *tracefs_synth_save*(struct tracefs_synth pass:[*]_synth_, 25 enum tracefs_synth_handler _type_, const char pass:[*]_var_, 26 char pass:[**]_save_fields_); 27-- 28 29DESCRIPTION 30----------- 31Synthetic events are dynamic events that are created by matching 32two other events which triggers a synthetic event. One event is the starting 33event which some field is recorded, and when the second event is executed, 34if it has a field (or fields) that matches the starting event's field (or fields) 35then it will trigger the synthetic event. The field values other than the matching 36fields may be passed from the starting event to the end event to perform calculations 37on, or to simply pass as a parameter to the synthetic event. 38 39One common use case is to set "sched_waking" as the starting event. This event is 40triggered when a process is awoken. Then set "sched_switch" as the ending event. 41This event is triggered when a new task is scheduled on the CPU. By setting 42the "common_pid" of both events as the matching fields, the time between the 43two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP* 44as a field for both events to calculate the delta in nanoseconds, or use 45*TRACEFS_TIMESTAMP_USECS* as the compare fields for both events to calculate the 46delta in microseconds. This is used as the example below. 47 48*tracefs_synth_create*() creates the synthetic event in the system. The synthetic events apply 49across all instances. A synthetic event must be created with *tracefs_synth_alloc*(3) before 50it can be created. 51 52*tracefs_synth_destroy*() destroys the synthetic event. It will attempt to stop the running of it in 53its instance (top by default), but if its running in another instance this may fail as busy. 54 55*tracefs_synth_complete*() returns true if the synthetic event _synth_ has both 56a starting and ending event. 57 58*tracefs_synth_trace*() Instead of doing just a trace on matching of the start and 59end events, do the _type_ handler where *TRACEFS_SYNTH_HANDLE_MAX* will do a trace 60when the given variable _var_ hits a new max for the matching keys. Or 61*TRACEFS_SYNTH_HANDLE_CHANGE* for when the _var_ changes. _var_ must be one of 62the _name_ elements used in *tracefs_synth_add_end_field*(3). 63 64*tracefs_synth_snapshot*() When the given variable _var_ is either a new max if 65_handler_ is *TRACEFS_SYNTH_HANDLE_MAX* or simply changed if *TRACEFS_SYNTH_HANDLE_CHANGE* 66then take a "snapshot" of the buffer. The snapshot moves the normal "trace" buffer 67into a "snapshot" buffer, that can be accessed via the "snapshot" file in the 68top level tracefs directory, or one of the instances. _var_ changes. _var_ must be one of 69the _name_ elements used in *tracefs_synth_add_end_field*(3). 70 71*tracefs_synth_save*() When the given variable _var_ is either a new max if 72_handler_ is *TRACEFS_SYNTH_HANDLE_MAX* or simpy changed if *TRACEFS_SYNTH_HANDLE_CHANGE* 73then save the given _save_fields_ list. The fields will be stored in the histogram 74"hist" file of the event that can be retrieved with *tracefs_event_file_read*(3). 75_var_ must be one of the _name_ elements used in *tracefs_synth_add_end_field*(3). 76 77RETURN VALUE 78------------ 79All functions return zero on success or -1 on error. 80 81ERRORS 82------ 83The following errors are for all the above calls: 84 85*EPERM* Not run as root user when required. 86 87*EINVAL* Either a parameter is not valid (NULL when it should not be) 88 or a field that is not compatible for calculations. 89 90*ENODEV* An event or one of its fields is not found. 91 92*EBADE* The fields of the start and end events are not compatible for 93 either matching or comparing. 94 95*ENOMEM* not enough memory is available. 96 97And more errors may have happened from the system calls to the system. 98 99EXAMPLE 100------- 101See *tracefs_sql*(3) for a more indepth use of some of this code. 102 103[source,c] 104-- 105#include <stdlib.h> 106#include <tracefs.h> 107 108#define start_event "sched_waking" 109#define start_field "pid" 110 111#define end_event "sched_switch" 112#define end_field "next_pid" 113 114#define match_name "pid" 115 116static struct tracefs_synth *synth; 117 118static void make_event(void) 119{ 120 struct tep_handle *tep; 121 122 /* Load all events from the system */ 123 tep = tracefs_local_events(NULL); 124 125 /* Initialize the synthetic event */ 126 synth = tracefs_synth_alloc(tep, "wakeup_lat", 127 NULL, start_event, 128 NULL, end_event, 129 start_field, end_field, 130 match_name); 131 132 /* The tep is no longer needed */ 133 tep_free(tep); 134 135 136 /* Save the "prio" field as "prio" from the start event */ 137 tracefs_synth_add_start_field(synth, "prio", NULL); 138 139 /* Save the "next_comm" as "comm" from the end event */ 140 tracefs_synth_add_end_field(synth, "next_comm", "comm"); 141 142 /* Save the "prev_prio" as "prev_prio" from the end event */ 143 tracefs_synth_add_end_field(synth, "prev_prio", NULL); 144 145 /* 146 * Take a microsecond time difference between end and start 147 * and record as "delta" 148 */ 149 tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS, 150 TRACEFS_TIMESTAMP_USECS, 151 TRACEFS_SYNTH_DELTA_END, "delta"); 152 153 /* Only record if start event "prio" is less than 100 */ 154 tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE, 155 "prio", TRACEFS_COMPARE_LT, "100"); 156 157 /* 158 * Only record if end event "next_prio" is less than 50 159 * or the previous task's prio was not greater than or equal to 100. 160 * next_prio < 50 || !(prev_prio >= 100) 161 */ 162 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, 163 "next_prio", TRACEFS_COMPARE_LT, "50"); 164 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL); 165 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL); 166 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL); 167 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, 168 "prev_prio", TRACEFS_COMPARE_GE, "100"); 169 /* 170 * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100" 171 * That's because, when the synth is executed, the remaining close parenthesis 172 * will be added. That is, the string will end up being: 173 * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create() 174 * or tracefs_sync_echo_cmd() is run. 175 */ 176} 177 178/* Display how to create the synthetic event */ 179static void show_event(void) 180{ 181 struct trace_seq s; 182 183 trace_seq_init(&s); 184 185 tracefs_synth_echo_cmd(&s, synth); 186 trace_seq_terminate(&s); 187 trace_seq_do_printf(&s); 188 trace_seq_destroy(&s); 189} 190 191int main (int argc, char **argv) 192{ 193 make_event(); 194 195 if (argc > 1) { 196 if (!strcmp(argv[1], "create")) { 197 /* Create the synthetic event */ 198 tracefs_synth_create(synth); 199 } else if (!strcmp(argv[1], "delete")) { 200 /* Delete the synthetic event */ 201 tracefs_synth_destroy(synth); 202 } else { 203 printf("usage: %s [create|delete]\n", argv[0]); 204 exit(-1); 205 } 206 } else 207 show_event(); 208 209 tracefs_synth_free(synth); 210 211 return 0; 212} 213-- 214 215FILES 216----- 217[verse] 218-- 219*tracefs.h* 220 Header file to include in order to have access to the library APIs. 221*-ltracefs* 222 Linker switch to add when building a program that uses the library. 223-- 224 225SEE ALSO 226-------- 227*libtracefs*(3), 228*libtraceevent*(3), 229*trace-cmd*(1), 230*tracefs_hist_alloc*(3), 231*tracefs_hist_alloc_2d*(3), 232*tracefs_hist_alloc_nd*(3), 233*tracefs_hist_free*(3), 234*tracefs_hist_add_key*(3), 235*tracefs_hist_add_value*(3), 236*tracefs_hist_add_name*(3), 237*tracefs_hist_start*(3), 238*tracefs_hist_destory*(3), 239*tracefs_hist_add_sort_key*(3), 240*tracefs_hist_sort_key_direction*(3), 241*tracefs_synth_alloc*(3), 242*tracefs_synth_add_match_field*(3), 243*tracefs_synth_add_compare_field*(3), 244*tracefs_synth_add_start_field*(3), 245*tracefs_synth_add_end_field*(3), 246*tracefs_synth_append_start_filter*(3), 247*tracefs_synth_append_end_filter*(3), 248*tracefs_synth_free*(3), 249*tracefs_synth_echo_cmd*(3), 250*tracefs_synth_get_start_hist*(3), 251*tracefs_synth_get_name*(3), 252*tracefs_synth_raw_fmt*(3), 253*tracefs_synth_show_event*(3), 254*tracefs_synth_show_start_hist*(3), 255*tracefs_synth_show_end_hist*(3), 256*tracefs_synth_get_event*(3), 257 258AUTHOR 259------ 260[verse] 261-- 262*Steven Rostedt* <rostedt@goodmis.org> 263*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com> 264*sameeruddin shaik* <sameeruddin.shaik8@gmail.com> 265-- 266REPORTING BUGS 267-------------- 268Report bugs to <linux-trace-devel@vger.kernel.org> 269 270LICENSE 271------- 272libtracefs is Free Software licensed under the GNU LGPL 2.1 273 274RESOURCES 275--------- 276https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 277 278COPYING 279------- 280Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 281the terms of the GNU Public License (GPL). 282