'\" 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_add_sort_key, tracefs_hist_set_sort_key, tracefs_hist_sort_key_direction, tracefs_hist_add_name, tracefs_hist_append_filter, tracefs_hist_echo_cmd, tracefs_hist_command, tracefs_hist_get_name, tracefs_hist_get_event, tracefs_hist_get_system \- Update and describe an event histogram .SH "SYNOPSIS" .sp .nf \fB#include \fR int \fBtracefs_hist_add_sort_key\fR(struct tracefs_hist *\fIhist\fR, const char *\fIsort_key\fR); int \fBtracefs_hist_set_sort_key\fR(struct tracefs_hist *\fIhist\fR, const char *\fIsort_key\fR, \fI\&...\fR); int \fBtracefs_hist_sort_key_direction\fR(struct tracefs_hist *\fIhist\fR, const char *\fIsort_key\fR, enum tracefs_hist_sort_direction \fIdir\fR); int \fBtracefs_hist_add_name\fR(struct tracefs_hist *\fIhist\fR, const char *\fIname\fR); int \fBtracefs_hist_append_filter\fR(struct tracefs_hist *\fIhist\fR, enum tracefs_filter \fItype\fR, const char *\fIfield\fR, enum tracefs_compare \fIcompare\fR, const char *\fIval\fR); int \fBtracefs_hist_echo_cmd\fR(struct trace_seq *\fIs\fR, struct tracefs_instance *\fIinstance\fR, struct tracefs_hist *\fIhist\fR, enum tracefs_hist_command \fIcommand\fR); int \fBtracefs_hist_command\fR(struct tracefs_instance *\fIinstance\fR, struct tracefs_hist *\fIhist\fR, enum tracefs_hist_command \fIcommand\fR); const char *\fBtracefs_hist_get_name\fR(struct tracefs_hist *\fIhist\fR); const char *\fBtracefs_hist_get_event\fR(struct tracefs_hist *\fIhist\fR); const char *\fBtracefs_hist_get_system\fR(struct tracefs_hist *\fIhist\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_add_sort_key\fR() will add a key to sort on\&. The \fIhist\fR is the histogram descriptor to add the sort key to\&. The \fIsort_key\fR is a string that must match either an already defined key of the histogram, or an already defined value\&. If \fIhist\fR already has sorting keys (previously added) the new \fIsort_key\fR will have lower priority(be secondary or so on) when sorting\&. .sp \fBtracefs_hist_set_sort_key\fR() will reset the list of key to sort on\&. The \fIhist\fR is the histogram descriptor to reset the sort key to\&. The \fIsort_key\fR is a string that must match either an already defined key of the histogram, or an already defined value\&. Multiple sort keys may be added to denote a secondary, sort order and so on, but all sort keys must match an existing key or value, or be TRACEFS_HIST_HITCOUNT\&. The last parameter of \fBtracefs_hist_add_sort_key\fR() must be NULL\&. .sp \fBtracefs_hist_sort_key_direction\fR() allows to change the direction of an existing sort key of \fIhist\fR\&. The \fIsort_key\fR is the sort key to change, and \fIdir\fR can be either TRACEFS_HIST_SORT_ASCENDING or TRACEFS_HIST_SORT_DESCENDING, to make the direction of the sort key either ascending or descending respectively\&. .sp \fBtracefs_hist_add_name\fR() adds a name to a histogram\&. A histogram may be named and if the name matches between more than one event, and they have compatible keys, the multiple histograms with the same name will be merged into a single histogram (shown by either event\(cqs hist file)\&. The \fIhist\fR is the histogram to name, and the \fIname\fR is the name to give it\&. .sp \fBtracefs_hist_append_filter\fR() creates a filter or appends to it for the histogram event\&. Depending on \fItype\fR, it will build a string of tokens for parenthesis or logic statements, or it may add a comparison of \fIfield\fR to \fIval\fR based on \fIcompare\fR\&. .sp If \fItype\fR is: \fBTRACEFS_FILTER_COMPARE\fR \- See below \fBTRACEFS_FILTER_AND\fR \- Append "&&" to the filter \fBTRACEFS_FILTER_OR\fR \- Append "||" to the filter \fBTRACEFS_FILTER_NOT\fR \- Append "!" to the filter \fBTRACEFS_FILTER_OPEN_PAREN\fR \- Append "(" to the filter \fBTRACEFS_FILTER_CLOSE_PAREN\fR \- Append ")" to the filter .sp \fIfield\fR, \fIcompare\fR, and \fIval\fR are ignored unless \fItype\fR is equal to \fBTRACEFS_FILTER_COMPARE\fR, then \fIcompare\fR will be used for the following: .sp \fBTRACEFS_COMPARE_EQ\fR \- \fIfield\fR == \fIval\fR .sp \fBTRACEFS_COMPARE_NE\fR \- \fIfield\fR != \fIval\fR .sp \fBTRACEFS_COMPARE_GT\fR \- \fIfield\fR > \fIval\fR .sp \fBTRACEFS_COMPARE_GE\fR \- \fIfield\fR >= \fIval\fR .sp \fBTRACEFS_COMPARE_LT\fR \- \fIfield\fR < \fIval\fR .sp \fBTRACEFS_COMPARE_LE\fR \- \fIfield\fR <= \fIval\fR .sp \fBTRACEFS_COMPARE_RE\fR \- \fIfield\fR ~ "\fIval\fR" : where \fIfield\fR is a string\&. .sp \fBTRACEFS_COMPARE_AND\fR \- \fIfield\fR & \fIval\fR : where \fIfield\fR is a flags field\&. .sp \fBtrace_hist_echo_cmd\fR() prints the commands needed to create the given histogram in the given \fIinstance\fR, or NULL for the top level, into the \fIseq\fR\&. The command that is printed is described by \fIcommand\fR and shows the functionality that would be done by \fBtracefs_hist_command\fR(3)\&. .sp \fBtracefs_hist_command\fR() is called to process a command on the histogram \fIhist\fR for its event in the given \fIinstance\fR, or NULL for the top level\&. The \fIcmd\fR can be one of: .sp \fBTRACEFS_HIST_CMD_START\fR or zero to start execution of the histogram\&. .sp \fBTRACEFS_HIST_CMD_PAUSE\fR to pause the given histogram\&. .sp \fBTRACEFS_HIST_CMD_CONT\fR to continue a paused histogram\&. .sp \fBTRACEFS_HIST_CMD_CLEAR\fR to reset the values of a histogram\&. .sp \fBTRACEFS_HIST_CMD_DESTROY\fR to destroy the histogram (undo a START)\&. .sp The below functions are wrappers to tracefs_hist_command() to make the calling conventions a bit easier to understand what is happening\&. .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_get_name\fR() returns the name of the histogram or NULL on error\&. The returned string belongs to the histogram object and is freed with the histogram by \fBtracefs_hist_free\fR()\&. .sp \fBtracefs_hist_get_event\fR() returns the event name of the histogram or NULL on error\&. The returned string belongs to the histogram object and is freed with the histogram by \fBtracefs_hist_free\fR()\&. .sp \fBtracefs_hist_get_system\fR() returns the system name of the histogram or NULL on error\&. The returned string belongs to the histogram object and is freed with the histogram by \fBtracefs_hist_free\fR()\&. .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 \fBtracefs_hist_get_name\fR(), \fBtracefs_hist_get_event\fR() and \fBtracefs_hist_get_system\fR() return strings owned by the histogram object\&. .sp All the other functions return zero on success or \-1 on error\&. .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