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