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