diff options
Diffstat (limited to 'Documentation/libtracefs-hist-mod.txt')
-rw-r--r-- | Documentation/libtracefs-hist-mod.txt | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/Documentation/libtracefs-hist-mod.txt b/Documentation/libtracefs-hist-mod.txt new file mode 100644 index 0000000..b308c7e --- /dev/null +++ b/Documentation/libtracefs-hist-mod.txt @@ -0,0 +1,540 @@ +libtracefs(3) +============= + +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 + +SYNOPSIS +-------- +[verse] +-- +*#include <tracefs.h>* + +int *tracefs_hist_add_sort_key*(struct tracefs_hist pass:[*]_hist_, + const char pass:[*]_sort_key_); + +int *tracefs_hist_set_sort_key*(struct tracefs_hist pass:[*]_hist_, + const char pass:[*]_sort_key_, _..._); +int *tracefs_hist_sort_key_direction*(struct tracefs_hist pass:[*]_hist_, + const char pass:[*]_sort_key_, + enum tracefs_hist_sort_direction _dir_); + +int *tracefs_hist_add_name*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_name_); + +int *tracefs_hist_append_filter*(struct tracefs_hist pass:[*]_hist_, + enum tracefs_filter _type_, + const char pass:[*]_field_, + enum tracefs_compare _compare_, + const char pass:[*]_val_); + +int *tracefs_hist_echo_cmd*(struct trace_seq pass:[*]_s_, struct tracefs_instance pass:[*]_instance_, + struct tracefs_hist pass:[*]_hist_, + enum tracefs_hist_command _command_); + +int *tracefs_hist_command*(struct tracefs_instance pass:[*]_instance_, + struct tracefs_hist pass:[*]_hist_, + enum tracefs_hist_command _command_); + +const char pass:[*]*tracefs_hist_get_name*(struct tracefs_hist pass:[*]_hist_); + +const char pass:[*]*tracefs_hist_get_event*(struct tracefs_hist pass:[*]_hist_); + +const char pass:[*]*tracefs_hist_get_system*(struct tracefs_hist pass:[*]_hist_); + +-- + +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_add_sort_key*() will add a key to sort on. The _hist_ is the +histogram descriptor to add the sort key to. The _sort_key_ is a string +that must match either an already defined key of the histogram, or an already +defined value. If _hist_ already has sorting keys (previously added) the new +_sort_key_ will have lower priority(be secondary or so on) when sorting. + +*tracefs_hist_set_sort_key*() will reset the list of key to sort on. The _hist_ is +the histogram descriptor to reset the sort key to. The _sort_key_ 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 *tracefs_hist_add_sort_key*() must +be NULL. + +*tracefs_hist_sort_key_direction*() allows to change the direction of an +existing sort key of _hist_. The _sort_key_ is the sort key to change, and +_dir_ 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. + +*tracefs_hist_add_name*() 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's hist file). The _hist_ +is the histogram to name, and the _name_ is the name to give it. + +*tracefs_hist_append_filter*() creates a filter or appends to it for the +histogram event. Depending on _type_, it will build a string of tokens for +parenthesis or logic statements, or it may add a comparison of _field_ +to _val_ based on _compare_. + +If _type_ is: +*TRACEFS_FILTER_COMPARE* - See below +*TRACEFS_FILTER_AND* - Append "&&" to the filter +*TRACEFS_FILTER_OR* - Append "||" to the filter +*TRACEFS_FILTER_NOT* - Append "!" to the filter +*TRACEFS_FILTER_OPEN_PAREN* - Append "(" to the filter +*TRACEFS_FILTER_CLOSE_PAREN* - Append ")" to the filter + +_field_, _compare_, and _val_ are ignored unless _type_ is equal to +*TRACEFS_FILTER_COMPARE*, then _compare_ will be used for the following: + +*TRACEFS_COMPARE_EQ* - _field_ == _val_ + +*TRACEFS_COMPARE_NE* - _field_ != _val_ + +*TRACEFS_COMPARE_GT* - _field_ > _val_ + +*TRACEFS_COMPARE_GE* - _field_ >= _val_ + +*TRACEFS_COMPARE_LT* - _field_ < _val_ + +*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_ + +*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string. + +*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field. + +*trace_hist_echo_cmd*() prints the commands needed to create the given histogram +in the given _instance_, or NULL for the top level, into the _seq_. +The command that is printed is described by _command_ and shows the functionality +that would be done by *tracefs_hist_command*(3). + +*tracefs_hist_command*() is called to process a command on the histogram +_hist_ for its event in the given _instance_, or NULL for the top level. +The _cmd_ can be one of: + +*TRACEFS_HIST_CMD_START* or zero to start execution of the histogram. + +*TRACEFS_HIST_CMD_PAUSE* to pause the given histogram. + +*TRACEFS_HIST_CMD_CONT* to continue a paused histogram. + +*TRACEFS_HIST_CMD_CLEAR* to reset the values of a histogram. + +*TRACEFS_HIST_CMD_DESTROY* to destroy the histogram (undo a START). + +The below functions are wrappers to tracefs_hist_command() to make the +calling conventions a bit easier to understand what is happening. + +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_get_name*() 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 *tracefs_hist_free*(). + +*tracefs_hist_get_event*() 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 *tracefs_hist_free*(). + +*tracefs_hist_get_system*() 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 *tracefs_hist_free*(). + +*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must +be freed by *tracefs_hist_free*() or NULL on error. + +*tracefs_hist_get_name*(), *tracefs_hist_get_event*() and *tracefs_hist_get_system*() +return strings owned by the histogram object. + +All the other functions return zero on success or -1 on error. + +EXAMPLE +------- +[source,c] +-- +#include <stdlib.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 **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, '.'); + 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 { + 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 *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); + } + + /* 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\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). |