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