summaryrefslogtreecommitdiffstats
path: root/Documentation/libtracefs-hist.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/libtracefs-hist.txt')
-rw-r--r--Documentation/libtracefs-hist.txt531
1 files changed, 531 insertions, 0 deletions
diff --git a/Documentation/libtracefs-hist.txt b/Documentation/libtracefs-hist.txt
new file mode 100644
index 0000000..7503fd0
--- /dev/null
+++ b/Documentation/libtracefs-hist.txt
@@ -0,0 +1,531 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_hist_alloc, tracefs_hist_alloc_2d, tracefs_hist_alloc_nd, tracefs_hist_alloc_nd_cnt, tracefs_hist_free,
+tracefs_hist_add_key, tracefs_hist_add_key_cnt, tracefs_hist_add_value - Create and destroy event histograms
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+enum *tracefs_hist_key_type* {
+ *TRACEFS_HIST_KEY_NORMAL* = 0,
+ *TRACEFS_HIST_KEY_HEX*,
+ *TRACEFS_HIST_KEY_SYM*,
+ *TRACEFS_HIST_KEY_SYM_OFFSET*,
+ *TRACEFS_HIST_KEY_SYSCALL*,
+ *TRACEFS_HIST_KEY_EXECNAME*,
+ *TRACEFS_HIST_KEY_LOG*,
+ *TRACEFS_HIST_KEY_USECS*,
+ *TRACEFS_HIST_KEY_MAX*
+};
+
+struct *tracefs_hist_axis* {
+ const char pass:[*]_key_;
+ enum tracefs_hist_key_type _type_;
+};
+
+struct tracefs_hist pass:[*]*tracefs_hist_alloc*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key_, enum tracefs_hist_key_type _type_);
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_2d*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key1_, enum tracefs_hist_key_type _type1_,
+ const char pass:[*]_key2_, enum tracefs_hist_key_type _type2_));
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ struct tracefs_hist_axis pass:[*]_axes_);
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd_cnt*(struct tep_handle pass:[*]_tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_name_,
+ struct tracefs_hist_axis_cnt pass:[*]_axes_);
+void *tracefs_hist_free*(struct tracefs_hist pass:[*]_hist_);
+
+int *tracefs_hist_add_key*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_);
+int *tracefs_hist_add_key_cnt*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_, int _cnt_);
+int *tracefs_hist_add_value*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_value_);
+--
+
+DESCRIPTION
+-----------
+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 https://www.kernel.org/doc/html/latest/trace/histogram.html for more information.
+
+*tracefs_hist_alloc*() allocates a "struct tracefs_hist" descriptor of a one-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _key_ is a field of the event that will be used as the key(dimension) of the histogram.
+The _type_ is the type of the _key_. See KEY TYPES below.
+
+*tracefs_hist_alloc_2d*() allocates a "struct tracefs_hist" descriptor of a two-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _key1_ is the first field of the event that will be used as the key(dimension)
+of the histogram. The _type1_ is the type of the _key1_. See KEY TYPES below.
+The _key2_ is the second field of the event that will be used as the key(dimension)
+of the histogram. The _type2_ is the type of the _key2_. See KEY TYPES below.
+
+*tracefs_hist_alloc_nd*() allocates a "struct tracefs_hist" descriptor of an N-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _axes_ is an array of _key_ / _type_ pairs, defining the dimensions of the histogram.
+
+*tracefs_hist_alloc_nd_cnt*() will initialize a histogram descriptor that will be attached to
+the _system_/_event_. This only initializes the descriptor with the given _axes_ keys as primaries.
+This only initializes the descriptor, it does not start the histogram in the kernel.
+The difference between this and *tracefs_hist_alloc_nd()* is that the _axes_ parameter
+is of type *struct tracefs_hist_axis_cnt* and not *struct tracefs_hist_axis*.
+
+*tracefs_hist_free*() frees the _tracefs_hist_ descriptor. Note, it does not stop
+or disable the running histogram if it was started. *tracefs_hist_destroy*() needs
+to be called to do so.
+
+*tracefs_hist_add_key*() Adds a secondary or tertiary key to the histogram.
+The key passed to *tracefs_hist_alloc_nd*() 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 _tertiary_ key (or three dimensional histogram). The _hist_ parameter is the
+histogram descriptor to add the _key_ to. The _type_ is the type of key to add
+(See KEY TYPES below).
+
+The *tracefs_hist_add_key_cnt*() is the same as *tracefs_hist_add_key*() except
+that it allows to add a counter for the given type. Currently, there's only
+the *buckets* type that requires a counter. When adding a key with the buckets
+type, *tracefs_hist_add_key*() is not sufficient, as the *buckets* type requires
+a counter or bucket size. Use *tracefs_hist_add_key_cnt*() when specifing
+a key that is broken up into buckets, and pass in the size of those buckets
+into _cnt_.
+
+*tracefs_hist_add_value*() will add a value to record. By default, the value is
+simply the "hitcount" of the number of times a instance of the histogram's
+key was hit. The _hist_ is the histogram descriptor to add the value to.
+The _value_ is a field in the histogram to add to when an instance of the
+key is hit.
+
+KEY TYPES
+---------
+
+*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires
+that key to have a type. The types may be:
+
+*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type.
+
+*TRACEFS_HIST_KEY_HEX* to display the key in hex.
+
+*TRACEFS_HIST_KEY_SYM* 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.
+
+*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include
+the offset of the function to match the exact address.
+
+*TRACEFS_HIST_KEY_SYSCALL* 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.
+
+*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task),
+instead of showing the number, show the name of the running task.
+
+*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale.
+
+*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP,
+in which case it will show the timestamp in microseconds instead of nanoseconds.
+
+RETURN VALUE
+------------
+*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must
+be freed by *tracefs_hist_free*() or NULL on error.
+
+All the other functions return zero on success or -1 on error.
+
+If *tracefs_hist_start*() returns an error, a message may be displayed
+in the kernel that can be retrieved by *tracefs_error_last()*.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+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_cnt **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_cnt *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, '.');
+ if (att) {
+ *att++ = '\0';
+ 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 if (strncmp(att, "buckets", 7) == 0) {
+ if (att[7] != '=' && !isdigit(att[8])) {
+ fprintf(stderr, "'buckets' key type requires '=<size>'\n");
+ exit(-1);
+ }
+ ax[cnt].type = TRACEFS_HIST_KEY_BUCKETS;
+ ax[cnt].cnt = atoi(&att[8]);
+ } else {
+ fprintf(stderr, "Undefined attribute '%s'\n", att);
+ fprintf(stderr," Acceptable attributes:\n");
+ fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\n");
+ 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_cnt *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\n");
+ 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\n", content);
+ free(content);
+ return;
+ }
+
+ if (!keys) {
+ fprintf(stderr, "Command needs -k option\n");
+ exit(-1);
+ }
+
+ cnt = parse_keys(keys, &axes);
+ if (!cnt) {
+ fprintf(stderr, "No keys??\n");
+ exit(-1);
+ }
+
+ /* buckets require the nd_cnt function */
+ switch (cnt) {
+ case 2:
+ if (axes[1].type == TRACEFS_HIST_KEY_BUCKETS)
+ cnt = -1;
+ /* fall through */
+ case 1:
+ if (axes[0].type == TRACEFS_HIST_KEY_BUCKETS)
+ cnt = -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_cnt(tep, system, event, axes);
+ }
+ if (!hist) {
+ fprintf(stderr, "Failed hist create\n");
+ 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\n", 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\n", 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\n", 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\n", 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, "\n%s\n", 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\n");
+ 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]\n", argv[0]);
+ fprintf(stderr, " [-a ascending][-d descending]\n");
+ 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\n", 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 'e':
+ event = optarg;
+ break;
+ case 'k':
+ keys = optarg;
+ break;
+ case 'v':
+ vals = optarg;
+ break;
+ case 'B':
+ instance = optarg;
+ break;
+ case 's':
+ sort = optarg;
+ break;
+ case 'd':
+ desc = optarg;
+ break;
+ case 'a':
+ 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);
+}
+
+--
+
+FILES
+-----
+[verse]
+--
+*tracefs.h*
+ Header file to include in order to have access to the library APIs.
+*-ltracefs*
+ Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1),
+*tracefs_hist_pause*(3),
+*tracefs_hist_continue*(3),
+*tracefs_hist_reset*(3)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>
+*sameeruddin shaik* <sameeruddin.shaik8@gmail.com>
+--
+REPORTING BUGS
+--------------
+Report bugs to <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtracefs is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
+
+COPYING
+-------
+Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).