1libtracefs(3) 2============= 3 4NAME 5---- 6tracefs_hist_alloc, tracefs_hist_alloc_2d, tracefs_hist_alloc_nd, tracefs_hist_alloc_nd_cnt, tracefs_hist_free, 7tracefs_hist_add_key, tracefs_hist_add_key_cnt, tracefs_hist_add_value - Create and destroy event histograms 8 9SYNOPSIS 10-------- 11[verse] 12-- 13*#include <tracefs.h>* 14 15enum *tracefs_hist_key_type* { 16 *TRACEFS_HIST_KEY_NORMAL* = 0, 17 *TRACEFS_HIST_KEY_HEX*, 18 *TRACEFS_HIST_KEY_SYM*, 19 *TRACEFS_HIST_KEY_SYM_OFFSET*, 20 *TRACEFS_HIST_KEY_SYSCALL*, 21 *TRACEFS_HIST_KEY_EXECNAME*, 22 *TRACEFS_HIST_KEY_LOG*, 23 *TRACEFS_HIST_KEY_USECS*, 24 *TRACEFS_HIST_KEY_MAX* 25}; 26 27struct *tracefs_hist_axis* { 28 const char pass:[*]_key_; 29 enum tracefs_hist_key_type _type_; 30}; 31 32struct tracefs_hist pass:[*]*tracefs_hist_alloc*(struct tracefs_tep pass:[*] _tep_, 33 const char pass:[*]_system_, const char pass:[*]_event_, 34 const char pass:[*]_key_, enum tracefs_hist_key_type _type_); 35struct tracefs_hist pass:[*]*tracefs_hist_alloc_2d*(struct tracefs_tep pass:[*] _tep_, 36 const char pass:[*]_system_, const char pass:[*]_event_, 37 const char pass:[*]_key1_, enum tracefs_hist_key_type _type1_, 38 const char pass:[*]_key2_, enum tracefs_hist_key_type _type2_)); 39struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd*(struct tracefs_tep pass:[*] _tep_, 40 const char pass:[*]_system_, const char pass:[*]_event_, 41 struct tracefs_hist_axis pass:[*]_axes_); 42struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd_cnt*(struct tep_handle pass:[*]_tep_, 43 const char pass:[*]_system_, const char pass:[*]_event_name_, 44 struct tracefs_hist_axis_cnt pass:[*]_axes_); 45void *tracefs_hist_free*(struct tracefs_hist pass:[*]_hist_); 46 47int *tracefs_hist_add_key*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_, 48 enum tracefs_hist_key_type _type_); 49int *tracefs_hist_add_key_cnt*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_, 50 enum tracefs_hist_key_type _type_, int _cnt_); 51int *tracefs_hist_add_value*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_value_); 52-- 53 54DESCRIPTION 55----------- 56Event histograms are created by the trigger file in the event directory. 57The syntax can be complex and difficult to get correct. This API handles the 58syntax, and facilitates the creation and interaction with the event histograms. 59See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information. 60 61*tracefs_hist_alloc*() allocates a "struct tracefs_hist" descriptor of a one-dimensional 62histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*(). 63The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the 64_system_ and _event_ that the histogram will be attached to. The _system_ is the 65system or group of the event. The _event_ is the event to attach the histogram to. 66The _key_ is a field of the event that will be used as the key(dimension) of the histogram. 67The _type_ is the type of the _key_. See KEY TYPES below. 68 69*tracefs_hist_alloc_2d*() allocates a "struct tracefs_hist" descriptor of a two-dimensional 70histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*(). 71The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the 72_system_ and _event_ that the histogram will be attached to. The _system_ is the 73system or group of the event. The _event_ is the event to attach the histogram to. 74The _key1_ is the first field of the event that will be used as the key(dimension) 75of the histogram. The _type1_ is the type of the _key1_. See KEY TYPES below. 76The _key2_ is the second field of the event that will be used as the key(dimension) 77of the histogram. The _type2_ is the type of the _key2_. See KEY TYPES below. 78 79*tracefs_hist_alloc_nd*() allocates a "struct tracefs_hist" descriptor of an N-dimensional 80histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*(). 81The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the 82_system_ and _event_ that the histogram will be attached to. The _system_ is the 83system or group of the event. The _event_ is the event to attach the histogram to. 84The _axes_ is an array of _key_ / _type_ pairs, defining the dimensions of the histogram. 85 86*tracefs_hist_alloc_nd_cnt*() will initialize a histogram descriptor that will be attached to 87the _system_/_event_. This only initializes the descriptor with the given _axes_ keys as primaries. 88This only initializes the descriptor, it does not start the histogram in the kernel. 89The difference between this and *tracefs_hist_alloc_nd()* is that the _axes_ parameter 90is of type *struct tracefs_hist_axis_cnt* and not *struct tracefs_hist_axis*. 91 92*tracefs_hist_free*() frees the _tracefs_hist_ descriptor. Note, it does not stop 93or disable the running histogram if it was started. *tracefs_hist_destroy*() needs 94to be called to do so. 95 96*tracefs_hist_add_key*() Adds a secondary or tertiary key to the histogram. 97The key passed to *tracefs_hist_alloc_nd*() is the primary key of the histogram. 98The first time this function is called, it will add a secondary key (or two dimensional 99histogram). If this function is called again on the same histogram, it will add 100a _tertiary_ key (or three dimensional histogram). The _hist_ parameter is the 101histogram descriptor to add the _key_ to. The _type_ is the type of key to add 102(See KEY TYPES below). 103 104The *tracefs_hist_add_key_cnt*() is the same as *tracefs_hist_add_key*() except 105that it allows to add a counter for the given type. Currently, there's only 106the *buckets* type that requires a counter. When adding a key with the buckets 107type, *tracefs_hist_add_key*() is not sufficient, as the *buckets* type requires 108a counter or bucket size. Use *tracefs_hist_add_key_cnt*() when specifing 109a key that is broken up into buckets, and pass in the size of those buckets 110into _cnt_. 111 112*tracefs_hist_add_value*() will add a value to record. By default, the value is 113simply the "hitcount" of the number of times a instance of the histogram's 114key was hit. The _hist_ is the histogram descriptor to add the value to. 115The _value_ is a field in the histogram to add to when an instance of the 116key is hit. 117 118KEY TYPES 119--------- 120 121*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires 122that key to have a type. The types may be: 123 124*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type. 125 126*TRACEFS_HIST_KEY_HEX* to display the key in hex. 127 128*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If 129the key is an address, this is useful as it will display the function names instead 130of just a number. 131 132*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include 133the offset of the function to match the exact address. 134 135*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user 136space to the kernel to tell it what system call it is calling), then the name of 137the system call is displayed. 138 139*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task), 140instead of showing the number, show the name of the running task. 141 142*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale. 143 144*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP, 145in which case it will show the timestamp in microseconds instead of nanoseconds. 146 147RETURN VALUE 148------------ 149*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must 150be freed by *tracefs_hist_free*() or NULL on error. 151 152All the other functions return zero on success or -1 on error. 153 154If *tracefs_hist_start*() returns an error, a message may be displayed 155in the kernel that can be retrieved by *tracefs_error_last()*. 156 157EXAMPLE 158------- 159[source,c] 160-- 161#include <stdlib.h> 162#include <ctype.h> 163#include <unistd.h> 164#include <tracefs.h> 165 166enum commands { 167 START, 168 PAUSE, 169 CONT, 170 RESET, 171 DELETE, 172 SHOW, 173}; 174 175static void parse_system_event(char *group, char **system, char **event) 176{ 177 *system = strtok(group, "/"); 178 *event = strtok(NULL, "/"); 179 if (!*event) { 180 *event = *system; 181 *system = NULL; 182 } 183} 184 185static int parse_keys(char *keys, struct tracefs_hist_axis_cnt **axes) 186{ 187 char *sav = NULL; 188 char *key; 189 int cnt = 0; 190 191 for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) { 192 struct tracefs_hist_axis_cnt *ax; 193 char *att; 194 195 ax = realloc(*axes, sizeof(*ax) * (cnt + 2)); 196 if (!ax) { 197 perror("Failed to allocate axes"); 198 exit(-1); 199 } 200 ax[cnt].key = key; 201 ax[cnt].type = 0; 202 ax[cnt + 1].key = NULL; 203 ax[cnt + 1].type = 0; 204 205 *axes = ax; 206 207 att = strchr(key, '.'); 208 if (att) { 209 *att++ = '\0'; 210 if (strcmp(att, "hex") == 0) 211 ax[cnt].type = TRACEFS_HIST_KEY_HEX; 212 else if (strcmp(att, "sym") == 0) 213 ax[cnt].type = TRACEFS_HIST_KEY_SYM; 214 else if (strcmp(att, "sym_offset") == 0) 215 ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET; 216 else if (strcmp(att, "syscall") == 0) 217 ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL; 218 else if (strcmp(att, "exec") == 0) 219 ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME; 220 else if (strcmp(att, "log") == 0) 221 ax[cnt].type = TRACEFS_HIST_KEY_LOG; 222 else if (strcmp(att, "usecs") == 0) 223 ax[cnt].type = TRACEFS_HIST_KEY_USECS; 224 else if (strncmp(att, "buckets", 7) == 0) { 225 if (att[7] != '=' && !isdigit(att[8])) { 226 fprintf(stderr, "'buckets' key type requires '=<size>'\n"); 227 exit(-1); 228 } 229 ax[cnt].type = TRACEFS_HIST_KEY_BUCKETS; 230 ax[cnt].cnt = atoi(&att[8]); 231 } else { 232 fprintf(stderr, "Undefined attribute '%s'\n", att); 233 fprintf(stderr," Acceptable attributes:\n"); 234 fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\n"); 235 exit(-1); 236 } 237 } 238 cnt++; 239 } 240 return cnt; 241} 242 243static void process_hist(enum commands cmd, const char *instance_name, 244 char *group, char *keys, char *vals, char *sort, 245 char *ascend, char *desc) 246{ 247 struct tracefs_instance *instance = NULL; 248 struct tracefs_hist *hist; 249 struct tep_handle *tep; 250 struct tracefs_hist_axis_cnt *axes = NULL; 251 char *system; 252 char *event; 253 char *sav; 254 char *val; 255 int ret; 256 int cnt; 257 258 if (instance_name) { 259 instance = tracefs_instance_create(instance_name); 260 if (!instance) { 261 fprintf(stderr, "Failed instance create\n"); 262 exit(-1); 263 } 264 } 265 266 tep = tracefs_local_events(NULL); 267 if (!tep) { 268 perror("Could not read events"); 269 exit(-1); 270 } 271 272 parse_system_event(group, &system, &event); 273 274 if (cmd == SHOW) { 275 char *content; 276 content = tracefs_event_file_read(instance, system, event, 277 "hist", NULL); 278 if (!content) { 279 perror("Reading hist file"); 280 exit(-1); 281 } 282 printf("%s\n", content); 283 free(content); 284 return; 285 } 286 287 if (!keys) { 288 fprintf(stderr, "Command needs -k option\n"); 289 exit(-1); 290 } 291 292 cnt = parse_keys(keys, &axes); 293 if (!cnt) { 294 fprintf(stderr, "No keys??\n"); 295 exit(-1); 296 } 297 298 /* buckets require the nd_cnt function */ 299 switch (cnt) { 300 case 2: 301 if (axes[1].type == TRACEFS_HIST_KEY_BUCKETS) 302 cnt = -1; 303 /* fall through */ 304 case 1: 305 if (axes[0].type == TRACEFS_HIST_KEY_BUCKETS) 306 cnt = -1; 307 } 308 309 /* Show examples of hist1d and hist2d */ 310 switch (cnt) { 311 case 1: 312 hist = tracefs_hist_alloc(tep, system, event, 313 axes[0].key, axes[0].type); 314 break; 315 case 2: 316 hist = tracefs_hist_alloc_2d(tep, system, event, 317 axes[0].key, axes[0].type, 318 axes[1].key, axes[1].type); 319 break; 320 default: 321 /* Really, 1 and 2 could use this too */ 322 hist = tracefs_hist_alloc_nd_cnt(tep, system, event, axes); 323 } 324 if (!hist) { 325 fprintf(stderr, "Failed hist create\n"); 326 exit(-1); 327 } 328 329 if (vals) { 330 sav = NULL; 331 for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 332 ret = tracefs_hist_add_value(hist, val); 333 if (ret) { 334 fprintf(stderr, "Failed to add value %s\n", val); 335 exit(-1); 336 } 337 } 338 } 339 340 if (sort) { 341 sav = NULL; 342 for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 343 ret = tracefs_hist_add_sort_key(hist, val); 344 if (ret) { 345 fprintf(stderr, "Failed to add sort key/val %s\n", val); 346 exit(-1); 347 } 348 } 349 } 350 351 if (ascend) { 352 sav = NULL; 353 for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 354 ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING); 355 if (ret) { 356 fprintf(stderr, "Failed to add ascending key/val %s\n", val); 357 exit(-1); 358 } 359 } 360 } 361 362 if (desc) { 363 sav = NULL; 364 for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) { 365 ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING); 366 if (ret) { 367 fprintf(stderr, "Failed to add descending key/val %s\n", val); 368 exit(-1); 369 } 370 } 371 } 372 373 tracefs_error_clear(instance); 374 375 switch (cmd) { 376 case START: 377 ret = tracefs_hist_start(instance, hist); 378 if (ret) { 379 char *err = tracefs_error_last(instance); 380 if (err) 381 fprintf(stderr, "\n%s\n", err); 382 } 383 break; 384 case PAUSE: 385 ret = tracefs_hist_pause(instance, hist); 386 break; 387 case CONT: 388 ret = tracefs_hist_continue(instance, hist); 389 break; 390 case RESET: 391 ret = tracefs_hist_reset(instance, hist); 392 break; 393 case DELETE: 394 ret = tracefs_hist_destroy(instance, hist); 395 break; 396 case SHOW: 397 /* Show was already done */ 398 break; 399 } 400 if (ret) 401 fprintf(stderr, "Failed: command\n"); 402 exit(ret); 403} 404 405int main (int argc, char **argv, char **env) 406{ 407 enum commands cmd; 408 char *instance = NULL; 409 char *cmd_str; 410 char *event = NULL; 411 char *keys = NULL; 412 char *vals = NULL; 413 char *sort = NULL; 414 char *desc = NULL; 415 char *ascend = NULL; 416 417 if (argc < 2) { 418 fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]); 419 fprintf(stderr, " [-a ascending][-d descending]\n"); 420 exit(-1); 421 } 422 423 cmd_str = argv[1]; 424 425 if (!strcmp(cmd_str, "start")) 426 cmd = START; 427 else if (!strcmp(cmd_str, "pause")) 428 cmd = PAUSE; 429 else if (!strcmp(cmd_str, "cont")) 430 cmd = CONT; 431 else if (!strcmp(cmd_str, "reset")) 432 cmd = RESET; 433 else if (!strcmp(cmd_str, "delete")) 434 cmd = DELETE; 435 else if (!strcmp(cmd_str, "show")) 436 cmd = SHOW; 437 else { 438 fprintf(stderr, "Unknown command %s\n", cmd_str); 439 exit(-1); 440 } 441 442 for (;;) { 443 int c; 444 445 c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:"); 446 if (c == -1) 447 break; 448 449 switch (c) { 450 case 'e': 451 event = optarg; 452 break; 453 case 'k': 454 keys = optarg; 455 break; 456 case 'v': 457 vals = optarg; 458 break; 459 case 'B': 460 instance = optarg; 461 break; 462 case 's': 463 sort = optarg; 464 break; 465 case 'd': 466 desc = optarg; 467 break; 468 case 'a': 469 ascend = optarg; 470 break; 471 } 472 } 473 if (!event) { 474 event = "kmem/kmalloc"; 475 if (!keys) 476 keys = "call_site.sym,bytes_req"; 477 if (!vals) 478 vals = "bytes_alloc"; 479 if (!sort) 480 sort = "bytes_req,bytes_alloc"; 481 if (!desc) 482 desc = "bytes_alloc"; 483 } 484 process_hist(cmd, instance, event, keys, vals, sort, ascend, desc); 485} 486 487-- 488 489FILES 490----- 491[verse] 492-- 493*tracefs.h* 494 Header file to include in order to have access to the library APIs. 495*-ltracefs* 496 Linker switch to add when building a program that uses the library. 497-- 498 499SEE ALSO 500-------- 501*libtracefs*(3), 502*libtraceevent*(3), 503*trace-cmd*(1), 504*tracefs_hist_pause*(3), 505*tracefs_hist_continue*(3), 506*tracefs_hist_reset*(3) 507 508AUTHOR 509------ 510[verse] 511-- 512*Steven Rostedt* <rostedt@goodmis.org> 513*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com> 514*sameeruddin shaik* <sameeruddin.shaik8@gmail.com> 515-- 516REPORTING BUGS 517-------------- 518Report bugs to <linux-trace-devel@vger.kernel.org> 519 520LICENSE 521------- 522libtracefs is Free Software licensed under the GNU LGPL 2.1 523 524RESOURCES 525--------- 526https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 527 528COPYING 529------- 530Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 531the terms of the GNU Public License (GPL). 532