'\" 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