xref: /aosp_15_r20/external/libtracefs/Documentation/libtracefs-hist-mod.txt (revision 287e80b3a36113050663245e7f2c00d274188f18)
1libtracefs(3)
2=============
3
4NAME
5----
6tracefs_hist_add_sort_key, tracefs_hist_set_sort_key, tracefs_hist_sort_key_direction,
7tracefs_hist_add_name, tracefs_hist_append_filter, tracefs_hist_echo_cmd, tracefs_hist_command,
8tracefs_hist_get_name, tracefs_hist_get_event, tracefs_hist_get_system - Update and describe an event histogram
9
10SYNOPSIS
11--------
12[verse]
13--
14*#include <tracefs.h>*
15
16int *tracefs_hist_add_sort_key*(struct tracefs_hist pass:[*]_hist_,
17			      const char pass:[*]_sort_key_);
18
19int *tracefs_hist_set_sort_key*(struct tracefs_hist pass:[*]_hist_,
20			      const char pass:[*]_sort_key_, _..._);
21int *tracefs_hist_sort_key_direction*(struct tracefs_hist pass:[*]_hist_,
22				    const char pass:[*]_sort_key_,
23				    enum tracefs_hist_sort_direction _dir_);
24
25int *tracefs_hist_add_name*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_name_);
26
27int *tracefs_hist_append_filter*(struct tracefs_hist pass:[*]_hist_,
28			       enum tracefs_filter _type_,
29			       const char pass:[*]_field_,
30			       enum tracefs_compare _compare_,
31			       const char pass:[*]_val_);
32
33int *tracefs_hist_echo_cmd*(struct trace_seq pass:[*]_s_, struct tracefs_instance pass:[*]_instance_,
34			  struct tracefs_hist pass:[*]_hist_,
35			  enum tracefs_hist_command _command_);
36
37int *tracefs_hist_command*(struct tracefs_instance pass:[*]_instance_,
38			 struct tracefs_hist pass:[*]_hist_,
39			 enum tracefs_hist_command _command_);
40
41const char pass:[*]*tracefs_hist_get_name*(struct tracefs_hist pass:[*]_hist_);
42
43const char pass:[*]*tracefs_hist_get_event*(struct tracefs_hist pass:[*]_hist_);
44
45const char pass:[*]*tracefs_hist_get_system*(struct tracefs_hist pass:[*]_hist_);
46
47--
48
49DESCRIPTION
50-----------
51Event histograms are created by the trigger file in the event directory.
52The syntax can be complex and difficult to get correct. This API handles the
53syntax, and facilitates the creation and interaction with the event histograms.
54See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information.
55
56*tracefs_hist_add_sort_key*() will add a key to sort on. The _hist_ is the
57histogram descriptor to add the sort key to. The _sort_key_ is a string
58that must match either an already defined key of the histogram, or an already
59defined value. If _hist_  already has sorting keys (previously added) the new
60_sort_key_ will have lower priority(be secondary or so on) when sorting.
61
62*tracefs_hist_set_sort_key*() will reset the list of key to sort on. The _hist_ is
63the histogram descriptor to reset the sort key to. The _sort_key_ is a string
64that must match either an already defined key of the histogram, or an already
65defined value. Multiple sort keys may be added to denote a secondary, sort order
66and so on, but all sort keys must match an existing key or value, or be
67TRACEFS_HIST_HITCOUNT. The last parameter of *tracefs_hist_add_sort_key*() must
68be NULL.
69
70*tracefs_hist_sort_key_direction*() allows to change the direction of an
71existing sort key of _hist_. The _sort_key_ is the sort key to change, and
72_dir_ can be either TRACEFS_HIST_SORT_ASCENDING or TRACEFS_HIST_SORT_DESCENDING,
73to make the direction of the sort key either ascending or descending respectively.
74
75*tracefs_hist_add_name*() adds a name to a histogram. A histogram may be
76named and if the name matches between more than one event, and they have
77compatible keys, the multiple histograms with the same name will be merged
78into a single histogram (shown by either event's hist file). The _hist_
79is the histogram to name, and the _name_ is the name to give it.
80
81*tracefs_hist_append_filter*() creates a filter or appends to it for the
82histogram  event. Depending on _type_, it will build a string of tokens for
83parenthesis or logic statements, or it may add a comparison of _field_
84to _val_ based on _compare_.
85
86If _type_ is:
87*TRACEFS_FILTER_COMPARE*     -  See below
88*TRACEFS_FILTER_AND*         -  Append "&&" to the filter
89*TRACEFS_FILTER_OR*          -  Append "||" to the filter
90*TRACEFS_FILTER_NOT*         -  Append "!" to the filter
91*TRACEFS_FILTER_OPEN_PAREN*  -  Append "(" to the filter
92*TRACEFS_FILTER_CLOSE_PAREN* -  Append ")" to the filter
93
94_field_, _compare_, and _val_ are ignored unless _type_ is equal to
95*TRACEFS_FILTER_COMPARE*, then _compare_ will be used for the following:
96
97*TRACEFS_COMPARE_EQ* - _field_ == _val_
98
99*TRACEFS_COMPARE_NE* - _field_ != _val_
100
101*TRACEFS_COMPARE_GT* - _field_ > _val_
102
103*TRACEFS_COMPARE_GE* - _field_ >= _val_
104
105*TRACEFS_COMPARE_LT* - _field_ < _val_
106
107*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_
108
109*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string.
110
111*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field.
112
113*trace_hist_echo_cmd*() prints the commands needed to create the given histogram
114in the given _instance_, or NULL for the top level, into the _seq_.
115The command that is printed is described by _command_ and shows the functionality
116that would be done by *tracefs_hist_command*(3).
117
118*tracefs_hist_command*() is called to process a command on the histogram
119_hist_ for its event in the given _instance_, or NULL for the top level.
120The _cmd_ can be one of:
121
122*TRACEFS_HIST_CMD_START* or zero to start execution of the histogram.
123
124*TRACEFS_HIST_CMD_PAUSE* to pause the given histogram.
125
126*TRACEFS_HIST_CMD_CONT* to continue a paused histogram.
127
128*TRACEFS_HIST_CMD_CLEAR* to reset the values of a histogram.
129
130*TRACEFS_HIST_CMD_DESTROY* to destroy the histogram (undo a START).
131
132The below functions are wrappers to tracefs_hist_command() to make the
133calling conventions a bit easier to understand what is happening.
134
135KEY TYPES
136---------
137
138*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires
139that key to have a type. The types may be:
140
141*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type.
142
143*TRACEFS_HIST_KEY_HEX* to display the key in hex.
144
145*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If
146the key is an address, this is useful as it will display the function names instead
147of just a number.
148
149*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include
150the offset of the function to match the exact address.
151
152*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user
153space to the kernel to tell it what system call it is calling), then the name of
154the system call is displayed.
155
156*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task),
157instead of showing the number, show the name of the running task.
158
159*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale.
160
161*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP,
162in which case it will show the timestamp in microseconds instead of nanoseconds.
163
164RETURN VALUE
165------------
166*tracefs_hist_get_name*() returns the name of the histogram or NULL on error.
167The returned string belongs to the histogram object and is freed with the histogram
168by *tracefs_hist_free*().
169
170*tracefs_hist_get_event*() returns the event name of the histogram or NULL on error.
171The returned string belongs to the histogram object and is freed with the histogram
172by *tracefs_hist_free*().
173
174*tracefs_hist_get_system*() returns the system name of the histogram or NULL on error.
175The returned string belongs to the histogram object and is freed with the histogram
176by *tracefs_hist_free*().
177
178*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must
179be freed by *tracefs_hist_free*() or NULL on error.
180
181*tracefs_hist_get_name*(), *tracefs_hist_get_event*() and *tracefs_hist_get_system*()
182return strings owned by the histogram object.
183
184All the other functions return zero on success or -1 on error.
185
186EXAMPLE
187-------
188[source,c]
189--
190#include <stdlib.h>
191#include <unistd.h>
192#include <tracefs.h>
193
194enum commands {
195	START,
196	PAUSE,
197	CONT,
198	RESET,
199	DELETE,
200	SHOW,
201};
202
203static void parse_system_event(char *group, char **system, char **event)
204{
205	*system = strtok(group, "/");
206	*event = strtok(NULL, "/");
207	if (!*event) {
208		*event = *system;
209		*system = NULL;
210	}
211}
212
213static int parse_keys(char *keys, struct tracefs_hist_axis **axes)
214{
215	char *sav = NULL;
216	char *key;
217	int cnt = 0;
218
219	for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) {
220		struct tracefs_hist_axis *ax;
221		char *att;
222
223		ax = realloc(*axes, sizeof(*ax) * (cnt + 2));
224		if (!ax) {
225			perror("Failed to allocate axes");
226			exit(-1);
227		}
228		ax[cnt].key = key;
229		ax[cnt].type = 0;
230		ax[cnt + 1].key = NULL;
231		ax[cnt + 1].type = 0;
232
233		*axes = ax;
234
235		att = strchr(key, '.');
236		if (att) {
237			*att++ = '\0';
238			if (strcmp(att, "hex") == 0)
239				ax[cnt].type = TRACEFS_HIST_KEY_HEX;
240			else if (strcmp(att, "sym") == 0)
241				ax[cnt].type = TRACEFS_HIST_KEY_SYM;
242			else if (strcmp(att, "sym_offset") == 0)
243				ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET;
244			else if (strcmp(att, "syscall") == 0)
245				ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL;
246			else if (strcmp(att, "exec") == 0)
247				ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME;
248			else if (strcmp(att, "log") == 0)
249				ax[cnt].type = TRACEFS_HIST_KEY_LOG;
250			else if (strcmp(att, "usecs") == 0)
251				ax[cnt].type = TRACEFS_HIST_KEY_USECS;
252			else {
253				fprintf(stderr, "Undefined attribute '%s'\n", att);
254				fprintf(stderr,"  Acceptable attributes:\n");
255				fprintf(stderr,"    hex, sym, sym_offset, syscall, exe, log, usecs\n");
256				exit(-1);
257			}
258		}
259		cnt++;
260	}
261	return cnt;
262}
263
264static void process_hist(enum commands cmd, const char *instance_name,
265			 char *group, char *keys, char *vals, char *sort,
266			 char *ascend, char *desc)
267{
268	struct tracefs_instance *instance = NULL;
269	struct tracefs_hist *hist;
270	struct tep_handle *tep;
271	struct tracefs_hist_axis *axes = NULL;
272	char *system;
273	char *event;
274	char *sav;
275	char *val;
276	int ret;
277	int cnt;
278
279	if (instance_name) {
280		instance = tracefs_instance_create(instance_name);
281		if (!instance) {
282			fprintf(stderr, "Failed instance create\n");
283			exit(-1);
284		}
285	}
286
287	tep = tracefs_local_events(NULL);
288	if (!tep) {
289		perror("Could not read events");
290		exit(-1);
291	}
292
293	parse_system_event(group, &system, &event);
294
295	if (cmd == SHOW) {
296		char *content;
297		content = tracefs_event_file_read(instance, system, event,
298						  "hist", NULL);
299		if (!content) {
300			perror("Reading hist file");
301			exit(-1);
302		}
303		printf("%s\n", content);
304		free(content);
305		return;
306	}
307
308	if (!keys) {
309		fprintf(stderr, "Command needs -k option\n");
310		exit(-1);
311	}
312
313	cnt = parse_keys(keys, &axes);
314	if (!cnt) {
315		fprintf(stderr, "No keys??\n");
316		exit(-1);
317	}
318
319	/* Show examples of hist1d and hist2d */
320	switch (cnt) {
321	case 1:
322		hist = tracefs_hist_alloc(tep, system, event,
323					  axes[0].key, axes[0].type);
324		break;
325	case 2:
326		hist = tracefs_hist_alloc_2d(tep, system, event,
327					     axes[0].key, axes[0].type,
328					     axes[1].key, axes[1].type);
329		break;
330	default:
331		/* Really, 1 and 2 could use this too */
332		hist = tracefs_hist_alloc_nd(tep, system, event, axes);
333	}
334	if (!hist) {
335		fprintf(stderr, "Failed hist create\n");
336		exit(-1);
337	}
338
339	if (vals) {
340		sav = NULL;
341		for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
342			ret = tracefs_hist_add_value(hist, val);
343			if (ret) {
344				fprintf(stderr, "Failed to add value %s\n", val);
345				exit(-1);
346			}
347		}
348	}
349
350	if (sort) {
351		sav = NULL;
352		for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
353			ret = tracefs_hist_add_sort_key(hist, val);
354			if (ret) {
355				fprintf(stderr, "Failed to add sort key/val %s\n", val);
356				exit(-1);
357			}
358		}
359	}
360
361	if (ascend) {
362		sav = NULL;
363		for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
364			ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING);
365			if (ret) {
366				fprintf(stderr, "Failed to add ascending key/val %s\n", val);
367				exit(-1);
368			}
369		}
370	}
371
372	if (desc) {
373		sav = NULL;
374		for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
375			ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING);
376			if (ret) {
377				fprintf(stderr, "Failed to add descending key/val %s\n", val);
378				exit(-1);
379			}
380		}
381	}
382
383	tracefs_error_clear(instance);
384
385	switch (cmd) {
386	case START:
387		ret = tracefs_hist_start(instance, hist);
388		if (ret) {
389			char *err = tracefs_error_last(instance);
390			if (err)
391				fprintf(stderr, "\n%s\n", err);
392		}
393		break;
394	case PAUSE:
395		ret = tracefs_hist_pause(instance, hist);
396		break;
397	case CONT:
398		ret = tracefs_hist_continue(instance, hist);
399		break;
400	case RESET:
401		ret = tracefs_hist_reset(instance, hist);
402		break;
403	case DELETE:
404		ret = tracefs_hist_destroy(instance, hist);
405		break;
406	case SHOW:
407		/* Show was already done */
408		break;
409	}
410	if (ret)
411		fprintf(stderr, "Failed: command\n");
412	exit(ret);
413}
414
415int main (int argc, char **argv, char **env)
416{
417	enum commands cmd;
418	char *instance = NULL;
419	char *cmd_str;
420	char *event = NULL;
421	char *keys = NULL;
422	char *vals = NULL;
423	char *sort = NULL;
424	char *desc = NULL;
425	char *ascend = NULL;
426
427	if (argc < 2) {
428		fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]);
429		fprintf(stderr, "      [-a ascending][-d descending]\n");
430		exit(-1);
431	}
432
433	cmd_str = argv[1];
434
435	if (!strcmp(cmd_str, "start"))
436		cmd = START;
437	else if (!strcmp(cmd_str, "pause"))
438		cmd = PAUSE;
439	else if (!strcmp(cmd_str, "cont"))
440		cmd = CONT;
441	else if (!strcmp(cmd_str, "reset"))
442		cmd = RESET;
443	else if (!strcmp(cmd_str, "delete"))
444		cmd = DELETE;
445	else if (!strcmp(cmd_str, "show"))
446		cmd = SHOW;
447	else {
448		fprintf(stderr, "Unknown command %s\n", cmd_str);
449		exit(-1);
450	}
451
452	for (;;) {
453		int c;
454
455		c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:");
456		if (c == -1)
457			break;
458
459		switch (c) {
460		case 'e':
461			event = optarg;
462			break;
463		case 'k':
464			keys = optarg;
465			break;
466		case 'v':
467			vals = optarg;
468			break;
469		case 'B':
470			instance = optarg;
471			break;
472		case 's':
473			sort = optarg;
474			break;
475		case 'd':
476			desc = optarg;
477			break;
478		case 'a':
479			ascend = optarg;
480			break;
481		}
482	}
483	if (!event) {
484		event = "kmem/kmalloc";
485		if (!keys)
486			keys = "call_site.sym,bytes_req";
487		if (!vals)
488			vals = "bytes_alloc";
489		if (!sort)
490			sort = "bytes_req,bytes_alloc";
491		if (!desc)
492			desc = "bytes_alloc";
493	}
494	process_hist(cmd, instance, event, keys, vals, sort, ascend, desc);
495}
496--
497
498FILES
499-----
500[verse]
501--
502*tracefs.h*
503	Header file to include in order to have access to the library APIs.
504*-ltracefs*
505	Linker switch to add when building a program that uses the library.
506--
507
508SEE ALSO
509--------
510*libtracefs*(3),
511*libtraceevent*(3),
512*trace-cmd*(1),
513*tracefs_hist_pause*(3),
514*tracefs_hist_continue*(3),
515*tracefs_hist_reset*(3)
516
517AUTHOR
518------
519[verse]
520--
521*Steven Rostedt* <[email protected]>
522*Tzvetomir Stoyanov* <[email protected]>
523*sameeruddin shaik* <[email protected]>
524--
525REPORTING BUGS
526--------------
527Report bugs to  <[email protected]>
528
529LICENSE
530-------
531libtracefs is Free Software licensed under the GNU LGPL 2.1
532
533RESOURCES
534---------
535https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
536
537COPYING
538-------
539Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
540the terms of the GNU Public License (GPL).
541