• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1libtracefs(3)
2=============
3
4NAME
5----
6tracefs_hist_alloc, tracefs_hist_alloc_2d, tracefs_hist_alloc_nd, tracefs_hist_alloc_nd_cnt, tracefs_hist_free,
7tracefs_hist_add_key, tracefs_hist_add_key_cnt, tracefs_hist_add_value - Create and destroy event histograms
8
9SYNOPSIS
10--------
11[verse]
12--
13*#include <tracefs.h>*
14
15enum *tracefs_hist_key_type* {
16	*TRACEFS_HIST_KEY_NORMAL* = 0,
17	*TRACEFS_HIST_KEY_HEX*,
18	*TRACEFS_HIST_KEY_SYM*,
19	*TRACEFS_HIST_KEY_SYM_OFFSET*,
20	*TRACEFS_HIST_KEY_SYSCALL*,
21	*TRACEFS_HIST_KEY_EXECNAME*,
22	*TRACEFS_HIST_KEY_LOG*,
23	*TRACEFS_HIST_KEY_USECS*,
24	*TRACEFS_HIST_KEY_MAX*
25};
26
27struct *tracefs_hist_axis* {
28	const char pass:[*]_key_;
29	enum tracefs_hist_key_type _type_;
30};
31
32struct tracefs_hist pass:[*]*tracefs_hist_alloc*(struct tracefs_tep pass:[*] _tep_,
33			const char pass:[*]_system_, const char pass:[*]_event_,
34			const char pass:[*]_key_, enum tracefs_hist_key_type _type_);
35struct tracefs_hist pass:[*]*tracefs_hist_alloc_2d*(struct tracefs_tep pass:[*] _tep_,
36			const char pass:[*]_system_, const char pass:[*]_event_,
37			const char pass:[*]_key1_, enum tracefs_hist_key_type _type1_,
38			const char pass:[*]_key2_, enum tracefs_hist_key_type _type2_));
39struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd*(struct tracefs_tep pass:[*] _tep_,
40			const char pass:[*]_system_, const char pass:[*]_event_,
41			struct tracefs_hist_axis pass:[*]_axes_);
42struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd_cnt*(struct tep_handle pass:[*]_tep_,
43			  const char pass:[*]_system_, const char pass:[*]_event_name_,
44			  struct tracefs_hist_axis_cnt pass:[*]_axes_);
45void *tracefs_hist_free*(struct tracefs_hist pass:[*]_hist_);
46
47int *tracefs_hist_add_key*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
48			 enum tracefs_hist_key_type _type_);
49int *tracefs_hist_add_key_cnt*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
50			 enum tracefs_hist_key_type _type_, int _cnt_);
51int *tracefs_hist_add_value*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_value_);
52--
53
54DESCRIPTION
55-----------
56Event histograms are created by the trigger file in the event directory.
57The syntax can be complex and difficult to get correct. This API handles the
58syntax, and facilitates the creation and interaction with the event histograms.
59See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information.
60
61*tracefs_hist_alloc*() allocates a "struct tracefs_hist" descriptor of a one-dimensional
62histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
63The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
64_system_ and _event_ that the histogram will be attached to. The _system_ is the
65system or group of the event. The _event_ is the event to attach the histogram to.
66The _key_ is a field of the event that will be used as the key(dimension) of the histogram.
67The _type_ is the type of the _key_. See KEY TYPES below.
68
69*tracefs_hist_alloc_2d*() allocates a "struct tracefs_hist" descriptor of a two-dimensional
70histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
71The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
72_system_ and _event_ that the histogram will be attached to. The _system_ is the
73system or group of the event. The _event_ is the event to attach the histogram to.
74The _key1_ is the first field of the event that will be used as the key(dimension)
75of the histogram. The _type1_ is the type of the _key1_. See KEY TYPES below.
76The _key2_ is the second field of the event that will be used as the key(dimension)
77of the histogram. The _type2_ is the type of the _key2_. See KEY TYPES below.
78
79*tracefs_hist_alloc_nd*() allocates a "struct tracefs_hist" descriptor of an N-dimensional
80histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
81The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
82_system_ and _event_ that the histogram will be attached to. The _system_ is the
83system or group of the event. The _event_ is the event to attach the histogram to.
84The _axes_ is an array of _key_ / _type_ pairs, defining the dimensions of the histogram.
85
86*tracefs_hist_alloc_nd_cnt*() will initialize a histogram descriptor that will be attached to
87the _system_/_event_. This only initializes the descriptor with the given _axes_ keys as primaries.
88This only initializes the descriptor, it does not start the histogram in the kernel.
89The difference between this and *tracefs_hist_alloc_nd()* is that the _axes_ parameter
90is of type *struct tracefs_hist_axis_cnt* and not *struct tracefs_hist_axis*.
91
92*tracefs_hist_free*() frees the _tracefs_hist_ descriptor. Note, it does not stop
93or disable the running histogram if it was started. *tracefs_hist_destroy*() needs
94to be called to do so.
95
96*tracefs_hist_add_key*() Adds a secondary or tertiary key to the histogram.
97The key passed to *tracefs_hist_alloc_nd*() is the primary key of the histogram.
98The first time this function is called, it will add a secondary key (or two dimensional
99histogram). If this function is called again on the same histogram, it will add
100a _tertiary_ key (or three dimensional histogram). The _hist_ parameter is the
101histogram descriptor to add the _key_ to. The _type_ is the type of key to add
102(See KEY TYPES below).
103
104The *tracefs_hist_add_key_cnt*() is the same as *tracefs_hist_add_key*() except
105that it allows to add a counter for the given type. Currently, there's only
106the *buckets* type that requires a counter. When adding a key with the buckets
107type, *tracefs_hist_add_key*() is not sufficient, as the *buckets* type requires
108a counter or bucket size. Use *tracefs_hist_add_key_cnt*() when specifing
109a key that is broken up into  buckets, and pass in the size of those buckets
110into _cnt_.
111
112*tracefs_hist_add_value*() will add a value to record. By default, the value is
113simply the "hitcount" of the number of times a instance of the histogram's
114key was hit. The _hist_ is the histogram descriptor to add the value to.
115The _value_ is a field in the histogram to add to when an instance of the
116key is hit.
117
118KEY TYPES
119---------
120
121*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires
122that key to have a type. The types may be:
123
124*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type.
125
126*TRACEFS_HIST_KEY_HEX* to display the key in hex.
127
128*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If
129the key is an address, this is useful as it will display the function names instead
130of just a number.
131
132*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include
133the offset of the function to match the exact address.
134
135*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user
136space to the kernel to tell it what system call it is calling), then the name of
137the system call is displayed.
138
139*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task),
140instead of showing the number, show the name of the running task.
141
142*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale.
143
144*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP,
145in which case it will show the timestamp in microseconds instead of nanoseconds.
146
147RETURN VALUE
148------------
149*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must
150be freed by *tracefs_hist_free*() or NULL on error.
151
152All the other functions return zero on success or -1 on error.
153
154If *tracefs_hist_start*() returns an error, a message may be displayed
155in the kernel that can be retrieved by *tracefs_error_last()*.
156
157EXAMPLE
158-------
159[source,c]
160--
161#include <stdlib.h>
162#include <ctype.h>
163#include <unistd.h>
164#include <tracefs.h>
165
166enum commands {
167	START,
168	PAUSE,
169	CONT,
170	RESET,
171	DELETE,
172	SHOW,
173};
174
175static void parse_system_event(char *group, char **system, char **event)
176{
177	*system = strtok(group, "/");
178	*event = strtok(NULL, "/");
179	if (!*event) {
180		*event = *system;
181		*system = NULL;
182	}
183}
184
185static int parse_keys(char *keys, struct tracefs_hist_axis_cnt **axes)
186{
187	char *sav = NULL;
188	char *key;
189	int cnt = 0;
190
191	for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) {
192		struct tracefs_hist_axis_cnt *ax;
193		char *att;
194
195		ax = realloc(*axes, sizeof(*ax) * (cnt + 2));
196		if (!ax) {
197			perror("Failed to allocate axes");
198			exit(-1);
199		}
200		ax[cnt].key = key;
201		ax[cnt].type = 0;
202		ax[cnt + 1].key = NULL;
203		ax[cnt + 1].type = 0;
204
205		*axes = ax;
206
207		att = strchr(key, '.');
208		if (att) {
209			*att++ = '\0';
210			if (strcmp(att, "hex") == 0)
211				ax[cnt].type = TRACEFS_HIST_KEY_HEX;
212			else if (strcmp(att, "sym") == 0)
213				ax[cnt].type = TRACEFS_HIST_KEY_SYM;
214			else if (strcmp(att, "sym_offset") == 0)
215				ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET;
216			else if (strcmp(att, "syscall") == 0)
217				ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL;
218			else if (strcmp(att, "exec") == 0)
219				ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME;
220			else if (strcmp(att, "log") == 0)
221				ax[cnt].type = TRACEFS_HIST_KEY_LOG;
222			else if (strcmp(att, "usecs") == 0)
223				ax[cnt].type = TRACEFS_HIST_KEY_USECS;
224			else if (strncmp(att, "buckets", 7) == 0) {
225				if (att[7] != '=' && !isdigit(att[8])) {
226					fprintf(stderr, "'buckets' key type requires '=<size>'\n");
227					exit(-1);
228				}
229				ax[cnt].type = TRACEFS_HIST_KEY_BUCKETS;
230				ax[cnt].cnt = atoi(&att[8]);
231			} else {
232				fprintf(stderr, "Undefined attribute '%s'\n", att);
233				fprintf(stderr,"  Acceptable attributes:\n");
234				fprintf(stderr,"    hex, sym, sym_offset, syscall, exe, log, usecs\n");
235				exit(-1);
236			}
237		}
238		cnt++;
239	}
240	return cnt;
241}
242
243static void process_hist(enum commands cmd, const char *instance_name,
244			 char *group, char *keys, char *vals, char *sort,
245			 char *ascend, char *desc)
246{
247	struct tracefs_instance *instance = NULL;
248	struct tracefs_hist *hist;
249	struct tep_handle *tep;
250	struct tracefs_hist_axis_cnt *axes = NULL;
251	char *system;
252	char *event;
253	char *sav;
254	char *val;
255	int ret;
256	int cnt;
257
258	if (instance_name) {
259		instance = tracefs_instance_create(instance_name);
260		if (!instance) {
261			fprintf(stderr, "Failed instance create\n");
262			exit(-1);
263		}
264	}
265
266	tep = tracefs_local_events(NULL);
267	if (!tep) {
268		perror("Could not read events");
269		exit(-1);
270	}
271
272	parse_system_event(group, &system, &event);
273
274	if (cmd == SHOW) {
275		char *content;
276		content = tracefs_event_file_read(instance, system, event,
277						  "hist", NULL);
278		if (!content) {
279			perror("Reading hist file");
280			exit(-1);
281		}
282		printf("%s\n", content);
283		free(content);
284		return;
285	}
286
287	if (!keys) {
288		fprintf(stderr, "Command needs -k option\n");
289		exit(-1);
290	}
291
292	cnt = parse_keys(keys, &axes);
293	if (!cnt) {
294		fprintf(stderr, "No keys??\n");
295		exit(-1);
296	}
297
298	/* buckets require the nd_cnt function */
299	switch (cnt) {
300	case 2:
301		if (axes[1].type == TRACEFS_HIST_KEY_BUCKETS)
302			cnt = -1;
303		/* fall through */
304	case 1:
305		if (axes[0].type == TRACEFS_HIST_KEY_BUCKETS)
306			cnt = -1;
307	}
308
309	/* Show examples of hist1d and hist2d */
310	switch (cnt) {
311	case 1:
312		hist = tracefs_hist_alloc(tep, system, event,
313					  axes[0].key, axes[0].type);
314		break;
315	case 2:
316		hist = tracefs_hist_alloc_2d(tep, system, event,
317					     axes[0].key, axes[0].type,
318					     axes[1].key, axes[1].type);
319		break;
320	default:
321		/* Really, 1 and 2 could use this too */
322		hist = tracefs_hist_alloc_nd_cnt(tep, system, event, axes);
323	}
324	if (!hist) {
325		fprintf(stderr, "Failed hist create\n");
326		exit(-1);
327	}
328
329	if (vals) {
330		sav = NULL;
331		for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
332			ret = tracefs_hist_add_value(hist, val);
333			if (ret) {
334				fprintf(stderr, "Failed to add value %s\n", val);
335				exit(-1);
336			}
337		}
338	}
339
340	if (sort) {
341		sav = NULL;
342		for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
343			ret = tracefs_hist_add_sort_key(hist, val);
344			if (ret) {
345				fprintf(stderr, "Failed to add sort key/val %s\n", val);
346				exit(-1);
347			}
348		}
349	}
350
351	if (ascend) {
352		sav = NULL;
353		for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
354			ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING);
355			if (ret) {
356				fprintf(stderr, "Failed to add ascending key/val %s\n", val);
357				exit(-1);
358			}
359		}
360	}
361
362	if (desc) {
363		sav = NULL;
364		for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
365			ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING);
366			if (ret) {
367				fprintf(stderr, "Failed to add descending key/val %s\n", val);
368				exit(-1);
369			}
370		}
371	}
372
373	tracefs_error_clear(instance);
374
375	switch (cmd) {
376	case START:
377		ret = tracefs_hist_start(instance, hist);
378		if (ret) {
379			char *err = tracefs_error_last(instance);
380			if (err)
381				fprintf(stderr, "\n%s\n", err);
382		}
383		break;
384	case PAUSE:
385		ret = tracefs_hist_pause(instance, hist);
386		break;
387	case CONT:
388		ret = tracefs_hist_continue(instance, hist);
389		break;
390	case RESET:
391		ret = tracefs_hist_reset(instance, hist);
392		break;
393	case DELETE:
394		ret = tracefs_hist_destroy(instance, hist);
395		break;
396	case SHOW:
397		/* Show was already done */
398		break;
399	}
400	if (ret)
401		fprintf(stderr, "Failed: command\n");
402	exit(ret);
403}
404
405int main (int argc, char **argv, char **env)
406{
407	enum commands cmd;
408	char *instance = NULL;
409	char *cmd_str;
410	char *event = NULL;
411	char *keys = NULL;
412	char *vals = NULL;
413	char *sort = NULL;
414	char *desc = NULL;
415	char *ascend = NULL;
416
417	if (argc < 2) {
418		fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]);
419		fprintf(stderr, "      [-a ascending][-d descending]\n");
420		exit(-1);
421	}
422
423	cmd_str = argv[1];
424
425	if (!strcmp(cmd_str, "start"))
426		cmd = START;
427	else if (!strcmp(cmd_str, "pause"))
428		cmd = PAUSE;
429	else if (!strcmp(cmd_str, "cont"))
430		cmd = CONT;
431	else if (!strcmp(cmd_str, "reset"))
432		cmd = RESET;
433	else if (!strcmp(cmd_str, "delete"))
434		cmd = DELETE;
435	else if (!strcmp(cmd_str, "show"))
436		cmd = SHOW;
437	else {
438		fprintf(stderr, "Unknown command %s\n", cmd_str);
439		exit(-1);
440	}
441
442	for (;;) {
443		int c;
444
445		c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:");
446		if (c == -1)
447			break;
448
449		switch (c) {
450		case 'e':
451			event = optarg;
452			break;
453		case 'k':
454			keys = optarg;
455			break;
456		case 'v':
457			vals = optarg;
458			break;
459		case 'B':
460			instance = optarg;
461			break;
462		case 's':
463			sort = optarg;
464			break;
465		case 'd':
466			desc = optarg;
467			break;
468		case 'a':
469			ascend = optarg;
470			break;
471		}
472	}
473	if (!event) {
474		event = "kmem/kmalloc";
475		if (!keys)
476			keys = "call_site.sym,bytes_req";
477		if (!vals)
478			vals = "bytes_alloc";
479		if (!sort)
480			sort = "bytes_req,bytes_alloc";
481		if (!desc)
482			desc = "bytes_alloc";
483	}
484	process_hist(cmd, instance, event, keys, vals, sort, ascend, desc);
485}
486
487--
488
489FILES
490-----
491[verse]
492--
493*tracefs.h*
494	Header file to include in order to have access to the library APIs.
495*-ltracefs*
496	Linker switch to add when building a program that uses the library.
497--
498
499SEE ALSO
500--------
501*libtracefs*(3),
502*libtraceevent*(3),
503*trace-cmd*(1),
504*tracefs_hist_pause*(3),
505*tracefs_hist_continue*(3),
506*tracefs_hist_reset*(3)
507
508AUTHOR
509------
510[verse]
511--
512*Steven Rostedt* <rostedt@goodmis.org>
513*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>
514*sameeruddin shaik* <sameeruddin.shaik8@gmail.com>
515--
516REPORTING BUGS
517--------------
518Report bugs to  <linux-trace-devel@vger.kernel.org>
519
520LICENSE
521-------
522libtracefs is Free Software licensed under the GNU LGPL 2.1
523
524RESOURCES
525---------
526https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
527
528COPYING
529-------
530Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
531the terms of the GNU Public License (GPL).
532