1*287e80b3SSadaf Ebrahimilibtracefs(3) 2*287e80b3SSadaf Ebrahimi============= 3*287e80b3SSadaf Ebrahimi 4*287e80b3SSadaf EbrahimiNAME 5*287e80b3SSadaf Ebrahimi---- 6*287e80b3SSadaf Ebrahimitracefs_sql - Create a synthetic event via an SQL statement 7*287e80b3SSadaf Ebrahimi 8*287e80b3SSadaf EbrahimiSYNOPSIS 9*287e80b3SSadaf Ebrahimi-------- 10*287e80b3SSadaf Ebrahimi[verse] 11*287e80b3SSadaf Ebrahimi-- 12*287e80b3SSadaf Ebrahimi*#include <tracefs.h>* 13*287e80b3SSadaf Ebrahimi 14*287e80b3SSadaf Ebrahimistruct tracefs_synth pass:[*]*tracefs_sql*(struct tep_handle pass:[*]_tep_, const char pass:[*]_name_, 15*287e80b3SSadaf Ebrahimi const char pass:[*]_sql_buffer_, char pass:[**]_err_); 16*287e80b3SSadaf Ebrahimi-- 17*287e80b3SSadaf Ebrahimi 18*287e80b3SSadaf EbrahimiDESCRIPTION 19*287e80b3SSadaf Ebrahimi----------- 20*287e80b3SSadaf EbrahimiSynthetic events are dynamically created events that attach two existing events 21*287e80b3SSadaf Ebrahimitogether via one or more matching fields between the two events. It can be used 22*287e80b3SSadaf Ebrahimito find the latency between the events, or to simply pass fields of the first event 23*287e80b3SSadaf Ebrahimion to the second event to display as one event. 24*287e80b3SSadaf Ebrahimi 25*287e80b3SSadaf EbrahimiThe Linux kernel interface to create synthetic events is complex, and there needs 26*287e80b3SSadaf Ebrahimito be a better way to create synthetic events that is easy and can be understood 27*287e80b3SSadaf Ebrahimivia existing technology. 28*287e80b3SSadaf Ebrahimi 29*287e80b3SSadaf EbrahimiIf you think of each event as a table, where the fields are the column of the table 30*287e80b3SSadaf Ebrahimiand each instance of the event as a row, you can understand how SQL can be used 31*287e80b3SSadaf Ebrahimito attach two events together and form another event (table). Utilizing the 32*287e80b3SSadaf EbrahimiSQL *SELECT* *FROM* *JOIN* *ON* [ *WHERE* ] syntax, a synthetic event can easily 33*287e80b3SSadaf Ebrahimibe created from two different events. 34*287e80b3SSadaf Ebrahimi 35*287e80b3SSadaf EbrahimiFor simple SQL queries to make a histogram instead of a synthetic event, see 36*287e80b3SSadaf EbrahimiHISTOGRAMS below. 37*287e80b3SSadaf Ebrahimi 38*287e80b3SSadaf Ebrahimi*tracefs_sql*() takes in a _tep_ handler (See _tep_local_events_(3)) that is used to 39*287e80b3SSadaf Ebrahimiverify the events within the _sql_buffer_ expression. The _name_ is the name of the 40*287e80b3SSadaf Ebrahimisynthetic event to create. If _err_ points to an address of a string, it will be filled 41*287e80b3SSadaf Ebrahimiwith a detailed message on any type of parsing error, including fields that do not belong 42*287e80b3SSadaf Ebrahimito an event, or if the events or fields are not properly compared. 43*287e80b3SSadaf Ebrahimi 44*287e80b3SSadaf EbrahimiThe example program below is a fully functional parser where it will create a synthetic 45*287e80b3SSadaf Ebrahimievent from a SQL syntax passed in via the command line or a file. 46*287e80b3SSadaf Ebrahimi 47*287e80b3SSadaf EbrahimiThe SQL format is as follows: 48*287e80b3SSadaf Ebrahimi 49*287e80b3SSadaf Ebrahimi*SELECT* <fields> *FROM* <start-event> *JOIN* <end-event> *ON* <matching-fields> *WHERE* <filter> 50*287e80b3SSadaf Ebrahimi 51*287e80b3SSadaf EbrahimiNote, although the examples show the SQL commands in uppercase, they are not required to 52*287e80b3SSadaf Ebrahimibe so. That is, you can use "SELECT" or "select" or "sElEct". 53*287e80b3SSadaf Ebrahimi 54*287e80b3SSadaf EbrahimiFor example: 55*287e80b3SSadaf Ebrahimi[source,c] 56*287e80b3SSadaf Ebrahimi-- 57*287e80b3SSadaf EbrahimiSELECT syscalls.sys_enter_read.fd, syscalls.sys_exit_read.ret FROM syscalls.sys_enter_read 58*287e80b3SSadaf Ebrahimi JOIN syscalls.sys_exit_read 59*287e80b3SSadaf Ebrahimi ON syscalls.sys_enter_read.common_pid = syscalls.sys_exit_write.common_pid 60*287e80b3SSadaf Ebrahimi-- 61*287e80b3SSadaf Ebrahimi 62*287e80b3SSadaf EbrahimiWill create a synthetic event that with the fields: 63*287e80b3SSadaf Ebrahimi 64*287e80b3SSadaf Ebrahimi u64 fd; s64 ret; 65*287e80b3SSadaf Ebrahimi 66*287e80b3SSadaf EbrahimiBecause the function takes a _tep_ handle, and usually all event names are unique, you can 67*287e80b3SSadaf Ebrahimileave off the system (group) name of the event, and *tracefs_sql*() will discover the 68*287e80b3SSadaf Ebrahimisystem for you. 69*287e80b3SSadaf Ebrahimi 70*287e80b3SSadaf EbrahimiThat is, the above statement would work with: 71*287e80b3SSadaf Ebrahimi 72*287e80b3SSadaf Ebrahimi[source,c] 73*287e80b3SSadaf Ebrahimi-- 74*287e80b3SSadaf EbrahimiSELECT sys_enter_read.fd, sys_exit_read.ret FROM sys_enter_read JOIN sys_exit_read 75*287e80b3SSadaf Ebrahimi ON sys_enter_read.common_pid = sys_exit_write.common_pid 76*287e80b3SSadaf Ebrahimi-- 77*287e80b3SSadaf Ebrahimi 78*287e80b3SSadaf EbrahimiThe *AS* keyword can be used to name the fields as well as to give an alias to the 79*287e80b3SSadaf Ebrahimievents, such that the above can be simplified even more as: 80*287e80b3SSadaf Ebrahimi 81*287e80b3SSadaf Ebrahimi[source,c] 82*287e80b3SSadaf Ebrahimi-- 83*287e80b3SSadaf EbrahimiSELECT start.fd, end.ret FROM sys_enter_read AS start JOIN sys_exit_read AS end ON start.common_pid = end.common_pid 84*287e80b3SSadaf Ebrahimi-- 85*287e80b3SSadaf Ebrahimi 86*287e80b3SSadaf EbrahimiThe above aliases _sys_enter_read_ as *start* and _sys_exit_read_ as *end* and uses 87*287e80b3SSadaf Ebrahimithose aliases to reference the event throughout the statement. 88*287e80b3SSadaf Ebrahimi 89*287e80b3SSadaf EbrahimiUsing the *AS* keyword in the selection portion of the SQL statement will define what 90*287e80b3SSadaf Ebrahimithose fields will be called in the synthetic event. 91*287e80b3SSadaf Ebrahimi 92*287e80b3SSadaf Ebrahimi[source,c] 93*287e80b3SSadaf Ebrahimi-- 94*287e80b3SSadaf EbrahimiSELECT start.fd AS filed, end.ret AS return FROM sys_enter_read AS start JOIN sys_exit_read AS end 95*287e80b3SSadaf Ebrahimi ON start.common_pid = end.common_pid 96*287e80b3SSadaf Ebrahimi-- 97*287e80b3SSadaf Ebrahimi 98*287e80b3SSadaf EbrahimiThe above labels the _fd_ of _start_ as *filed* and the _ret_ of _end_ as *return* where 99*287e80b3SSadaf Ebrahimithe synthetic event that is created will now have the fields: 100*287e80b3SSadaf Ebrahimi 101*287e80b3SSadaf Ebrahimi u64 filed; s64 return; 102*287e80b3SSadaf Ebrahimi 103*287e80b3SSadaf EbrahimiThe fields can also be calculated with results passed to the synthetic event: 104*287e80b3SSadaf Ebrahimi 105*287e80b3SSadaf Ebrahimi[source,c] 106*287e80b3SSadaf Ebrahimi-- 107*287e80b3SSadaf Ebrahimiselect start.truesize, end.len, (start.truesize - end.len) as diff from napi_gro_receive_entry as start 108*287e80b3SSadaf Ebrahimi JOIN netif_receive_skb as end ON start.skbaddr = end.skbaddr 109*287e80b3SSadaf Ebrahimi-- 110*287e80b3SSadaf Ebrahimi 111*287e80b3SSadaf EbrahimiWhich would show the *truesize* of the _napi_gro_receive_entry_ event, the actual 112*287e80b3SSadaf Ebrahimi_len_ of the content, shown by the _netif_receive_skb_, and the delta between 113*287e80b3SSadaf Ebrahimithe two and expressed by the field *diff*. 114*287e80b3SSadaf Ebrahimi 115*287e80b3SSadaf EbrahimiThe code also supports recording the timestamps at either event, and performing calculations 116*287e80b3SSadaf Ebrahimion them. For wakeup latency, you have: 117*287e80b3SSadaf Ebrahimi 118*287e80b3SSadaf Ebrahimi[source,c] 119*287e80b3SSadaf Ebrahimi-- 120*287e80b3SSadaf Ebrahimiselect start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start 121*287e80b3SSadaf Ebrahimi JOIN sched_switch as end ON start.pid = end.next_pid 122*287e80b3SSadaf Ebrahimi-- 123*287e80b3SSadaf Ebrahimi 124*287e80b3SSadaf EbrahimiThe above will create a synthetic event that records the _pid_ of the task being woken up, 125*287e80b3SSadaf Ebrahimiand the time difference between the _sched_waking_ event and the _sched_switch_ event. 126*287e80b3SSadaf EbrahimiThe *TIMESTAMP_USECS* will truncate the time down to microseconds as the timestamp usually 127*287e80b3SSadaf Ebrahimirecorded in the tracing buffer has nanosecond resolution. If you do not want that 128*287e80b3SSadaf Ebrahimitruncation, use *TIMESTAMP* instead of *TIMESTAMP_USECS*. 129*287e80b3SSadaf Ebrahimi 130*287e80b3SSadaf EbrahimiFinally, the *WHERE* clause can be added, that will let you add filters on either or both events. 131*287e80b3SSadaf Ebrahimi 132*287e80b3SSadaf Ebrahimi[source,c] 133*287e80b3SSadaf Ebrahimi-- 134*287e80b3SSadaf Ebrahimiselect start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start 135*287e80b3SSadaf Ebrahimi JOIN sched_switch as end ON start.pid = end.next_pid 136*287e80b3SSadaf Ebrahimi WHERE start.prio < 100 && (!(end.prev_pid < 1 || end.prev_prio > 100) || end.prev_pid == 0) 137*287e80b3SSadaf Ebrahimi-- 138*287e80b3SSadaf Ebrahimi 139*287e80b3SSadaf Ebrahimi*NOTE* 140*287e80b3SSadaf Ebrahimi 141*287e80b3SSadaf EbrahimiAlthough both events can be used together in the *WHERE* clause, they must not be mixed outside 142*287e80b3SSadaf Ebrahimithe top most "&&" statements. You can not OR (||) the events together, where a filter of one 143*287e80b3SSadaf Ebrahimievent is OR'd to a filter of the other event. This does not make sense, as the synthetic event 144*287e80b3SSadaf Ebrahimirequires both events to take place to be recorded. If one is filtered out, then the synthetic 145*287e80b3SSadaf Ebrahimievent does not execute. 146*287e80b3SSadaf Ebrahimi 147*287e80b3SSadaf Ebrahimi[source,c] 148*287e80b3SSadaf Ebrahimi-- 149*287e80b3SSadaf Ebrahimiselect start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start 150*287e80b3SSadaf Ebrahimi JOIN sched_switch as end ON start.pid = end.next_pid 151*287e80b3SSadaf Ebrahimi WHERE start.prio < 100 && end.prev_prio < 100 152*287e80b3SSadaf Ebrahimi-- 153*287e80b3SSadaf Ebrahimi 154*287e80b3SSadaf EbrahimiThe above is valid. 155*287e80b3SSadaf Ebrahimi 156*287e80b3SSadaf EbrahimiWhere as the below is not. 157*287e80b3SSadaf Ebrahimi 158*287e80b3SSadaf Ebrahimi[source,c] 159*287e80b3SSadaf Ebrahimi-- 160*287e80b3SSadaf Ebrahimiselect start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start 161*287e80b3SSadaf Ebrahimi JOIN sched_switch as end ON start.pid = end.next_pid 162*287e80b3SSadaf Ebrahimi WHERE start.prio < 100 || end.prev_prio < 100 163*287e80b3SSadaf Ebrahimi-- 164*287e80b3SSadaf Ebrahimi 165*287e80b3SSadaf Ebrahimi 166*287e80b3SSadaf EbrahimiKEYWORDS AS EVENT FIELDS 167*287e80b3SSadaf Ebrahimi------------------------ 168*287e80b3SSadaf Ebrahimi 169*287e80b3SSadaf EbrahimiIn some cases, an event may have a keyword. For example, regcache_drop_region has "from" 170*287e80b3SSadaf Ebrahimias a field and the following will not work 171*287e80b3SSadaf Ebrahimi 172*287e80b3SSadaf Ebrahimi[source,c] 173*287e80b3SSadaf Ebrahimi-- 174*287e80b3SSadaf Ebrahimi select from from regcache_drop_region 175*287e80b3SSadaf Ebrahimi-- 176*287e80b3SSadaf Ebrahimi 177*287e80b3SSadaf EbrahimiIn such cases, add a backslash to the conflicting field, and this will tell the parser 178*287e80b3SSadaf Ebrahimithat the "from" is a field and not a keyword: 179*287e80b3SSadaf Ebrahimi 180*287e80b3SSadaf Ebrahimi[source,c] 181*287e80b3SSadaf Ebrahimi-- 182*287e80b3SSadaf Ebrahimi select \from from regcache_drop_region 183*287e80b3SSadaf Ebrahimi-- 184*287e80b3SSadaf Ebrahimi 185*287e80b3SSadaf EbrahimiHISTOGRAMS 186*287e80b3SSadaf Ebrahimi---------- 187*287e80b3SSadaf Ebrahimi 188*287e80b3SSadaf EbrahimiSimple SQL statements without the *JOIN* *ON* may also be used, which will create a histogram 189*287e80b3SSadaf Ebrahimiinstead. When doing this, the struct tracefs_hist descriptor can be retrieved from the 190*287e80b3SSadaf Ebrahimireturned synthetic event descriptor via the *tracefs_synth_get_start_hist*(3). 191*287e80b3SSadaf Ebrahimi 192*287e80b3SSadaf EbrahimiIn order to utilize the histogram types (see xxx) the CAST command of SQL can be used. 193*287e80b3SSadaf Ebrahimi 194*287e80b3SSadaf EbrahimiThat is: 195*287e80b3SSadaf Ebrahimi 196*287e80b3SSadaf Ebrahimi[source,c] 197*287e80b3SSadaf Ebrahimi-- 198*287e80b3SSadaf Ebrahimi select CAST(common_pid AS comm), CAST(id AS syscall) FROM sys_enter 199*287e80b3SSadaf Ebrahimi-- 200*287e80b3SSadaf Ebrahimi 201*287e80b3SSadaf EbrahimiWhich produces: 202*287e80b3SSadaf Ebrahimi 203*287e80b3SSadaf Ebrahimi[source,c] 204*287e80b3SSadaf Ebrahimi-- 205*287e80b3SSadaf Ebrahimi # echo 'hist:keys=common_pid.execname,id.syscall' > events/raw_syscalls/sys_enter/trigger 206*287e80b3SSadaf Ebrahimi 207*287e80b3SSadaf Ebrahimi # cat events/raw_syscalls/sys_enter/hist 208*287e80b3SSadaf Ebrahimi 209*287e80b3SSadaf Ebrahimi{ common_pid: bash [ 18248], id: sys_setpgid [109] } hitcount: 1 210*287e80b3SSadaf Ebrahimi{ common_pid: sendmail [ 1812], id: sys_read [ 0] } hitcount: 1 211*287e80b3SSadaf Ebrahimi{ common_pid: bash [ 18247], id: sys_getpid [ 39] } hitcount: 1 212*287e80b3SSadaf Ebrahimi{ common_pid: bash [ 18247], id: sys_dup2 [ 33] } hitcount: 1 213*287e80b3SSadaf Ebrahimi{ common_pid: gmain [ 13684], id: sys_inotify_add_watch [254] } hitcount: 1 214*287e80b3SSadaf Ebrahimi{ common_pid: cat [ 18247], id: sys_access [ 21] } hitcount: 1 215*287e80b3SSadaf Ebrahimi{ common_pid: bash [ 18248], id: sys_getpid [ 39] } hitcount: 1 216*287e80b3SSadaf Ebrahimi{ common_pid: cat [ 18247], id: sys_fadvise64 [221] } hitcount: 1 217*287e80b3SSadaf Ebrahimi{ common_pid: sendmail [ 1812], id: sys_openat [257] } hitcount: 1 218*287e80b3SSadaf Ebrahimi{ common_pid: less [ 18248], id: sys_munmap [ 11] } hitcount: 1 219*287e80b3SSadaf Ebrahimi{ common_pid: sendmail [ 1812], id: sys_close [ 3] } hitcount: 1 220*287e80b3SSadaf Ebrahimi{ common_pid: gmain [ 1534], id: sys_poll [ 7] } hitcount: 1 221*287e80b3SSadaf Ebrahimi{ common_pid: bash [ 18247], id: sys_execve [ 59] } hitcount: 1 222*287e80b3SSadaf Ebrahimi-- 223*287e80b3SSadaf Ebrahimi 224*287e80b3SSadaf EbrahimiNote, string fields may not be cast. 225*287e80b3SSadaf Ebrahimi 226*287e80b3SSadaf EbrahimiThe possible types to cast to are: 227*287e80b3SSadaf Ebrahimi 228*287e80b3SSadaf Ebrahimi*HEX* - convert the value to use hex and not decimal 229*287e80b3SSadaf Ebrahimi 230*287e80b3SSadaf Ebrahimi*SYM* - convert a pointer to symbolic (kallsyms values) 231*287e80b3SSadaf Ebrahimi 232*287e80b3SSadaf Ebrahimi*SYM-OFFSET* - convert a pointer to symbolic and include the offset. 233*287e80b3SSadaf Ebrahimi 234*287e80b3SSadaf Ebrahimi*SYSCALL* - convert the number to the mapped system call name 235*287e80b3SSadaf Ebrahimi 236*287e80b3SSadaf Ebrahimi*EXECNAME* or *COMM* - can only be used with the common_pid field. Will show the task 237*287e80b3SSadaf Ebrahiminame of the process. 238*287e80b3SSadaf Ebrahimi 239*287e80b3SSadaf Ebrahimi*LOG* or *LOG2* - bucket the key values in a log 2 values (1, 2, 3-4, 5-8, 9-16, 17-32, ...) 240*287e80b3SSadaf Ebrahimi 241*287e80b3SSadaf EbrahimiThe above fields are not case sensitive, and "LOG2" works as good as "log". 242*287e80b3SSadaf Ebrahimi 243*287e80b3SSadaf EbrahimiA special CAST to _COUNTER_ or __COUNTER__ will make the field a value and not 244*287e80b3SSadaf Ebrahimia key. For example: 245*287e80b3SSadaf Ebrahimi 246*287e80b3SSadaf Ebrahimi[source,c] 247*287e80b3SSadaf Ebrahimi-- 248*287e80b3SSadaf Ebrahimi SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc 249*287e80b3SSadaf Ebrahimi-- 250*287e80b3SSadaf Ebrahimi 251*287e80b3SSadaf EbrahimiWhich will create 252*287e80b3SSadaf Ebrahimi 253*287e80b3SSadaf Ebrahimi[source,c] 254*287e80b3SSadaf Ebrahimi-- 255*287e80b3SSadaf Ebrahimi echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger 256*287e80b3SSadaf Ebrahimi 257*287e80b3SSadaf Ebrahimi cat events/kmem/kmalloc/hist 258*287e80b3SSadaf Ebrahimi 259*287e80b3SSadaf Ebrahimi{ common_pid: 1812 } hitcount: 1 bytes_req: 32 260*287e80b3SSadaf Ebrahimi{ common_pid: 9111 } hitcount: 2 bytes_req: 272 261*287e80b3SSadaf Ebrahimi{ common_pid: 1768 } hitcount: 3 bytes_req: 1112 262*287e80b3SSadaf Ebrahimi{ common_pid: 0 } hitcount: 4 bytes_req: 512 263*287e80b3SSadaf Ebrahimi{ common_pid: 18297 } hitcount: 11 bytes_req: 2004 264*287e80b3SSadaf Ebrahimi-- 265*287e80b3SSadaf Ebrahimi 266*287e80b3SSadaf EbrahimiRETURN VALUE 267*287e80b3SSadaf Ebrahimi------------ 268*287e80b3SSadaf EbrahimiReturns 0 on success and -1 on failure. On failure, if _err_ is defined, it will be 269*287e80b3SSadaf Ebrahimiallocated to hold a detailed description of what went wrong if it the error was caused 270*287e80b3SSadaf Ebrahimiby a parsing error, or that an event, field does not exist or is not compatible with 271*287e80b3SSadaf Ebrahimiwhat it was combined with. 272*287e80b3SSadaf Ebrahimi 273*287e80b3SSadaf EbrahimiCREATE A TOOL 274*287e80b3SSadaf Ebrahimi------------- 275*287e80b3SSadaf Ebrahimi 276*287e80b3SSadaf EbrahimiThe below example is a functional program that can be used to parse SQL commands into 277*287e80b3SSadaf Ebrahimisynthetic events. 278*287e80b3SSadaf Ebrahimi 279*287e80b3SSadaf Ebrahimi[source, c] 280*287e80b3SSadaf Ebrahimi-- 281*287e80b3SSadaf Ebrahimi man tracefs_sql | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/d ; /FILES/d ; p}' > sqlhist.c 282*287e80b3SSadaf Ebrahimi gcc -o sqlhist sqlhist.c `pkg-config --cflags --libs libtracefs` 283*287e80b3SSadaf Ebrahimi-- 284*287e80b3SSadaf Ebrahimi 285*287e80b3SSadaf EbrahimiThen you can run the above examples: 286*287e80b3SSadaf Ebrahimi 287*287e80b3SSadaf Ebrahimi[source, c] 288*287e80b3SSadaf Ebrahimi-- 289*287e80b3SSadaf Ebrahimi sudo ./sqlhist 'select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start 290*287e80b3SSadaf Ebrahimi JOIN sched_switch as end ON start.pid = end.next_pid 291*287e80b3SSadaf Ebrahimi WHERE start.prio < 100 || end.prev_prio < 100' 292*287e80b3SSadaf Ebrahimi-- 293*287e80b3SSadaf EbrahimiEXAMPLE 294*287e80b3SSadaf Ebrahimi------- 295*287e80b3SSadaf Ebrahimi[source,c] 296*287e80b3SSadaf Ebrahimi-- 297*287e80b3SSadaf Ebrahimi#include <stdio.h> 298*287e80b3SSadaf Ebrahimi#include <stdlib.h> 299*287e80b3SSadaf Ebrahimi#include <stdarg.h> 300*287e80b3SSadaf Ebrahimi#include <string.h> 301*287e80b3SSadaf Ebrahimi#include <errno.h> 302*287e80b3SSadaf Ebrahimi#include <unistd.h> 303*287e80b3SSadaf Ebrahimi#include <tracefs.h> 304*287e80b3SSadaf Ebrahimi 305*287e80b3SSadaf Ebrahimistatic void usage(char **argv) 306*287e80b3SSadaf Ebrahimi{ 307*287e80b3SSadaf Ebrahimi fprintf(stderr, "usage: %s [-ed][-n name][-s][-S fields][-m var][-c var][-T][-t dir][-f file | sql-command-line]\n" 308*287e80b3SSadaf Ebrahimi " -n name - name of synthetic event 'Anonymous' if left off\n" 309*287e80b3SSadaf Ebrahimi " -t dir - use dir instead of /sys/kernel/tracing\n" 310*287e80b3SSadaf Ebrahimi " -e - execute the commands to create the synthetic event\n" 311*287e80b3SSadaf Ebrahimi " -m - trigger the action when var is a new max.\n" 312*287e80b3SSadaf Ebrahimi " -c - trigger the action when var changes.\n" 313*287e80b3SSadaf Ebrahimi " -s - used with -m or -c to do a snapshot of the tracing buffer\n" 314*287e80b3SSadaf Ebrahimi " -S - used with -m or -c to save fields of the end event (comma deliminated)\n" 315*287e80b3SSadaf Ebrahimi " -T - used with -m or -c to do both a snapshot and a trace\n" 316*287e80b3SSadaf Ebrahimi " -f file - read sql lines from file otherwise from the command line\n" 317*287e80b3SSadaf Ebrahimi " if file is '-' then read from standard input.\n", 318*287e80b3SSadaf Ebrahimi argv[0]); 319*287e80b3SSadaf Ebrahimi exit(-1); 320*287e80b3SSadaf Ebrahimi} 321*287e80b3SSadaf Ebrahimi 322*287e80b3SSadaf Ebrahimienum action { 323*287e80b3SSadaf Ebrahimi ACTION_DEFAULT = 0, 324*287e80b3SSadaf Ebrahimi ACTION_SNAPSHOT = (1 << 0), 325*287e80b3SSadaf Ebrahimi ACTION_TRACE = (1 << 1), 326*287e80b3SSadaf Ebrahimi ACTION_SAVE = (1 << 2), 327*287e80b3SSadaf Ebrahimi ACTION_MAX = (1 << 3), 328*287e80b3SSadaf Ebrahimi ACTION_CHANGE = (1 << 4), 329*287e80b3SSadaf Ebrahimi}; 330*287e80b3SSadaf Ebrahimi 331*287e80b3SSadaf Ebrahimi#define ACTIONS ((ACTION_MAX - 1)) 332*287e80b3SSadaf Ebrahimi 333*287e80b3SSadaf Ebrahimistatic int do_sql(const char *instance_name, 334*287e80b3SSadaf Ebrahimi const char *buffer, const char *name, const char *var, 335*287e80b3SSadaf Ebrahimi const char *trace_dir, bool execute, int action, 336*287e80b3SSadaf Ebrahimi char **save_fields) 337*287e80b3SSadaf Ebrahimi{ 338*287e80b3SSadaf Ebrahimi struct tracefs_synth *synth; 339*287e80b3SSadaf Ebrahimi struct tep_handle *tep; 340*287e80b3SSadaf Ebrahimi struct trace_seq seq; 341*287e80b3SSadaf Ebrahimi enum tracefs_synth_handler handler; 342*287e80b3SSadaf Ebrahimi char *err; 343*287e80b3SSadaf Ebrahimi int ret; 344*287e80b3SSadaf Ebrahimi 345*287e80b3SSadaf Ebrahimi if ((action & ACTIONS) && !var) { 346*287e80b3SSadaf Ebrahimi fprintf(stderr, "Error: -s, -S and -T not supported without -m or -c"); 347*287e80b3SSadaf Ebrahimi exit(-1); 348*287e80b3SSadaf Ebrahimi } 349*287e80b3SSadaf Ebrahimi 350*287e80b3SSadaf Ebrahimi if (!name) 351*287e80b3SSadaf Ebrahimi name = "Anonymous"; 352*287e80b3SSadaf Ebrahimi 353*287e80b3SSadaf Ebrahimi trace_seq_init(&seq); 354*287e80b3SSadaf Ebrahimi tep = tracefs_local_events(trace_dir); 355*287e80b3SSadaf Ebrahimi if (!tep) { 356*287e80b3SSadaf Ebrahimi if (!trace_dir) 357*287e80b3SSadaf Ebrahimi trace_dir = "tracefs directory"; 358*287e80b3SSadaf Ebrahimi perror(trace_dir); 359*287e80b3SSadaf Ebrahimi exit(-1); 360*287e80b3SSadaf Ebrahimi } 361*287e80b3SSadaf Ebrahimi 362*287e80b3SSadaf Ebrahimi synth = tracefs_sql(tep, name, buffer, &err); 363*287e80b3SSadaf Ebrahimi if (!synth) { 364*287e80b3SSadaf Ebrahimi perror("Failed creating synthetic event!"); 365*287e80b3SSadaf Ebrahimi if (err) 366*287e80b3SSadaf Ebrahimi fprintf(stderr, "%s", err); 367*287e80b3SSadaf Ebrahimi free(err); 368*287e80b3SSadaf Ebrahimi exit(-1); 369*287e80b3SSadaf Ebrahimi } 370*287e80b3SSadaf Ebrahimi 371*287e80b3SSadaf Ebrahimi if (tracefs_synth_complete(synth)) { 372*287e80b3SSadaf Ebrahimi if (var) { 373*287e80b3SSadaf Ebrahimi if (action & ACTION_MAX) 374*287e80b3SSadaf Ebrahimi handler = TRACEFS_SYNTH_HANDLE_MAX; 375*287e80b3SSadaf Ebrahimi else 376*287e80b3SSadaf Ebrahimi handler = TRACEFS_SYNTH_HANDLE_CHANGE; 377*287e80b3SSadaf Ebrahimi 378*287e80b3SSadaf Ebrahimi if (action & ACTION_SAVE) { 379*287e80b3SSadaf Ebrahimi ret = tracefs_synth_save(synth, handler, var, save_fields); 380*287e80b3SSadaf Ebrahimi if (ret < 0) { 381*287e80b3SSadaf Ebrahimi err = "adding save"; 382*287e80b3SSadaf Ebrahimi goto failed_action; 383*287e80b3SSadaf Ebrahimi } 384*287e80b3SSadaf Ebrahimi } 385*287e80b3SSadaf Ebrahimi if (action & ACTION_TRACE) { 386*287e80b3SSadaf Ebrahimi /* 387*287e80b3SSadaf Ebrahimi * By doing the trace before snapshot, it will be included 388*287e80b3SSadaf Ebrahimi * in the snapshot. 389*287e80b3SSadaf Ebrahimi */ 390*287e80b3SSadaf Ebrahimi ret = tracefs_synth_trace(synth, handler, var); 391*287e80b3SSadaf Ebrahimi if (ret < 0) { 392*287e80b3SSadaf Ebrahimi err = "adding trace"; 393*287e80b3SSadaf Ebrahimi goto failed_action; 394*287e80b3SSadaf Ebrahimi } 395*287e80b3SSadaf Ebrahimi } 396*287e80b3SSadaf Ebrahimi if (action & ACTION_SNAPSHOT) { 397*287e80b3SSadaf Ebrahimi ret = tracefs_synth_snapshot(synth, handler, var); 398*287e80b3SSadaf Ebrahimi if (ret < 0) { 399*287e80b3SSadaf Ebrahimi err = "adding snapshot"; 400*287e80b3SSadaf Ebrahimi failed_action: 401*287e80b3SSadaf Ebrahimi perror(err); 402*287e80b3SSadaf Ebrahimi if (errno == ENODEV) 403*287e80b3SSadaf Ebrahimi fprintf(stderr, "ERROR: '%s' is not a variable\n", 404*287e80b3SSadaf Ebrahimi var); 405*287e80b3SSadaf Ebrahimi exit(-1); 406*287e80b3SSadaf Ebrahimi } 407*287e80b3SSadaf Ebrahimi } 408*287e80b3SSadaf Ebrahimi } 409*287e80b3SSadaf Ebrahimi tracefs_synth_echo_cmd(&seq, synth); 410*287e80b3SSadaf Ebrahimi if (execute) { 411*287e80b3SSadaf Ebrahimi ret = tracefs_synth_create(synth); 412*287e80b3SSadaf Ebrahimi if (ret < 0) { 413*287e80b3SSadaf Ebrahimi fprintf(stderr, "%s\n", tracefs_error_last(NULL)); 414*287e80b3SSadaf Ebrahimi exit(-1); 415*287e80b3SSadaf Ebrahimi } 416*287e80b3SSadaf Ebrahimi } 417*287e80b3SSadaf Ebrahimi } else { 418*287e80b3SSadaf Ebrahimi struct tracefs_instance *instance = NULL; 419*287e80b3SSadaf Ebrahimi struct tracefs_hist *hist; 420*287e80b3SSadaf Ebrahimi 421*287e80b3SSadaf Ebrahimi hist = tracefs_synth_get_start_hist(synth); 422*287e80b3SSadaf Ebrahimi if (!hist) { 423*287e80b3SSadaf Ebrahimi perror("get_start_hist"); 424*287e80b3SSadaf Ebrahimi exit(-1); 425*287e80b3SSadaf Ebrahimi } 426*287e80b3SSadaf Ebrahimi if (instance_name) { 427*287e80b3SSadaf Ebrahimi if (execute) 428*287e80b3SSadaf Ebrahimi instance = tracefs_instance_create(instance_name); 429*287e80b3SSadaf Ebrahimi else 430*287e80b3SSadaf Ebrahimi instance = tracefs_instance_alloc(trace_dir, 431*287e80b3SSadaf Ebrahimi instance_name); 432*287e80b3SSadaf Ebrahimi if (!instance) { 433*287e80b3SSadaf Ebrahimi perror("Failed to create instance"); 434*287e80b3SSadaf Ebrahimi exit(-1); 435*287e80b3SSadaf Ebrahimi } 436*287e80b3SSadaf Ebrahimi } 437*287e80b3SSadaf Ebrahimi tracefs_hist_echo_cmd(&seq, instance, hist, 0); 438*287e80b3SSadaf Ebrahimi if (execute) { 439*287e80b3SSadaf Ebrahimi ret = tracefs_hist_start(instance, hist); 440*287e80b3SSadaf Ebrahimi if (ret < 0) { 441*287e80b3SSadaf Ebrahimi fprintf(stderr, "%s\n", tracefs_error_last(instance)); 442*287e80b3SSadaf Ebrahimi exit(-1); 443*287e80b3SSadaf Ebrahimi } 444*287e80b3SSadaf Ebrahimi } 445*287e80b3SSadaf Ebrahimi } 446*287e80b3SSadaf Ebrahimi 447*287e80b3SSadaf Ebrahimi tracefs_synth_free(synth); 448*287e80b3SSadaf Ebrahimi 449*287e80b3SSadaf Ebrahimi trace_seq_do_printf(&seq); 450*287e80b3SSadaf Ebrahimi trace_seq_destroy(&seq); 451*287e80b3SSadaf Ebrahimi return 0; 452*287e80b3SSadaf Ebrahimi} 453*287e80b3SSadaf Ebrahimi 454*287e80b3SSadaf Ebrahimiint main (int argc, char **argv) 455*287e80b3SSadaf Ebrahimi{ 456*287e80b3SSadaf Ebrahimi char *trace_dir = NULL; 457*287e80b3SSadaf Ebrahimi char *buffer = NULL; 458*287e80b3SSadaf Ebrahimi char buf[BUFSIZ]; 459*287e80b3SSadaf Ebrahimi int buffer_size = 0; 460*287e80b3SSadaf Ebrahimi const char *file = NULL; 461*287e80b3SSadaf Ebrahimi const char *instance = NULL; 462*287e80b3SSadaf Ebrahimi bool execute = false; 463*287e80b3SSadaf Ebrahimi char **save_fields = NULL; 464*287e80b3SSadaf Ebrahimi const char *name; 465*287e80b3SSadaf Ebrahimi const char *var; 466*287e80b3SSadaf Ebrahimi int action = 0; 467*287e80b3SSadaf Ebrahimi char *tok; 468*287e80b3SSadaf Ebrahimi FILE *fp; 469*287e80b3SSadaf Ebrahimi size_t r; 470*287e80b3SSadaf Ebrahimi int c; 471*287e80b3SSadaf Ebrahimi int i; 472*287e80b3SSadaf Ebrahimi 473*287e80b3SSadaf Ebrahimi for (;;) { 474*287e80b3SSadaf Ebrahimi c = getopt(argc, argv, "ht:f:en:m:c:sS:TB:"); 475*287e80b3SSadaf Ebrahimi if (c == -1) 476*287e80b3SSadaf Ebrahimi break; 477*287e80b3SSadaf Ebrahimi 478*287e80b3SSadaf Ebrahimi switch(c) { 479*287e80b3SSadaf Ebrahimi case 'h': 480*287e80b3SSadaf Ebrahimi usage(argv); 481*287e80b3SSadaf Ebrahimi case 't': 482*287e80b3SSadaf Ebrahimi trace_dir = optarg; 483*287e80b3SSadaf Ebrahimi break; 484*287e80b3SSadaf Ebrahimi case 'f': 485*287e80b3SSadaf Ebrahimi file = optarg; 486*287e80b3SSadaf Ebrahimi break; 487*287e80b3SSadaf Ebrahimi case 'e': 488*287e80b3SSadaf Ebrahimi execute = true; 489*287e80b3SSadaf Ebrahimi break; 490*287e80b3SSadaf Ebrahimi case 'm': 491*287e80b3SSadaf Ebrahimi action |= ACTION_MAX; 492*287e80b3SSadaf Ebrahimi var = optarg; 493*287e80b3SSadaf Ebrahimi break; 494*287e80b3SSadaf Ebrahimi case 'c': 495*287e80b3SSadaf Ebrahimi action |= ACTION_CHANGE; 496*287e80b3SSadaf Ebrahimi var = optarg; 497*287e80b3SSadaf Ebrahimi break; 498*287e80b3SSadaf Ebrahimi case 's': 499*287e80b3SSadaf Ebrahimi action |= ACTION_SNAPSHOT; 500*287e80b3SSadaf Ebrahimi break; 501*287e80b3SSadaf Ebrahimi case 'S': 502*287e80b3SSadaf Ebrahimi action |= ACTION_SAVE; 503*287e80b3SSadaf Ebrahimi tok = strtok(optarg, ","); 504*287e80b3SSadaf Ebrahimi while (tok) { 505*287e80b3SSadaf Ebrahimi save_fields = tracefs_list_add(save_fields, tok); 506*287e80b3SSadaf Ebrahimi tok = strtok(NULL, ","); 507*287e80b3SSadaf Ebrahimi } 508*287e80b3SSadaf Ebrahimi if (!save_fields) { 509*287e80b3SSadaf Ebrahimi perror(optarg); 510*287e80b3SSadaf Ebrahimi exit(-1); 511*287e80b3SSadaf Ebrahimi } 512*287e80b3SSadaf Ebrahimi break; 513*287e80b3SSadaf Ebrahimi case 'T': 514*287e80b3SSadaf Ebrahimi action |= ACTION_TRACE | ACTION_SNAPSHOT; 515*287e80b3SSadaf Ebrahimi break; 516*287e80b3SSadaf Ebrahimi case 'B': 517*287e80b3SSadaf Ebrahimi instance = optarg; 518*287e80b3SSadaf Ebrahimi break; 519*287e80b3SSadaf Ebrahimi case 'n': 520*287e80b3SSadaf Ebrahimi name = optarg; 521*287e80b3SSadaf Ebrahimi break; 522*287e80b3SSadaf Ebrahimi } 523*287e80b3SSadaf Ebrahimi } 524*287e80b3SSadaf Ebrahimi 525*287e80b3SSadaf Ebrahimi if ((action & (ACTION_MAX|ACTION_CHANGE)) == (ACTION_MAX|ACTION_CHANGE)) { 526*287e80b3SSadaf Ebrahimi fprintf(stderr, "Can not use both -m and -c together\n"); 527*287e80b3SSadaf Ebrahimi exit(-1); 528*287e80b3SSadaf Ebrahimi } 529*287e80b3SSadaf Ebrahimi if (file) { 530*287e80b3SSadaf Ebrahimi if (!strcmp(file, "-")) 531*287e80b3SSadaf Ebrahimi fp = stdin; 532*287e80b3SSadaf Ebrahimi else 533*287e80b3SSadaf Ebrahimi fp = fopen(file, "r"); 534*287e80b3SSadaf Ebrahimi if (!fp) { 535*287e80b3SSadaf Ebrahimi perror(file); 536*287e80b3SSadaf Ebrahimi exit(-1); 537*287e80b3SSadaf Ebrahimi } 538*287e80b3SSadaf Ebrahimi while ((r = fread(buf, 1, BUFSIZ, fp)) > 0) { 539*287e80b3SSadaf Ebrahimi buffer = realloc(buffer, buffer_size + r + 1); 540*287e80b3SSadaf Ebrahimi strncpy(buffer + buffer_size, buf, r); 541*287e80b3SSadaf Ebrahimi buffer_size += r; 542*287e80b3SSadaf Ebrahimi } 543*287e80b3SSadaf Ebrahimi fclose(fp); 544*287e80b3SSadaf Ebrahimi if (buffer_size) 545*287e80b3SSadaf Ebrahimi buffer[buffer_size] = '\0'; 546*287e80b3SSadaf Ebrahimi } else if (argc == optind) { 547*287e80b3SSadaf Ebrahimi usage(argv); 548*287e80b3SSadaf Ebrahimi } else { 549*287e80b3SSadaf Ebrahimi for (i = optind; i < argc; i++) { 550*287e80b3SSadaf Ebrahimi r = strlen(argv[i]); 551*287e80b3SSadaf Ebrahimi buffer = realloc(buffer, buffer_size + r + 2); 552*287e80b3SSadaf Ebrahimi if (i != optind) 553*287e80b3SSadaf Ebrahimi buffer[buffer_size++] = ' '; 554*287e80b3SSadaf Ebrahimi strcpy(buffer + buffer_size, argv[i]); 555*287e80b3SSadaf Ebrahimi buffer_size += r; 556*287e80b3SSadaf Ebrahimi } 557*287e80b3SSadaf Ebrahimi } 558*287e80b3SSadaf Ebrahimi 559*287e80b3SSadaf Ebrahimi do_sql(instance, buffer, name, var, trace_dir, execute, action, save_fields); 560*287e80b3SSadaf Ebrahimi free(buffer); 561*287e80b3SSadaf Ebrahimi 562*287e80b3SSadaf Ebrahimi return 0; 563*287e80b3SSadaf Ebrahimi} 564*287e80b3SSadaf Ebrahimi-- 565*287e80b3SSadaf Ebrahimi 566*287e80b3SSadaf EbrahimiFILES 567*287e80b3SSadaf Ebrahimi----- 568*287e80b3SSadaf Ebrahimi[verse] 569*287e80b3SSadaf Ebrahimi-- 570*287e80b3SSadaf Ebrahimi*tracefs.h* 571*287e80b3SSadaf Ebrahimi Header file to include in order to have access to the library APIs. 572*287e80b3SSadaf Ebrahimi*-ltracefs* 573*287e80b3SSadaf Ebrahimi Linker switch to add when building a program that uses the library. 574*287e80b3SSadaf Ebrahimi-- 575*287e80b3SSadaf Ebrahimi 576*287e80b3SSadaf EbrahimiSEE ALSO 577*287e80b3SSadaf Ebrahimi-------- 578*287e80b3SSadaf Ebrahimi*sqlhist*(1), 579*287e80b3SSadaf Ebrahimi*libtracefs*(3), 580*287e80b3SSadaf Ebrahimi*libtraceevent*(3), 581*287e80b3SSadaf Ebrahimi*trace-cmd*(1), 582*287e80b3SSadaf Ebrahimi*tracefs_synth_init*(3), 583*287e80b3SSadaf Ebrahimi*tracefs_synth_add_match_field*(3), 584*287e80b3SSadaf Ebrahimi*tracefs_synth_add_compare_field*(3), 585*287e80b3SSadaf Ebrahimi*tracefs_synth_add_start_field*(3), 586*287e80b3SSadaf Ebrahimi*tracefs_synth_add_end_field*(3), 587*287e80b3SSadaf Ebrahimi*tracefs_synth_append_start_filter*(3), 588*287e80b3SSadaf Ebrahimi*tracefs_synth_append_end_filter*(3), 589*287e80b3SSadaf Ebrahimi*tracefs_synth_create*(3), 590*287e80b3SSadaf Ebrahimi*tracefs_synth_destroy*(3), 591*287e80b3SSadaf Ebrahimi*tracefs_synth_free*(3), 592*287e80b3SSadaf Ebrahimi*tracefs_synth_echo_cmd*(3), 593*287e80b3SSadaf Ebrahimi*tracefs_hist_alloc*(3), 594*287e80b3SSadaf Ebrahimi*tracefs_hist_alloc_2d*(3), 595*287e80b3SSadaf Ebrahimi*tracefs_hist_alloc_nd*(3), 596*287e80b3SSadaf Ebrahimi*tracefs_hist_free*(3), 597*287e80b3SSadaf Ebrahimi*tracefs_hist_add_key*(3), 598*287e80b3SSadaf Ebrahimi*tracefs_hist_add_value*(3), 599*287e80b3SSadaf Ebrahimi*tracefs_hist_add_name*(3), 600*287e80b3SSadaf Ebrahimi*tracefs_hist_start*(3), 601*287e80b3SSadaf Ebrahimi*tracefs_hist_destory*(3), 602*287e80b3SSadaf Ebrahimi*tracefs_hist_add_sort_key*(3), 603*287e80b3SSadaf Ebrahimi*tracefs_hist_sort_key_direction*(3) 604*287e80b3SSadaf Ebrahimi 605*287e80b3SSadaf EbrahimiAUTHOR 606*287e80b3SSadaf Ebrahimi------ 607*287e80b3SSadaf Ebrahimi[verse] 608*287e80b3SSadaf Ebrahimi-- 609*287e80b3SSadaf Ebrahimi*Steven Rostedt* <[email protected]> 610*287e80b3SSadaf Ebrahimi*Tzvetomir Stoyanov* <[email protected]> 611*287e80b3SSadaf Ebrahimi*sameeruddin shaik* <[email protected]> 612*287e80b3SSadaf Ebrahimi-- 613*287e80b3SSadaf EbrahimiREPORTING BUGS 614*287e80b3SSadaf Ebrahimi-------------- 615*287e80b3SSadaf EbrahimiReport bugs to <[email protected]> 616*287e80b3SSadaf Ebrahimi 617*287e80b3SSadaf EbrahimiLICENSE 618*287e80b3SSadaf Ebrahimi------- 619*287e80b3SSadaf Ebrahimilibtracefs is Free Software licensed under the GNU LGPL 2.1 620*287e80b3SSadaf Ebrahimi 621*287e80b3SSadaf EbrahimiRESOURCES 622*287e80b3SSadaf Ebrahimi--------- 623*287e80b3SSadaf Ebrahimihttps://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 624*287e80b3SSadaf Ebrahimi 625*287e80b3SSadaf EbrahimiCOPYING 626*287e80b3SSadaf Ebrahimi------- 627*287e80b3SSadaf EbrahimiCopyright \(C) 2020 VMware, Inc. Free use of this software is granted under 628*287e80b3SSadaf Ebrahimithe terms of the GNU Public License (GPL). 629