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