1libtracefs(3) 2============= 3 4NAME 5---- 6tracefs_synth_alloc, tracefs_synth_add_match_field, tracefs_synth_add_compare_field, tracefs_synth_add_start_field, 7tracefs_synth_add_end_field, tracefs_synth_append_start_filter, tracefs_synth_append_end_filter, tracefs_synth_free, 8- Creation of a synthetic event descriptor 9 10SYNOPSIS 11-------- 12[verse] 13-- 14*#include <tracefs.h>* 15 16struct tracefs_synth pass:[*]*tracefs_synth_alloc*(struct tep_handle pass:[*]_tep_, 17 const char pass:[*]_name_, 18 const char pass:[*]_start_system_, 19 const char pass:[*]_start_event_, 20 const char pass:[*]_end_system_, 21 const char pass:[*]_end_event_, 22 const char pass:[*]_start_match_field_, 23 const char pass:[*]_end_match_field_, 24 const char pass:[*]_match_name_); 25int *tracefs_synth_add_match_field*(struct tracefs_synth pass:[*]_synth_, 26 const char pass:[*]_start_match_field_, 27 const char pass:[*]_end_match_field_, 28 const char pass:[*]_name_); 29int *tracefs_synth_add_compare_field*(struct tracefs_synth pass:[*]_synth_, 30 const char pass:[*]_start_compare_field_, 31 const char pass:[*]_end_compare_field_, 32 enum tracefs_synth_calc _calc_, 33 const char pass:[*]_name_); 34int *tracefs_synth_add_start_field*(struct tracefs_synth pass:[*]_synth_, 35 const char pass:[*]_start_field_, 36 const char pass:[*]_name_); 37int *tracefs_synth_add_end_field*(struct tracefs_synth pass:[*]_synth_, 38 const char pass:[*]_end_field_, 39 const char pass:[*]_name_); 40int *tracefs_synth_append_start_filter*(struct tracefs_synth pass:[*]_synth_, 41 struct tracefs_filter _type_, 42 const char pass:[*]_field_, 43 enum tracefs_synth_compare _compare_, 44 const char pass:[*]_val_); 45int *tracefs_synth_append_end_filter*(struct tracefs_synth pass:[*]_synth_, 46 struct tracefs_filter _type_, 47 const char pass:[*]_field_, 48 enum tracefs_synth_compare _compare_, 49 const char pass:[*]_val_); 50void *tracefs_synth_free*(struct tracefs_synth pass:[*]_synth_); 51-- 52 53DESCRIPTION 54----------- 55Synthetic events are dynamic events that are created by matching 56two other events which triggers a synthetic event. One event is the starting 57event which some field is recorded, and when the second event is executed, 58if it has a field (or fields) that matches the starting event's field (or fields) 59then it will trigger the synthetic event. The field values other than the matching 60fields may be passed from the starting event to the end event to perform calculations 61on, or to simply pass as a parameter to the synthetic event. 62 63One common use case is to set "sched_waking" as the starting event. This event is 64triggered when a process is awoken. Then set "sched_switch" as the ending event. 65This event is triggered when a new task is scheduled on the CPU. By setting 66the "common_pid" of both events as the matching fields, the time between the 67two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP* 68as a field for both events to calculate the delta in nanoseconds, or use 69*TRACEFS_TIMESTAMP_USECS" as the compare fields for both events to calculate the 70delta in microseconds. This is used as the example below. 71 72*tracefs_synth_alloc*() allocates and initializes a synthetic event. 73It does not create the synthetic event, but supplies the minimal information 74to do so. See *tracefs_synth_create*(3) for how to create the synthetic 75event in the system. It requires a _tep_ handler that can be created by 76*tracefs_local_events*(3) for more information. The _name_ holds the name 77of the synthetic event that will be created. The _start_system_ is the name 78of the system for the starting event. It may be NULL and the first event 79with the name of _start_event_ will be chosen. The _end_system_ is the 80name of the system for theh ending event. It may be NULL and the first event 81with the name of _end_event_ will be chosen as the ending event. If _match_name_ 82is given, then this will be the field of the created synthetic event that 83holds the matching keys of the starting event's _start_match_field_ and 84the ending event's _end_match_field_. If _match_name_ is NULL, then it will 85not be recorded in the created synthetic event. 86 87*tracefs_synth_add_match_field*() will add a second key to match between the 88starting event and the ending event. If _name_ is given, then the content 89of the matching field will be saved by this _name_ in the synthetic event. 90The _start_match_field_ is the field of the starting event to mach with the 91ending event's _end_match_field_. 92 93*tracefs_synth_add_compare_field*() is used to compare the _start_compare_field_ 94of the starting event with the _end_compare_field_ of the ending event. The _name_ 95must be given so that the result will be saved by the synthetic event. It makes 96no sense to not pass this to the synthetic event after doing the work of 97the compared fields, as it serves no other purpose. The _calc_ parameter 98can be one of: 99 100*TRACEFS_SYNTH_DELTA_END* - calculate the difference between the content in 101 the _end_compare_field_ from the content of the _start_compare_field_. 102 103_name_ = _end_compare_field_ - _start_compare_field_ 104 105*TRACEFS_SYNTH_DELTA_START* - calculate the difference between the content in 106 the _start_compare_field_ from the content of the _end_compare_field_. 107 108_name_ = _start_compare_field_ - _end_compare_field_ 109 110*TRACEFS_SYNTH_ADD* - Add the content of the _start_compare_field_ to the 111 content of the _end_compare_field_. 112 113_name_ = _start_compare_field_ + _end_compare_field_ 114 115*tracefs_synth_add_start_field*() - Records the _start_field_ of the starting 116event as _name_ in the synthetic event. If _name_ is NULL, then the name used 117will be the same as _start_field_. 118 119*tracefs_synth_add_end_field*() - Records the _end_field_ of the ending 120event as _name_ in the synthetic event. If _name_ is NULL, then the name used 121will be the same as _end_field_. 122 123*tracefs_synth_append_start_filter*() creates a filter or appends to it for the 124starting event. Depending on _type_, it will build a string of tokens for 125parenthesis or logic statements, or it may add a comparison of _field_ 126to _val_ based on _compare_. 127 128If _type_ is: 129*TRACEFS_FILTER_COMPARE* - See below 130*TRACEFS_FILTER_AND* - Append "&&" to the filter 131*TRACEFS_FILTER_OR* - Append "||" to the filter 132*TRACEFS_FILTER_NOT* - Append "!" to the filter 133*TRACEFS_FILTER_OPEN_PAREN* - Append "(" to the filter 134*TRACEFS_FILTER_CLOSE_PAREN* - Append ")" to the filter 135 136_field_, _compare_, and _val_ are ignored unless _type_ is equal to 137*TRACEFS_FILTER_COMPARE*, then _compare will be used for the following: 138 139*TRACEFS_COMPARE_EQ* - _field_ == _val_ 140 141*TRACEFS_COMPARE_NE* - _field_ != _val_ 142 143*TRACEFS_COMPARE_GT* - _field_ > _val_ 144 145*TRACEFS_COMPARE_GE* - _field_ >= _val_ 146 147*TRACEFS_COMPARE_LT* - _field_ < _val_ 148 149*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_ 150 151*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string. 152 153*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field. 154 155*tracefs_synth_append_end_filter*() is the same as *tracefs_synth_append_start_filter* but 156filters on the ending event. 157 158*tracefs_synth_free*() frees the allocated descriptor returned by 159*tracefs_synth_alloc*(). 160 161RETURN VALUE 162------------ 163*tracefs_synth_alloc*() returns an allocated struct tracefs_synth descriptor 164on success or NULL on error. 165 166All other functions that return an integer returns zero on success or -1 167on error. 168 169ERRORS 170------ 171The following errors are for all the above calls: 172 173*EPERM* Not run as root user when required. 174 175*EINVAL* Either a parameter is not valid (NULL when it should not be) 176 or a field that is not compatible for calculations. 177 178*ENODEV* An event or one of its fields is not found. 179 180*EBADE* The fields of the start and end events are not compatible for 181 either matching or comparing. 182 183*ENOMEM* not enough memory is available. 184 185And more errors may have happened from the system calls to the system. 186 187EXAMPLE 188------- 189[source,c] 190-- 191#include <stdlib.h> 192#include <tracefs.h> 193 194#define start_event "sched_waking" 195#define start_field "pid" 196 197#define end_event "sched_switch" 198#define end_field "next_pid" 199 200#define match_name "pid" 201 202static struct tracefs_synth *synth; 203 204static void make_event(void) 205{ 206 struct tep_handle *tep; 207 208 /* Load all events from the system */ 209 tep = tracefs_local_events(NULL); 210 211 /* Initialize the synthetic event */ 212 synth = tracefs_synth_alloc(tep, "wakeup_lat", 213 NULL, start_event, 214 NULL, end_event, 215 start_field, end_field, 216 match_name); 217 218 /* The tep is no longer needed */ 219 tep_free(tep); 220 221 222 /* Save the "prio" field as "prio" from the start event */ 223 tracefs_synth_add_start_field(synth, "prio", NULL); 224 225 /* Save the "next_comm" as "comm" from the end event */ 226 tracefs_synth_add_end_field(synth, "next_comm", "comm"); 227 228 /* Save the "prev_prio" as "prev_prio" from the end event */ 229 tracefs_synth_add_end_field(synth, "prev_prio", NULL); 230 231 /* 232 * Take a microsecond time difference between end and start 233 * and record as "delta" 234 */ 235 tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS, 236 TRACEFS_TIMESTAMP_USECS, 237 TRACEFS_SYNTH_DELTA_END, "delta"); 238 239 /* Only record if start event "prio" is less than 100 */ 240 tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE, 241 "prio", TRACEFS_COMPARE_LT, "100"); 242 243 /* 244 * Only record if end event "next_prio" is less than 50 245 * or the previous task's prio was not greater than or equal to 100. 246 * next_prio < 50 || !(prev_prio >= 100) 247 */ 248 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, 249 "next_prio", TRACEFS_COMPARE_LT, "50"); 250 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL); 251 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL); 252 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL); 253 tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE, 254 "prev_prio", TRACEFS_COMPARE_GE, "100"); 255 /* 256 * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100" 257 * That's because, when the synth is executed, the remaining close parenthesis 258 * will be added. That is, the string will end up being: 259 * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create() 260 * or tracefs_sync_echo_cmd() is run. 261 */ 262} 263 264/* Display how to create the synthetic event */ 265static void show_event(void) 266{ 267 struct trace_seq s; 268 269 trace_seq_init(&s); 270 271 tracefs_synth_echo_cmd(&s, synth); 272 trace_seq_terminate(&s); 273 trace_seq_do_printf(&s); 274 trace_seq_destroy(&s); 275} 276 277int main (int argc, char **argv) 278{ 279 make_event(); 280 281 if (argc > 1) { 282 if (!strcmp(argv[1], "create")) { 283 /* Create the synthetic event */ 284 tracefs_synth_create(synth); 285 } else if (!strcmp(argv[1], "delete")) { 286 /* Delete the synthetic event */ 287 tracefs_synth_destroy(synth); 288 } else { 289 printf("usage: %s [create|delete]\n", argv[0]); 290 exit(-1); 291 } 292 } else 293 show_event(); 294 295 tracefs_synth_free(synth); 296 297 return 0; 298} 299-- 300 301FILES 302----- 303[verse] 304-- 305*tracefs.h* 306 Header file to include in order to have access to the library APIs. 307*-ltracefs* 308 Linker switch to add when building a program that uses the library. 309-- 310 311SEE ALSO 312-------- 313*tracefs_synth_create*(3), 314*tracefs_synth_destroy*(3), 315*tracfes_synth_echo_cmd*(3), 316*libtracefs*(3), 317*libtraceevent*(3), 318*trace-cmd*(1), 319*tracefs_hist_alloc*(3), 320*tracefs_hist_alloc_2d*(3), 321*tracefs_hist_alloc_nd*(3), 322*tracefs_hist_free*(3), 323*tracefs_hist_add_key*(3), 324*tracefs_hist_add_value*(3), 325*tracefs_hist_add_name*(3), 326*tracefs_hist_start*(3), 327*tracefs_hist_destory*(3), 328*tracefs_hist_add_sort_key*(3), 329*tracefs_hist_sort_key_direction*(3), 330*tracefs_synth_create*(3), 331*tracefs_synth_destroy*(3), 332*tracefs_synth_complete*(3), 333*tracefs_synth_trace*(3), 334*tracefs_synth_snapshot*(3), 335*tracefs_synth_save*(3), 336*tracefs_synth_echo_cmd*(3), 337*tracefs_synth_get_start_hist*(3), 338*tracefs_synth_get_name*(3), 339*tracefs_synth_raw_fmt*(3), 340*tracefs_synth_show_event*(3), 341*tracefs_synth_show_start_hist*(3), 342*tracefs_synth_show_end_hist*(3), 343*tracefs_synth_get_event*(3), 344 345AUTHOR 346------ 347[verse] 348-- 349*Steven Rostedt* <[email protected]> 350*Tzvetomir Stoyanov* <[email protected]> 351*sameeruddin shaik* <[email protected]> 352-- 353REPORTING BUGS 354-------------- 355Report bugs to <[email protected]> 356 357LICENSE 358------- 359libtracefs is Free Software licensed under the GNU LGPL 2.1 360 361RESOURCES 362--------- 363https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 364 365COPYING 366------- 367Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 368the terms of the GNU Public License (GPL). 369