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