xref: /aosp_15_r20/external/libtracefs/Documentation/libtracefs-sql.txt (revision 287e80b3a36113050663245e7f2c00d274188f18)
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