'\" t .\" Title: libtracefs .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 10/08/2022 .\" Manual: libtracefs Manual .\" Source: libtracefs 1.5.0 .\" Language: English .\" .TH "LIBTRACEFS" "3" "10/08/2022" "libtracefs 1\&.5\&.0" "libtracefs Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tracefs_hist_alloc, tracefs_hist_alloc_2d, tracefs_hist_alloc_nd, tracefs_hist_free, tracefs_hist_add_key, tracefs_hist_add_value \- Create and destroy event histograms .SH "SYNOPSIS" .sp .nf \fB#include \fR enum \fBtracefs_hist_key_type\fR { \fBTRACEFS_HIST_KEY_NORMAL\fR = 0, \fBTRACEFS_HIST_KEY_HEX\fR, \fBTRACEFS_HIST_KEY_SYM\fR, \fBTRACEFS_HIST_KEY_SYM_OFFSET\fR, \fBTRACEFS_HIST_KEY_SYSCALL\fR, \fBTRACEFS_HIST_KEY_EXECNAME\fR, \fBTRACEFS_HIST_KEY_LOG\fR, \fBTRACEFS_HIST_KEY_USECS\fR, \fBTRACEFS_HIST_KEY_MAX\fR }; struct \fBtracefs_hist_axis\fR { const char *\fIkey\fR; enum tracefs_hist_key_type \fItype\fR; }; struct tracefs_hist *\fBtracefs_hist_alloc\fR(struct tracefs_tep * \fItep\fR, const char *\fIsystem\fR, const char *\fIevent\fR, const char *\fIkey\fR, enum tracefs_hist_key_type \fItype\fR); struct tracefs_hist *\fBtracefs_hist_alloc_2d\fR(struct tracefs_tep * \fItep\fR, const char *\fIsystem\fR, const char *\fIevent\fR, const char *\fIkey1\fR, enum tracefs_hist_key_type \fItype1\fR, const char *\fIkey2\fR, enum tracefs_hist_key_type \fItype2\fR)); struct tracefs_hist *\fBtracefs_hist_alloc_nd\fR(struct tracefs_tep * \fItep\fR, const char *\fIsystem\fR, const char *\fIevent\fR, struct tracefs_hist_axis *\fIaxes\fR); void \fBtracefs_hist_free\fR(struct tracefs_hist *\fIhist\fR); int \fBtracefs_hist_add_key\fR(struct tracefs_hist *\fIhist\fR, const char *\fIkey\fR, enum tracefs_hist_key_type \fItype\fR); int \fBtracefs_hist_add_value\fR(struct tracefs_hist *\fIhist\fR, const char *\fIvalue\fR); .fi .SH "DESCRIPTION" .sp Event histograms are created by the trigger file in the event directory\&. The syntax can be complex and difficult to get correct\&. This API handles the syntax, and facilitates the creation and interaction with the event histograms\&. See \m[blue]\fBhttps://www\&.kernel\&.org/doc/html/latest/trace/histogram\&.html\fR\m[] for more information\&. .sp \fBtracefs_hist_alloc\fR() allocates a "struct tracefs_hist" descriptor of a one\-dimensional histogram and returns the address of it\&. This descriptor must be freed by \fBtracefs_hist_free\fR()\&. The \fItep\fR is a trace event handle (see \fBtracefs_local_events\fR(3)), that holds the \fIsystem\fR and \fIevent\fR that the histogram will be attached to\&. The \fIsystem\fR is the system or group of the event\&. The \fIevent\fR is the event to attach the histogram to\&. The \fIkey\fR is a field of the event that will be used as the key(dimension) of the histogram\&. The \fItype\fR is the type of the \fIkey\fR\&. See KEY TYPES below\&. .sp \fBtracefs_hist_alloc_2d\fR() allocates a "struct tracefs_hist" descriptor of a two\-dimensional histogram and returns the address of it\&. This descriptor must be freed by \fBtracefs_hist_free\fR()\&. The \fItep\fR is a trace event handle (see \fBtracefs_local_events\fR(3)), that holds the \fIsystem\fR and \fIevent\fR that the histogram will be attached to\&. The \fIsystem\fR is the system or group of the event\&. The \fIevent\fR is the event to attach the histogram to\&. The \fIkey1\fR is the first field of the event that will be used as the key(dimension) of the histogram\&. The \fItype1\fR is the type of the \fIkey1\fR\&. See KEY TYPES below\&. The \fIkey2\fR is the second field of the event that will be used as the key(dimension) of the histogram\&. The \fItype2\fR is the type of the \fIkey2\fR\&. See KEY TYPES below\&. .sp \fBtracefs_hist_alloc_nd\fR() allocates a "struct tracefs_hist" descriptor of an N\-dimensional histogram and returns the address of it\&. This descriptor must be freed by \fBtracefs_hist_free\fR()\&. The \fItep\fR is a trace event handle (see \fBtracefs_local_events\fR(3)), that holds the \fIsystem\fR and \fIevent\fR that the histogram will be attached to\&. The \fIsystem\fR is the system or group of the event\&. The \fIevent\fR is the event to attach the histogram to\&. The \fIaxes\fR is an array of \fIkey\fR / \fItype\fR pairs, defining the dimensions of the histogram\&. .sp \fBtracefs_hist_free\fR() frees the \fItracefs_hist\fR descriptor\&. Note, it does not stop or disable the running histogram if it was started\&. \fBtracefs_hist_destroy\fR() needs to be called to do so\&. .sp \fBtracefs_hist_add_key\fR() Adds a secondary or tertiary key to the histogram\&. The key passed to \fBtracefs_hist_alloc_nd\fR() is the primary key of the histogram\&. The first time this function is called, it will add a secondary key (or two dimensional histogram)\&. If this function is called again on the same histogram, it will add a \fItertiary\fR key (or three dimensional histogram)\&. The \fIhist\fR parameter is the histogram descriptor to add the \fIkey\fR to\&. The \fItype\fR is the type of key to add (See KEY TYPES below)\&. .sp \fBtracefs_hist_add_value\fR() will add a value to record\&. By default, the value is simply the "hitcount" of the number of times a instance of the histogram\(cqs key was hit\&. The \fIhist\fR is the histogram descriptor to add the value to\&. The \fIvalue\fR is a field in the histogram to add to when an instance of the key is hit\&. .SH "KEY TYPES" .sp \fBtracefs_hist_alloc_nd\fR() and \fBtracefs_hist_add_key\fR() both add a key and requires that key to have a type\&. The types may be: .sp \fBTRACEFS_HIST_KEY_NORMAL\fR or zero (0) which is to not modify the type\&. .sp \fBTRACEFS_HIST_KEY_HEX\fR to display the key in hex\&. .sp \fBTRACEFS_HIST_KEY_SYM\fR to display the key as a kernel symbol (if found)\&. If the key is an address, this is useful as it will display the function names instead of just a number\&. .sp \fBTRACEFS_HIST_KEY_SYM_OFFSET\fR similar to \fBTRACEFS_HIST_KEY_SYM\fR but will also include the offset of the function to match the exact address\&. .sp \fBTRACEFS_HIST_KEY_SYSCALL\fR If the key is a system call "id" (the number passed from user space to the kernel to tell it what system call it is calling), then the name of the system call is displayed\&. .sp \fBTRACEFS_HIST_KEY_EXECNAME\fR If "common_pid" is the key (the pid of the executing task), instead of showing the number, show the name of the running task\&. .sp \fBTRACEFS_HIST_KEY_LOG\fR will display the key in a binary logarithmic scale\&. .sp \fBTRACEFS_HIST_KEY_USECS\fR for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP, in which case it will show the timestamp in microseconds instead of nanoseconds\&. .SH "RETURN VALUE" .sp \fBtracefs_hist_alloc_nd\fR() returns an allocated histogram descriptor which must be freed by \fBtracefs_hist_free\fR() or NULL on error\&. .sp All the other functions return zero on success or \-1 on error\&. .sp If \fBtracefs_hist_start\fR() returns an error, a message may be displayed in the kernel that can be retrieved by \fBtracefs_error_last()\fR\&. .SH "EXAMPLE" .sp .if n \{\ .RS 4 .\} .nf #include #include #include enum commands { START, PAUSE, CONT, RESET, DELETE, SHOW, }; static void parse_system_event(char *group, char **system, char **event) { *system = strtok(group, "/"); *event = strtok(NULL, "/"); if (!*event) { *event = *system; *system = NULL; } } static int parse_keys(char *keys, struct tracefs_hist_axis **axes) { char *sav = NULL; char *key; int cnt = 0; for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) { struct tracefs_hist_axis *ax; char *att; ax = realloc(*axes, sizeof(*ax) * (cnt + 2)); if (!ax) { perror("Failed to allocate axes"); exit(\-1); } ax[cnt]\&.key = key; ax[cnt]\&.type = 0; ax[cnt + 1]\&.key = NULL; ax[cnt + 1]\&.type = 0; *axes = ax; att = strchr(key, \*(Aq\&.\*(Aq); if (att) { *att++ = \*(Aq\e0\*(Aq; if (strcmp(att, "hex") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_HEX; else if (strcmp(att, "sym") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_SYM; else if (strcmp(att, "sym_offset") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_SYM_OFFSET; else if (strcmp(att, "syscall") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_SYSCALL; else if (strcmp(att, "exec") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_EXECNAME; else if (strcmp(att, "log") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_LOG; else if (strcmp(att, "usecs") == 0) ax[cnt]\&.type = TRACEFS_HIST_KEY_USECS; else { fprintf(stderr, "Undefined attribute \*(Aq%s\*(Aq\en", att); fprintf(stderr," Acceptable attributes:\en"); fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\en"); exit(\-1); } } cnt++; } return cnt; } static void process_hist(enum commands cmd, const char *instance_name, char *group, char *keys, char *vals, char *sort, char *ascend, char *desc) { struct tracefs_instance *instance = NULL; struct tracefs_hist *hist; struct tep_handle *tep; struct tracefs_hist_axis *axes = NULL; char *system; char *event; char *sav; char *val; int ret; int cnt; if (instance_name) { instance = tracefs_instance_create(instance_name); if (!instance) { fprintf(stderr, "Failed instance create\en"); exit(\-1); } } tep = tracefs_local_events(NULL); if (!tep) { perror("Could not read events"); exit(\-1); } parse_system_event(group, &system, &event); if (cmd == SHOW) { char *content; content = tracefs_event_file_read(instance, system, event, "hist", NULL); if (!content) { perror("Reading hist file"); exit(\-1); } printf("%s\en", content); free(content); return; } if (!keys) { fprintf(stderr, "Command needs \-k option\en"); exit(\-1); } cnt = parse_keys(keys, &axes); if (!cnt) { fprintf(stderr, "No keys??\en"); exit(\-1); } /* Show examples of hist1d and hist2d */ switch (cnt) { case 1: hist = tracefs_hist_alloc(tep, system, event, axes[0]\&.key, axes[0]\&.type); break; case 2: hist = tracefs_hist_alloc_2d(tep, system, event, axes[0]\&.key, axes[0]\&.type, axes[1]\&.key, axes[1]\&.type); break; default: /* Really, 1 and 2 could use this too */ hist = tracefs_hist_alloc_nd(tep, system, event, axes); } if (!hist) { fprintf(stderr, "Failed hist create\en"); exit(\-1); } if (vals) { sav = NULL; for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_add_value(hist, val); if (ret) { fprintf(stderr, "Failed to add value %s\en", val); exit(\-1); } } } if (sort) { sav = NULL; for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_add_sort_key(hist, val); if (ret) { fprintf(stderr, "Failed to add sort key/val %s\en", val); exit(\-1); } } } if (ascend) { sav = NULL; for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING); if (ret) { fprintf(stderr, "Failed to add ascending key/val %s\en", val); exit(\-1); } } } if (desc) { sav = NULL; for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING); if (ret) { fprintf(stderr, "Failed to add descending key/val %s\en", val); exit(\-1); } } } tracefs_error_clear(instance); switch (cmd) { case START: ret = tracefs_hist_start(instance, hist); if (ret) { char *err = tracefs_error_last(instance); if (err) fprintf(stderr, "\en%s\en", err); } break; case PAUSE: ret = tracefs_hist_pause(instance, hist); break; case CONT: ret = tracefs_hist_continue(instance, hist); break; case RESET: ret = tracefs_hist_reset(instance, hist); break; case DELETE: ret = tracefs_hist_destroy(instance, hist); break; case SHOW: /* Show was already done */ break; } if (ret) fprintf(stderr, "Failed: command\en"); exit(ret); } int main (int argc, char **argv, char **env) { enum commands cmd; char *instance = NULL; char *cmd_str; char *event = NULL; char *keys = NULL; char *vals = NULL; char *sort = NULL; char *desc = NULL; char *ascend = NULL; if (argc < 2) { fprintf(stderr, "usage: %s command [\-B instance][\-e [system/]event][\-k keys][\-v vals][\-s sort]\en", argv[0]); fprintf(stderr, " [\-a ascending][\-d descending]\en"); exit(\-1); } cmd_str = argv[1]; if (!strcmp(cmd_str, "start")) cmd = START; else if (!strcmp(cmd_str, "pause")) cmd = PAUSE; else if (!strcmp(cmd_str, "cont")) cmd = CONT; else if (!strcmp(cmd_str, "reset")) cmd = RESET; else if (!strcmp(cmd_str, "delete")) cmd = DELETE; else if (!strcmp(cmd_str, "show")) cmd = SHOW; else { fprintf(stderr, "Unknown command %s\en", cmd_str); exit(\-1); } for (;;) { int c; c = getopt(argc \- 1, argv + 1, "e:k:v:B:s:d:a:"); if (c == \-1) break; switch (c) { case \*(Aqe\*(Aq: event = optarg; break; case \*(Aqk\*(Aq: keys = optarg; break; case \*(Aqv\*(Aq: vals = optarg; break; case \*(AqB\*(Aq: instance = optarg; break; case \*(Aqs\*(Aq: sort = optarg; break; case \*(Aqd\*(Aq: desc = optarg; break; case \*(Aqa\*(Aq: ascend = optarg; break; } } if (!event) { event = "kmem/kmalloc"; if (!keys) keys = "call_site\&.sym,bytes_req"; if (!vals) vals = "bytes_alloc"; if (!sort) sort = "bytes_req,bytes_alloc"; if (!desc) desc = "bytes_alloc"; } process_hist(cmd, instance, event, keys, vals, sort, ascend, desc); } .fi .if n \{\ .RE .\} .SH "FILES" .sp .if n \{\ .RS 4 .\} .nf \fBtracefs\&.h\fR Header file to include in order to have access to the library APIs\&. \fB\-ltracefs\fR Linker switch to add when building a program that uses the library\&. .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBlibtracefs\fR(3), \fBlibtraceevent\fR(3), \fBtrace\-cmd\fR(1), \fBtracefs_hist_pause\fR(3), \fBtracefs_hist_continue\fR(3), \fBtracefs_hist_reset\fR(3) .SH "AUTHOR" .sp .if n \{\ .RS 4 .\} .nf \fBSteven Rostedt\fR <\m[blue]\fBrostedt@goodmis\&.org\fR\m[]\&\s-2\u[1]\d\s+2> \fBTzvetomir Stoyanov\fR <\m[blue]\fBtz\&.stoyanov@gmail\&.com\fR\m[]\&\s-2\u[2]\d\s+2> \fBsameeruddin shaik\fR <\m[blue]\fBsameeruddin\&.shaik8@gmail\&.com\fR\m[]\&\s-2\u[3]\d\s+2> .fi .if n \{\ .RE .\} .SH "REPORTING BUGS" .sp Report bugs to <\m[blue]\fBlinux\-trace\-devel@vger\&.kernel\&.org\fR\m[]\&\s-2\u[4]\d\s+2> .SH "LICENSE" .sp libtracefs is Free Software licensed under the GNU LGPL 2\&.1 .SH "RESOURCES" .sp \m[blue]\fBhttps://git\&.kernel\&.org/pub/scm/libs/libtrace/libtracefs\&.git/\fR\m[] .SH "COPYING" .sp Copyright (C) 2020 VMware, Inc\&. Free use of this software is granted under the terms of the GNU Public License (GPL)\&. .SH "NOTES" .IP " 1." 4 rostedt@goodmis.org .RS 4 \%mailto:rostedt@goodmis.org .RE .IP " 2." 4 tz.stoyanov@gmail.com .RS 4 \%mailto:tz.stoyanov@gmail.com .RE .IP " 3." 4 sameeruddin.shaik8@gmail.com .RS 4 \%mailto:sameeruddin.shaik8@gmail.com .RE .IP " 4." 4 linux-trace-devel@vger.kernel.org .RS 4 \%mailto:linux-trace-devel@vger.kernel.org .RE