1libtracefs(3) 2============= 3 4NAME 5---- 6tracefs_hist_add_sort_key, tracefs_hist_set_sort_key, tracefs_hist_sort_key_direction, 7tracefs_hist_add_name, tracefs_hist_append_filter, tracefs_hist_echo_cmd, tracefs_hist_command, 8tracefs_hist_get_name, tracefs_hist_get_event, tracefs_hist_get_system - Update and describe an event histogram 9 10SYNOPSIS 11-------- 12[verse] 13-- 14*#include <tracefs.h>* 15 16int *tracefs_hist_add_sort_key*(struct tracefs_hist pass:[*]_hist_, 17 const char pass:[*]_sort_key_); 18 19int *tracefs_hist_set_sort_key*(struct tracefs_hist pass:[*]_hist_, 20 const char pass:[*]_sort_key_, _..._); 21int *tracefs_hist_sort_key_direction*(struct tracefs_hist pass:[*]_hist_, 22 const char pass:[*]_sort_key_, 23 enum tracefs_hist_sort_direction _dir_); 24 25int *tracefs_hist_add_name*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_name_); 26 27int *tracefs_hist_append_filter*(struct tracefs_hist pass:[*]_hist_, 28 enum tracefs_filter _type_, 29 const char pass:[*]_field_, 30 enum tracefs_compare _compare_, 31 const char pass:[*]_val_); 32 33int *tracefs_hist_echo_cmd*(struct trace_seq pass:[*]_s_, struct tracefs_instance pass:[*]_instance_, 34 struct tracefs_hist pass:[*]_hist_, 35 enum tracefs_hist_command _command_); 36 37int *tracefs_hist_command*(struct tracefs_instance pass:[*]_instance_, 38 struct tracefs_hist pass:[*]_hist_, 39 enum tracefs_hist_command _command_); 40 41const char pass:[*]*tracefs_hist_get_name*(struct tracefs_hist pass:[*]_hist_); 42 43const char pass:[*]*tracefs_hist_get_event*(struct tracefs_hist pass:[*]_hist_); 44 45const char pass:[*]*tracefs_hist_get_system*(struct tracefs_hist pass:[*]_hist_); 46 47-- 48 49DESCRIPTION 50----------- 51Event histograms are created by the trigger file in the event directory. 52The syntax can be complex and difficult to get correct. This API handles the 53syntax, and facilitates the creation and interaction with the event histograms. 54See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information. 55 56*tracefs_hist_add_sort_key*() will add a key to sort on. The _hist_ is the 57histogram descriptor to add the sort key to. The _sort_key_ is a string 58that must match either an already defined key of the histogram, or an already 59defined value. If _hist_ already has sorting keys (previously added) the new 60_sort_key_ will have lower priority(be secondary or so on) when sorting. 61 62*tracefs_hist_set_sort_key*() will reset the list of key to sort on. The _hist_ is 63the histogram descriptor to reset the sort key to. The _sort_key_ is a string 64that must match either an already defined key of the histogram, or an already 65defined value. Multiple sort keys may be added to denote a secondary, sort order 66and so on, but all sort keys must match an existing key or value, or be 67TRACEFS_HIST_HITCOUNT. The last parameter of *tracefs_hist_add_sort_key*() must 68be NULL. 69 70*tracefs_hist_sort_key_direction*() allows to change the direction of an 71existing sort key of _hist_. The _sort_key_ is the sort key to change, and 72_dir_ can be either TRACEFS_HIST_SORT_ASCENDING or TRACEFS_HIST_SORT_DESCENDING, 73to make the direction of the sort key either ascending or descending respectively. 74 75*tracefs_hist_add_name*() adds a name to a histogram. A histogram may be 76named and if the name matches between more than one event, and they have 77compatible keys, the multiple histograms with the same name will be merged 78into a single histogram (shown by either event's hist file). The _hist_ 79is the histogram to name, and the _name_ is the name to give it. 80 81*tracefs_hist_append_filter*() creates a filter or appends to it for the 82histogram event. Depending on _type_, it will build a string of tokens for 83parenthesis or logic statements, or it may add a comparison of _field_ 84to _val_ based on _compare_. 85 86If _type_ is: 87*TRACEFS_FILTER_COMPARE* - See below 88*TRACEFS_FILTER_AND* - Append "&&" to the filter 89*TRACEFS_FILTER_OR* - Append "||" to the filter 90*TRACEFS_FILTER_NOT* - Append "!" to the filter 91*TRACEFS_FILTER_OPEN_PAREN* - Append "(" to the filter 92*TRACEFS_FILTER_CLOSE_PAREN* - Append ")" to the filter 93 94_field_, _compare_, and _val_ are ignored unless _type_ is equal to 95*TRACEFS_FILTER_COMPARE*, then _compare_ will be used for the following: 96 97*TRACEFS_COMPARE_EQ* - _field_ == _val_ 98 99*TRACEFS_COMPARE_NE* - _field_ != _val_ 100 101*TRACEFS_COMPARE_GT* - _field_ > _val_ 102 103*TRACEFS_COMPARE_GE* - _field_ >= _val_ 104 105*TRACEFS_COMPARE_LT* - _field_ < _val_ 106 107*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_ 108 109*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string. 110 111*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field. 112 113*trace_hist_echo_cmd*() prints the commands needed to create the given histogram 114in the given _instance_, or NULL for the top level, into the _seq_. 115The command that is printed is described by _command_ and shows the functionality 116that would be done by *tracefs_hist_command*(3). 117 118*tracefs_hist_command*() is called to process a command on the histogram 119_hist_ for its event in the given _instance_, or NULL for the top level. 120The _cmd_ can be one of: 121 122*TRACEFS_HIST_CMD_START* or zero to start execution of the histogram. 123 124*TRACEFS_HIST_CMD_PAUSE* to pause the given histogram. 125 126*TRACEFS_HIST_CMD_CONT* to continue a paused histogram. 127 128*TRACEFS_HIST_CMD_CLEAR* to reset the values of a histogram. 129 130*TRACEFS_HIST_CMD_DESTROY* to destroy the histogram (undo a START). 131 132The below functions are wrappers to tracefs_hist_command() to make the 133calling conventions a bit easier to understand what is happening. 134 135KEY TYPES 136--------- 137 138*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires 139that key to have a type. The types may be: 140 141*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type. 142 143*TRACEFS_HIST_KEY_HEX* to display the key in hex. 144 145*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If 146the key is an address, this is useful as it will display the function names instead 147of just a number. 148 149*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include 150the offset of the function to match the exact address. 151 152*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user 153space to the kernel to tell it what system call it is calling), then the name of 154the system call is displayed. 155 156*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task), 157instead of showing the number, show the name of the running task. 158 159*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale. 160 161*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP, 162in which case it will show the timestamp in microseconds instead of nanoseconds. 163 164RETURN VALUE 165------------ 166*tracefs_hist_get_name*() returns the name of the histogram or NULL on error. 167The returned string belongs to the histogram object and is freed with the histogram 168by *tracefs_hist_free*(). 169 170*tracefs_hist_get_event*() returns the event name of the histogram or NULL on error. 171The returned string belongs to the histogram object and is freed with the histogram 172by *tracefs_hist_free*(). 173 174*tracefs_hist_get_system*() returns the system name of the histogram or NULL on error. 175The returned string belongs to the histogram object and is freed with the histogram 176by *tracefs_hist_free*(). 177 178*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must 179be freed by *tracefs_hist_free*() or NULL on error. 180 181*tracefs_hist_get_name*(), *tracefs_hist_get_event*() and *tracefs_hist_get_system*() 182return strings owned by the histogram object. 183 184All the other functions return zero on success or -1 on error. 185 186EXAMPLE 187------- 188[source,c] 189-- 190#include <stdlib.h> 191#include <unistd.h> 192#include <tracefs.h> 193 194enum commands { 195 START, 196 PAUSE, 197 CONT, 198 RESET, 199 DELETE, 200 SHOW, 201}; 202 203static void parse_system_event(char *group, char **system, char **event) 204{ 205 *system = strtok(group, "/"); 206 *event = strtok(NULL, "/"); 207 if (!*event) { 208 *event = *system; 209 *system = NULL; 210 } 211} 212 213static int parse_keys(char *keys, struct tracefs_hist_axis **axes) 214{ 215 char *sav = NULL; 216 char *key; 217 int cnt = 0; 218 219 for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) { 220 struct tracefs_hist_axis *ax; 221 char *att; 222 223 ax = realloc(*axes, sizeof(*ax) * (cnt + 2)); 224 if (!ax) { 225 perror("Failed to allocate axes"); 226 exit(-1); 227 } 228 ax[cnt].key = key; 229 ax[cnt].type = 0; 230 ax[cnt + 1].key = NULL; 231 ax[cnt + 1].type = 0; 232 233 *axes = ax; 234 235 att = strchr(key, '.'); 236 if (att) { 237 *att++ = '\0'; 238 if (strcmp(att, "hex") == 0) 239 ax[cnt].type = TRACEFS_HIST_KEY_HEX; 240 else if (strcmp(att, "sym") == 0) 241 ax[cnt].type = TRACEFS_HIST_KEY_SYM; 242 else if (strcmp(att, "sym_offset") == 0) 243 ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET; 244 else if (strcmp(att, "syscall") == 0) 245 ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL; 246 else if (strcmp(att, "exec") == 0) 247 ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME; 248 else if (strcmp(att, "log") == 0) 249 ax[cnt].type = TRACEFS_HIST_KEY_LOG; 250 else if (strcmp(att, "usecs") == 0) 251 ax[cnt].type = TRACEFS_HIST_KEY_USECS; 252 else { 253 fprintf(stderr, "Undefined attribute '%s'\n", att); 254 fprintf(stderr," Acceptable attributes:\n"); 255 fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\n"); 256 exit(-1); 257 } 258 } 259 cnt++; 260 } 261 return cnt; 262} 263 264static void process_hist(enum commands cmd, const char *instance_name, 265 char *group, char *keys, char *vals, char *sort, 266 char *ascend, char *desc) 267{ 268 struct tracefs_instance *instance = NULL; 269 struct tracefs_hist *hist; 270 struct tep_handle *tep; 271 struct tracefs_hist_axis *axes = NULL; 272 char *system; 273 char *event; 274 char *sav; 275 char *val; 276 int ret; 277 int cnt; 278 279 if (instance_name) { 280 instance = tracefs_instance_create(instance_name); 281 if (!instance) { 282 fprintf(stderr, "Failed instance create\n"); 283 exit(-1); 284 } 285 } 286 287 tep = tracefs_local_events(NULL); 288 if (!tep) { 289 perror("Could not read events"); 290 exit(-1); 291 } 292 293 parse_system_event(group, &system, &event); 294 295 if (cmd == SHOW) { 296 char *content; 297 content = tracefs_event_file_read(instance, system, event, 298 "hist", NULL); 299 if (!content) { 300 perror("Reading hist file"); 301 exit(-1); 302 } 303 printf("%s\n", content); 304 free(content); 305 return; 306 } 307 308 if (!keys) { 309 fprintf(stderr, "Command needs -k option\n"); 310 exit(-1); 311 } 312 313 cnt = parse_keys(keys, &axes); 314 if (!cnt) { 315 fprintf(stderr, "No keys??\n"); 316 exit(-1); 317 } 318 319 /* Show examples of hist1d and hist2d */ 320 switch (cnt) { 321 case 1: 322 hist = tracefs_hist_alloc(tep, system, event, 323 axes[0].key, axes[0].type); 324 break; 325 case 2: 326 hist = tracefs_hist_alloc_2d(tep, system, event, 327 axes[0].key, axes[0].type, 328 axes[1].key, axes[1].type); 329 break; 330 default: 331 /* Really, 1 and 2 could use this too */ 332 hist = tracefs_hist_alloc_nd(tep, system, event, axes); 333 } 334 if (!hist) { 335 fprintf(stderr, "Failed hist create\n"); 336 exit(-1); 337 } 338 339 if (vals) { 340 sav = NULL; 341 for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 342 ret = tracefs_hist_add_value(hist, val); 343 if (ret) { 344 fprintf(stderr, "Failed to add value %s\n", val); 345 exit(-1); 346 } 347 } 348 } 349 350 if (sort) { 351 sav = NULL; 352 for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 353 ret = tracefs_hist_add_sort_key(hist, val); 354 if (ret) { 355 fprintf(stderr, "Failed to add sort key/val %s\n", val); 356 exit(-1); 357 } 358 } 359 } 360 361 if (ascend) { 362 sav = NULL; 363 for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 364 ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING); 365 if (ret) { 366 fprintf(stderr, "Failed to add ascending key/val %s\n", val); 367 exit(-1); 368 } 369 } 370 } 371 372 if (desc) { 373 sav = NULL; 374 for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 375 ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING); 376 if (ret) { 377 fprintf(stderr, "Failed to add descending key/val %s\n", val); 378 exit(-1); 379 } 380 } 381 } 382 383 tracefs_error_clear(instance); 384 385 switch (cmd) { 386 case START: 387 ret = tracefs_hist_start(instance, hist); 388 if (ret) { 389 char *err = tracefs_error_last(instance); 390 if (err) 391 fprintf(stderr, "\n%s\n", err); 392 } 393 break; 394 case PAUSE: 395 ret = tracefs_hist_pause(instance, hist); 396 break; 397 case CONT: 398 ret = tracefs_hist_continue(instance, hist); 399 break; 400 case RESET: 401 ret = tracefs_hist_reset(instance, hist); 402 break; 403 case DELETE: 404 ret = tracefs_hist_destroy(instance, hist); 405 break; 406 case SHOW: 407 /* Show was already done */ 408 break; 409 } 410 if (ret) 411 fprintf(stderr, "Failed: command\n"); 412 exit(ret); 413} 414 415int main (int argc, char **argv, char **env) 416{ 417 enum commands cmd; 418 char *instance = NULL; 419 char *cmd_str; 420 char *event = NULL; 421 char *keys = NULL; 422 char *vals = NULL; 423 char *sort = NULL; 424 char *desc = NULL; 425 char *ascend = NULL; 426 427 if (argc < 2) { 428 fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]); 429 fprintf(stderr, " [-a ascending][-d descending]\n"); 430 exit(-1); 431 } 432 433 cmd_str = argv[1]; 434 435 if (!strcmp(cmd_str, "start")) 436 cmd = START; 437 else if (!strcmp(cmd_str, "pause")) 438 cmd = PAUSE; 439 else if (!strcmp(cmd_str, "cont")) 440 cmd = CONT; 441 else if (!strcmp(cmd_str, "reset")) 442 cmd = RESET; 443 else if (!strcmp(cmd_str, "delete")) 444 cmd = DELETE; 445 else if (!strcmp(cmd_str, "show")) 446 cmd = SHOW; 447 else { 448 fprintf(stderr, "Unknown command %s\n", cmd_str); 449 exit(-1); 450 } 451 452 for (;;) { 453 int c; 454 455 c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:"); 456 if (c == -1) 457 break; 458 459 switch (c) { 460 case 'e': 461 event = optarg; 462 break; 463 case 'k': 464 keys = optarg; 465 break; 466 case 'v': 467 vals = optarg; 468 break; 469 case 'B': 470 instance = optarg; 471 break; 472 case 's': 473 sort = optarg; 474 break; 475 case 'd': 476 desc = optarg; 477 break; 478 case 'a': 479 ascend = optarg; 480 break; 481 } 482 } 483 if (!event) { 484 event = "kmem/kmalloc"; 485 if (!keys) 486 keys = "call_site.sym,bytes_req"; 487 if (!vals) 488 vals = "bytes_alloc"; 489 if (!sort) 490 sort = "bytes_req,bytes_alloc"; 491 if (!desc) 492 desc = "bytes_alloc"; 493 } 494 process_hist(cmd, instance, event, keys, vals, sort, ascend, desc); 495} 496-- 497 498FILES 499----- 500[verse] 501-- 502*tracefs.h* 503 Header file to include in order to have access to the library APIs. 504*-ltracefs* 505 Linker switch to add when building a program that uses the library. 506-- 507 508SEE ALSO 509-------- 510*libtracefs*(3), 511*libtraceevent*(3), 512*trace-cmd*(1), 513*tracefs_hist_pause*(3), 514*tracefs_hist_continue*(3), 515*tracefs_hist_reset*(3) 516 517AUTHOR 518------ 519[verse] 520-- 521*Steven Rostedt* <[email protected]> 522*Tzvetomir Stoyanov* <[email protected]> 523*sameeruddin shaik* <[email protected]> 524-- 525REPORTING BUGS 526-------------- 527Report bugs to <[email protected]> 528 529LICENSE 530------- 531libtracefs is Free Software licensed under the GNU LGPL 2.1 532 533RESOURCES 534--------- 535https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 536 537COPYING 538------- 539Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 540the terms of the GNU Public License (GPL). 541