1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * builtin-ftrace.c 4 * 5 * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> 6 * Copyright (c) 2020 Changbin Du <changbin.du@gmail.com>, significant enhancement. 7 */ 8 9 #include "builtin.h" 10 11 #include <errno.h> 12 #include <unistd.h> 13 #include <signal.h> 14 #include <stdlib.h> 15 #include <fcntl.h> 16 #include <inttypes.h> 17 #include <math.h> 18 #include <poll.h> 19 #include <ctype.h> 20 #include <linux/capability.h> 21 #include <linux/string.h> 22 23 #include "debug.h" 24 #include <subcmd/pager.h> 25 #include <subcmd/parse-options.h> 26 #include <api/io.h> 27 #include <api/fs/tracing_path.h> 28 #include "evlist.h" 29 #include "target.h" 30 #include "cpumap.h" 31 #include "hashmap.h" 32 #include "thread_map.h" 33 #include "strfilter.h" 34 #include "util/cap.h" 35 #include "util/config.h" 36 #include "util/ftrace.h" 37 #include "util/stat.h" 38 #include "util/units.h" 39 #include "util/parse-sublevel-options.h" 40 41 #define DEFAULT_TRACER "function_graph" 42 43 static volatile sig_atomic_t workload_exec_errno; 44 static volatile sig_atomic_t done; 45 46 static void sig_handler(int sig __maybe_unused) 47 { 48 done = true; 49 } 50 51 /* 52 * evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 53 * we asked by setting its exec_error to the function below, 54 * ftrace__workload_exec_failed_signal. 55 * 56 * XXX We need to handle this more appropriately, emitting an error, etc. 57 */ 58 static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, 59 siginfo_t *info __maybe_unused, 60 void *ucontext __maybe_unused) 61 { 62 workload_exec_errno = info->si_value.sival_int; 63 done = true; 64 } 65 66 static bool check_ftrace_capable(void) 67 { 68 bool used_root; 69 70 if (perf_cap__capable(CAP_PERFMON, &used_root)) 71 return true; 72 73 if (!used_root && perf_cap__capable(CAP_SYS_ADMIN, &used_root)) 74 return true; 75 76 pr_err("ftrace only works for %s!\n", 77 used_root ? "root" 78 : "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" 79 ); 80 return false; 81 } 82 83 static int __write_tracing_file(const char *name, const char *val, bool append) 84 { 85 char *file; 86 int fd, ret = -1; 87 ssize_t size = strlen(val); 88 int flags = O_WRONLY; 89 char errbuf[512]; 90 char *val_copy; 91 92 file = get_tracing_file(name); 93 if (!file) { 94 pr_debug("cannot get tracing file: %s\n", name); 95 return -1; 96 } 97 98 if (append) 99 flags |= O_APPEND; 100 else 101 flags |= O_TRUNC; 102 103 fd = open(file, flags); 104 if (fd < 0) { 105 pr_debug("cannot open tracing file: %s: %s\n", 106 name, str_error_r(errno, errbuf, sizeof(errbuf))); 107 goto out; 108 } 109 110 /* 111 * Copy the original value and append a '\n'. Without this, 112 * the kernel can hide possible errors. 113 */ 114 val_copy = strdup(val); 115 if (!val_copy) 116 goto out_close; 117 val_copy[size] = '\n'; 118 119 if (write(fd, val_copy, size + 1) == size + 1) 120 ret = 0; 121 else 122 pr_debug("write '%s' to tracing/%s failed: %s\n", 123 val, name, str_error_r(errno, errbuf, sizeof(errbuf))); 124 125 free(val_copy); 126 out_close: 127 close(fd); 128 out: 129 put_tracing_file(file); 130 return ret; 131 } 132 133 static int write_tracing_file(const char *name, const char *val) 134 { 135 return __write_tracing_file(name, val, false); 136 } 137 138 static int append_tracing_file(const char *name, const char *val) 139 { 140 return __write_tracing_file(name, val, true); 141 } 142 143 static int read_tracing_file_to_stdout(const char *name) 144 { 145 char buf[4096]; 146 char *file; 147 int fd; 148 int ret = -1; 149 150 file = get_tracing_file(name); 151 if (!file) { 152 pr_debug("cannot get tracing file: %s\n", name); 153 return -1; 154 } 155 156 fd = open(file, O_RDONLY); 157 if (fd < 0) { 158 pr_debug("cannot open tracing file: %s: %s\n", 159 name, str_error_r(errno, buf, sizeof(buf))); 160 goto out; 161 } 162 163 /* read contents to stdout */ 164 while (true) { 165 int n = read(fd, buf, sizeof(buf)); 166 if (n == 0) 167 break; 168 else if (n < 0) 169 goto out_close; 170 171 if (fwrite(buf, n, 1, stdout) != 1) 172 goto out_close; 173 } 174 ret = 0; 175 176 out_close: 177 close(fd); 178 out: 179 put_tracing_file(file); 180 return ret; 181 } 182 183 static int read_tracing_file_by_line(const char *name, 184 void (*cb)(char *str, void *arg), 185 void *cb_arg) 186 { 187 char *line = NULL; 188 size_t len = 0; 189 char *file; 190 FILE *fp; 191 192 file = get_tracing_file(name); 193 if (!file) { 194 pr_debug("cannot get tracing file: %s\n", name); 195 return -1; 196 } 197 198 fp = fopen(file, "r"); 199 if (fp == NULL) { 200 pr_debug("cannot open tracing file: %s\n", name); 201 put_tracing_file(file); 202 return -1; 203 } 204 205 while (getline(&line, &len, fp) != -1) { 206 cb(line, cb_arg); 207 } 208 209 if (line) 210 free(line); 211 212 fclose(fp); 213 put_tracing_file(file); 214 return 0; 215 } 216 217 static int write_tracing_file_int(const char *name, int value) 218 { 219 char buf[16]; 220 221 snprintf(buf, sizeof(buf), "%d", value); 222 if (write_tracing_file(name, buf) < 0) 223 return -1; 224 225 return 0; 226 } 227 228 static int write_tracing_option_file(const char *name, const char *val) 229 { 230 char *file; 231 int ret; 232 233 if (asprintf(&file, "options/%s", name) < 0) 234 return -1; 235 236 ret = __write_tracing_file(file, val, false); 237 free(file); 238 return ret; 239 } 240 241 static int reset_tracing_cpu(void); 242 static void reset_tracing_filters(void); 243 244 static void reset_tracing_options(struct perf_ftrace *ftrace __maybe_unused) 245 { 246 write_tracing_option_file("function-fork", "0"); 247 write_tracing_option_file("func_stack_trace", "0"); 248 write_tracing_option_file("sleep-time", "1"); 249 write_tracing_option_file("funcgraph-irqs", "1"); 250 write_tracing_option_file("funcgraph-proc", "0"); 251 write_tracing_option_file("funcgraph-abstime", "0"); 252 write_tracing_option_file("funcgraph-tail", "0"); 253 write_tracing_option_file("latency-format", "0"); 254 write_tracing_option_file("irq-info", "0"); 255 } 256 257 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 258 { 259 if (write_tracing_file("tracing_on", "0") < 0) 260 return -1; 261 262 if (write_tracing_file("current_tracer", "nop") < 0) 263 return -1; 264 265 if (write_tracing_file("set_ftrace_pid", " ") < 0) 266 return -1; 267 268 if (reset_tracing_cpu() < 0) 269 return -1; 270 271 if (write_tracing_file("max_graph_depth", "0") < 0) 272 return -1; 273 274 if (write_tracing_file("tracing_thresh", "0") < 0) 275 return -1; 276 277 reset_tracing_filters(); 278 reset_tracing_options(ftrace); 279 return 0; 280 } 281 282 static int set_tracing_pid(struct perf_ftrace *ftrace) 283 { 284 int i; 285 char buf[16]; 286 287 if (target__has_cpu(&ftrace->target)) 288 return 0; 289 290 for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { 291 scnprintf(buf, sizeof(buf), "%d", 292 perf_thread_map__pid(ftrace->evlist->core.threads, i)); 293 if (append_tracing_file("set_ftrace_pid", buf) < 0) 294 return -1; 295 } 296 return 0; 297 } 298 299 static int set_tracing_cpumask(struct perf_cpu_map *cpumap) 300 { 301 char *cpumask; 302 size_t mask_size; 303 int ret; 304 int last_cpu; 305 306 last_cpu = perf_cpu_map__cpu(cpumap, perf_cpu_map__nr(cpumap) - 1).cpu; 307 mask_size = last_cpu / 4 + 2; /* one more byte for EOS */ 308 mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */ 309 310 cpumask = malloc(mask_size); 311 if (cpumask == NULL) { 312 pr_debug("failed to allocate cpu mask\n"); 313 return -1; 314 } 315 316 cpu_map__snprint_mask(cpumap, cpumask, mask_size); 317 318 ret = write_tracing_file("tracing_cpumask", cpumask); 319 320 free(cpumask); 321 return ret; 322 } 323 324 static int set_tracing_cpu(struct perf_ftrace *ftrace) 325 { 326 struct perf_cpu_map *cpumap = ftrace->evlist->core.user_requested_cpus; 327 328 if (!target__has_cpu(&ftrace->target)) 329 return 0; 330 331 return set_tracing_cpumask(cpumap); 332 } 333 334 static int set_tracing_func_stack_trace(struct perf_ftrace *ftrace) 335 { 336 if (!ftrace->func_stack_trace) 337 return 0; 338 339 if (write_tracing_option_file("func_stack_trace", "1") < 0) 340 return -1; 341 342 return 0; 343 } 344 345 static int set_tracing_func_irqinfo(struct perf_ftrace *ftrace) 346 { 347 if (!ftrace->func_irq_info) 348 return 0; 349 350 if (write_tracing_option_file("irq-info", "1") < 0) 351 return -1; 352 353 return 0; 354 } 355 356 static int reset_tracing_cpu(void) 357 { 358 struct perf_cpu_map *cpumap = perf_cpu_map__new_online_cpus(); 359 int ret; 360 361 ret = set_tracing_cpumask(cpumap); 362 perf_cpu_map__put(cpumap); 363 return ret; 364 } 365 366 static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) 367 { 368 struct filter_entry *pos; 369 370 list_for_each_entry(pos, funcs, list) { 371 if (append_tracing_file(filter_file, pos->name) < 0) 372 return -1; 373 } 374 375 return 0; 376 } 377 378 static int set_tracing_filters(struct perf_ftrace *ftrace) 379 { 380 int ret; 381 382 ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); 383 if (ret < 0) 384 return ret; 385 386 ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); 387 if (ret < 0) 388 return ret; 389 390 ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); 391 if (ret < 0) 392 return ret; 393 394 /* old kernels do not have this filter */ 395 __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); 396 397 return ret; 398 } 399 400 static void reset_tracing_filters(void) 401 { 402 write_tracing_file("set_ftrace_filter", " "); 403 write_tracing_file("set_ftrace_notrace", " "); 404 write_tracing_file("set_graph_function", " "); 405 write_tracing_file("set_graph_notrace", " "); 406 } 407 408 static int set_tracing_depth(struct perf_ftrace *ftrace) 409 { 410 if (ftrace->graph_depth == 0) 411 return 0; 412 413 if (ftrace->graph_depth < 0) { 414 pr_err("invalid graph depth: %d\n", ftrace->graph_depth); 415 return -1; 416 } 417 418 if (write_tracing_file_int("max_graph_depth", ftrace->graph_depth) < 0) 419 return -1; 420 421 return 0; 422 } 423 424 static int set_tracing_percpu_buffer_size(struct perf_ftrace *ftrace) 425 { 426 int ret; 427 428 if (ftrace->percpu_buffer_size == 0) 429 return 0; 430 431 ret = write_tracing_file_int("buffer_size_kb", 432 ftrace->percpu_buffer_size / 1024); 433 if (ret < 0) 434 return ret; 435 436 return 0; 437 } 438 439 static int set_tracing_trace_inherit(struct perf_ftrace *ftrace) 440 { 441 if (!ftrace->inherit) 442 return 0; 443 444 if (write_tracing_option_file("function-fork", "1") < 0) 445 return -1; 446 447 return 0; 448 } 449 450 static int set_tracing_sleep_time(struct perf_ftrace *ftrace) 451 { 452 if (!ftrace->graph_nosleep_time) 453 return 0; 454 455 if (write_tracing_option_file("sleep-time", "0") < 0) 456 return -1; 457 458 return 0; 459 } 460 461 static int set_tracing_funcgraph_irqs(struct perf_ftrace *ftrace) 462 { 463 if (!ftrace->graph_noirqs) 464 return 0; 465 466 if (write_tracing_option_file("funcgraph-irqs", "0") < 0) 467 return -1; 468 469 return 0; 470 } 471 472 static int set_tracing_funcgraph_verbose(struct perf_ftrace *ftrace) 473 { 474 if (!ftrace->graph_verbose) 475 return 0; 476 477 if (write_tracing_option_file("funcgraph-proc", "1") < 0) 478 return -1; 479 480 if (write_tracing_option_file("funcgraph-abstime", "1") < 0) 481 return -1; 482 483 if (write_tracing_option_file("latency-format", "1") < 0) 484 return -1; 485 486 return 0; 487 } 488 489 static int set_tracing_funcgraph_tail(struct perf_ftrace *ftrace) 490 { 491 if (!ftrace->graph_tail) 492 return 0; 493 494 if (write_tracing_option_file("funcgraph-tail", "1") < 0) 495 return -1; 496 497 return 0; 498 } 499 500 static int set_tracing_thresh(struct perf_ftrace *ftrace) 501 { 502 int ret; 503 504 if (ftrace->graph_thresh == 0) 505 return 0; 506 507 ret = write_tracing_file_int("tracing_thresh", ftrace->graph_thresh); 508 if (ret < 0) 509 return ret; 510 511 return 0; 512 } 513 514 static int set_tracing_options(struct perf_ftrace *ftrace) 515 { 516 if (set_tracing_pid(ftrace) < 0) { 517 pr_err("failed to set ftrace pid\n"); 518 return -1; 519 } 520 521 if (set_tracing_cpu(ftrace) < 0) { 522 pr_err("failed to set tracing cpumask\n"); 523 return -1; 524 } 525 526 if (set_tracing_func_stack_trace(ftrace) < 0) { 527 pr_err("failed to set tracing option func_stack_trace\n"); 528 return -1; 529 } 530 531 if (set_tracing_func_irqinfo(ftrace) < 0) { 532 pr_err("failed to set tracing option irq-info\n"); 533 return -1; 534 } 535 536 if (set_tracing_filters(ftrace) < 0) { 537 pr_err("failed to set tracing filters\n"); 538 return -1; 539 } 540 541 if (set_tracing_depth(ftrace) < 0) { 542 pr_err("failed to set graph depth\n"); 543 return -1; 544 } 545 546 if (set_tracing_percpu_buffer_size(ftrace) < 0) { 547 pr_err("failed to set tracing per-cpu buffer size\n"); 548 return -1; 549 } 550 551 if (set_tracing_trace_inherit(ftrace) < 0) { 552 pr_err("failed to set tracing option function-fork\n"); 553 return -1; 554 } 555 556 if (set_tracing_sleep_time(ftrace) < 0) { 557 pr_err("failed to set tracing option sleep-time\n"); 558 return -1; 559 } 560 561 if (set_tracing_funcgraph_irqs(ftrace) < 0) { 562 pr_err("failed to set tracing option funcgraph-irqs\n"); 563 return -1; 564 } 565 566 if (set_tracing_funcgraph_verbose(ftrace) < 0) { 567 pr_err("failed to set tracing option funcgraph-proc/funcgraph-abstime\n"); 568 return -1; 569 } 570 571 if (set_tracing_thresh(ftrace) < 0) { 572 pr_err("failed to set tracing thresh\n"); 573 return -1; 574 } 575 576 if (set_tracing_funcgraph_tail(ftrace) < 0) { 577 pr_err("failed to set tracing option funcgraph-tail\n"); 578 return -1; 579 } 580 581 return 0; 582 } 583 584 static void select_tracer(struct perf_ftrace *ftrace) 585 { 586 bool graph = !list_empty(&ftrace->graph_funcs) || 587 !list_empty(&ftrace->nograph_funcs); 588 bool func = !list_empty(&ftrace->filters) || 589 !list_empty(&ftrace->notrace); 590 591 /* The function_graph has priority over function tracer. */ 592 if (graph) 593 ftrace->tracer = "function_graph"; 594 else if (func) 595 ftrace->tracer = "function"; 596 /* Otherwise, the default tracer is used. */ 597 598 pr_debug("%s tracer is used\n", ftrace->tracer); 599 } 600 601 static int __cmd_ftrace(struct perf_ftrace *ftrace) 602 { 603 char *trace_file; 604 int trace_fd; 605 char buf[4096]; 606 struct pollfd pollfd = { 607 .events = POLLIN, 608 }; 609 610 select_tracer(ftrace); 611 612 if (reset_tracing_files(ftrace) < 0) { 613 pr_err("failed to reset ftrace\n"); 614 goto out; 615 } 616 617 /* reset ftrace buffer */ 618 if (write_tracing_file("trace", "0") < 0) 619 goto out; 620 621 if (set_tracing_options(ftrace) < 0) 622 goto out_reset; 623 624 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 625 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 626 goto out_reset; 627 } 628 629 setup_pager(); 630 631 trace_file = get_tracing_file("trace_pipe"); 632 if (!trace_file) { 633 pr_err("failed to open trace_pipe\n"); 634 goto out_reset; 635 } 636 637 trace_fd = open(trace_file, O_RDONLY); 638 639 put_tracing_file(trace_file); 640 641 if (trace_fd < 0) { 642 pr_err("failed to open trace_pipe\n"); 643 goto out_reset; 644 } 645 646 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 647 pollfd.fd = trace_fd; 648 649 /* display column headers */ 650 read_tracing_file_to_stdout("trace"); 651 652 if (!ftrace->target.initial_delay) { 653 if (write_tracing_file("tracing_on", "1") < 0) { 654 pr_err("can't enable tracing\n"); 655 goto out_close_fd; 656 } 657 } 658 659 evlist__start_workload(ftrace->evlist); 660 661 if (ftrace->target.initial_delay > 0) { 662 usleep(ftrace->target.initial_delay * 1000); 663 if (write_tracing_file("tracing_on", "1") < 0) { 664 pr_err("can't enable tracing\n"); 665 goto out_close_fd; 666 } 667 } 668 669 while (!done) { 670 if (poll(&pollfd, 1, -1) < 0) 671 break; 672 673 if (pollfd.revents & POLLIN) { 674 int n = read(trace_fd, buf, sizeof(buf)); 675 if (n < 0) 676 break; 677 if (fwrite(buf, n, 1, stdout) != 1) 678 break; 679 /* flush output since stdout is in full buffering mode due to pager */ 680 fflush(stdout); 681 } 682 } 683 684 write_tracing_file("tracing_on", "0"); 685 686 if (workload_exec_errno) { 687 const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf)); 688 /* flush stdout first so below error msg appears at the end. */ 689 fflush(stdout); 690 pr_err("workload failed: %s\n", emsg); 691 goto out_close_fd; 692 } 693 694 /* read remaining buffer contents */ 695 while (true) { 696 int n = read(trace_fd, buf, sizeof(buf)); 697 if (n <= 0) 698 break; 699 if (fwrite(buf, n, 1, stdout) != 1) 700 break; 701 } 702 703 out_close_fd: 704 close(trace_fd); 705 out_reset: 706 reset_tracing_files(ftrace); 707 out: 708 return (done && !workload_exec_errno) ? 0 : -1; 709 } 710 711 static void make_histogram(int buckets[], char *buf, size_t len, char *linebuf, 712 bool use_nsec) 713 { 714 char *p, *q; 715 char *unit; 716 double num; 717 int i; 718 719 /* ensure NUL termination */ 720 buf[len] = '\0'; 721 722 /* handle data line by line */ 723 for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) { 724 *q = '\0'; 725 /* move it to the line buffer */ 726 strcat(linebuf, p); 727 728 /* 729 * parse trace output to get function duration like in 730 * 731 * # tracer: function_graph 732 * # 733 * # CPU DURATION FUNCTION CALLS 734 * # | | | | | | | 735 * 1) + 10.291 us | do_filp_open(); 736 * 1) 4.889 us | do_filp_open(); 737 * 1) 6.086 us | do_filp_open(); 738 * 739 */ 740 if (linebuf[0] == '#') 741 goto next; 742 743 /* ignore CPU */ 744 p = strchr(linebuf, ')'); 745 if (p == NULL) 746 p = linebuf; 747 748 while (*p && !isdigit(*p) && (*p != '|')) 749 p++; 750 751 /* no duration */ 752 if (*p == '\0' || *p == '|') 753 goto next; 754 755 num = strtod(p, &unit); 756 if (!unit || strncmp(unit, " us", 3)) 757 goto next; 758 759 if (use_nsec) 760 num *= 1000; 761 762 i = log2(num); 763 if (i < 0) 764 i = 0; 765 if (i >= NUM_BUCKET) 766 i = NUM_BUCKET - 1; 767 768 buckets[i]++; 769 770 next: 771 /* empty the line buffer for the next output */ 772 linebuf[0] = '\0'; 773 } 774 775 /* preserve any remaining output (before newline) */ 776 strcat(linebuf, p); 777 } 778 779 static void display_histogram(int buckets[], bool use_nsec) 780 { 781 int i; 782 int total = 0; 783 int bar_total = 46; /* to fit in 80 column */ 784 char bar[] = "###############################################"; 785 int bar_len; 786 787 for (i = 0; i < NUM_BUCKET; i++) 788 total += buckets[i]; 789 790 if (total == 0) { 791 printf("No data found\n"); 792 return; 793 } 794 795 printf("# %14s | %10s | %-*s |\n", 796 " DURATION ", "COUNT", bar_total, "GRAPH"); 797 798 bar_len = buckets[0] * bar_total / total; 799 printf(" %4d - %-4d %s | %10d | %.*s%*s |\n", 800 0, 1, "us", buckets[0], bar_len, bar, bar_total - bar_len, ""); 801 802 for (i = 1; i < NUM_BUCKET - 1; i++) { 803 int start = (1 << (i - 1)); 804 int stop = 1 << i; 805 const char *unit = use_nsec ? "ns" : "us"; 806 807 if (start >= 1024) { 808 start >>= 10; 809 stop >>= 10; 810 unit = use_nsec ? "us" : "ms"; 811 } 812 bar_len = buckets[i] * bar_total / total; 813 printf(" %4d - %-4d %s | %10d | %.*s%*s |\n", 814 start, stop, unit, buckets[i], bar_len, bar, 815 bar_total - bar_len, ""); 816 } 817 818 bar_len = buckets[NUM_BUCKET - 1] * bar_total / total; 819 printf(" %4d - %-4s %s | %10d | %.*s%*s |\n", 820 1, "...", use_nsec ? "ms" : " s", buckets[NUM_BUCKET - 1], 821 bar_len, bar, bar_total - bar_len, ""); 822 823 } 824 825 static int prepare_func_latency(struct perf_ftrace *ftrace) 826 { 827 char *trace_file; 828 int fd; 829 830 if (ftrace->target.use_bpf) 831 return perf_ftrace__latency_prepare_bpf(ftrace); 832 833 if (reset_tracing_files(ftrace) < 0) { 834 pr_err("failed to reset ftrace\n"); 835 return -1; 836 } 837 838 /* reset ftrace buffer */ 839 if (write_tracing_file("trace", "0") < 0) 840 return -1; 841 842 if (set_tracing_options(ftrace) < 0) 843 return -1; 844 845 /* force to use the function_graph tracer to track duration */ 846 if (write_tracing_file("current_tracer", "function_graph") < 0) { 847 pr_err("failed to set current_tracer to function_graph\n"); 848 return -1; 849 } 850 851 trace_file = get_tracing_file("trace_pipe"); 852 if (!trace_file) { 853 pr_err("failed to open trace_pipe\n"); 854 return -1; 855 } 856 857 fd = open(trace_file, O_RDONLY); 858 if (fd < 0) 859 pr_err("failed to open trace_pipe\n"); 860 861 put_tracing_file(trace_file); 862 return fd; 863 } 864 865 static int start_func_latency(struct perf_ftrace *ftrace) 866 { 867 if (ftrace->target.use_bpf) 868 return perf_ftrace__latency_start_bpf(ftrace); 869 870 if (write_tracing_file("tracing_on", "1") < 0) { 871 pr_err("can't enable tracing\n"); 872 return -1; 873 } 874 875 return 0; 876 } 877 878 static int stop_func_latency(struct perf_ftrace *ftrace) 879 { 880 if (ftrace->target.use_bpf) 881 return perf_ftrace__latency_stop_bpf(ftrace); 882 883 write_tracing_file("tracing_on", "0"); 884 return 0; 885 } 886 887 static int read_func_latency(struct perf_ftrace *ftrace, int buckets[]) 888 { 889 if (ftrace->target.use_bpf) 890 return perf_ftrace__latency_read_bpf(ftrace, buckets); 891 892 return 0; 893 } 894 895 static int cleanup_func_latency(struct perf_ftrace *ftrace) 896 { 897 if (ftrace->target.use_bpf) 898 return perf_ftrace__latency_cleanup_bpf(ftrace); 899 900 reset_tracing_files(ftrace); 901 return 0; 902 } 903 904 static int __cmd_latency(struct perf_ftrace *ftrace) 905 { 906 int trace_fd; 907 char buf[4096]; 908 char line[256]; 909 struct pollfd pollfd = { 910 .events = POLLIN, 911 }; 912 int buckets[NUM_BUCKET] = { }; 913 914 trace_fd = prepare_func_latency(ftrace); 915 if (trace_fd < 0) 916 goto out; 917 918 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 919 pollfd.fd = trace_fd; 920 921 if (start_func_latency(ftrace) < 0) 922 goto out; 923 924 evlist__start_workload(ftrace->evlist); 925 926 line[0] = '\0'; 927 while (!done) { 928 if (poll(&pollfd, 1, -1) < 0) 929 break; 930 931 if (pollfd.revents & POLLIN) { 932 int n = read(trace_fd, buf, sizeof(buf) - 1); 933 if (n < 0) 934 break; 935 936 make_histogram(buckets, buf, n, line, ftrace->use_nsec); 937 } 938 } 939 940 stop_func_latency(ftrace); 941 942 if (workload_exec_errno) { 943 const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf)); 944 pr_err("workload failed: %s\n", emsg); 945 goto out; 946 } 947 948 /* read remaining buffer contents */ 949 while (!ftrace->target.use_bpf) { 950 int n = read(trace_fd, buf, sizeof(buf) - 1); 951 if (n <= 0) 952 break; 953 make_histogram(buckets, buf, n, line, ftrace->use_nsec); 954 } 955 956 read_func_latency(ftrace, buckets); 957 958 display_histogram(buckets, ftrace->use_nsec); 959 960 out: 961 close(trace_fd); 962 cleanup_func_latency(ftrace); 963 964 return (done && !workload_exec_errno) ? 0 : -1; 965 } 966 967 static size_t profile_hash(long func, void *ctx __maybe_unused) 968 { 969 return str_hash((char *)func); 970 } 971 972 static bool profile_equal(long func1, long func2, void *ctx __maybe_unused) 973 { 974 return !strcmp((char *)func1, (char *)func2); 975 } 976 977 static int prepare_func_profile(struct perf_ftrace *ftrace) 978 { 979 ftrace->tracer = "function_graph"; 980 ftrace->graph_tail = 1; 981 982 ftrace->profile_hash = hashmap__new(profile_hash, profile_equal, NULL); 983 if (ftrace->profile_hash == NULL) 984 return -ENOMEM; 985 986 return 0; 987 } 988 989 /* This is saved in a hashmap keyed by the function name */ 990 struct ftrace_profile_data { 991 struct stats st; 992 }; 993 994 static int add_func_duration(struct perf_ftrace *ftrace, char *func, double time_ns) 995 { 996 struct ftrace_profile_data *prof = NULL; 997 998 if (!hashmap__find(ftrace->profile_hash, func, &prof)) { 999 char *key = strdup(func); 1000 1001 if (key == NULL) 1002 return -ENOMEM; 1003 1004 prof = zalloc(sizeof(*prof)); 1005 if (prof == NULL) { 1006 free(key); 1007 return -ENOMEM; 1008 } 1009 1010 init_stats(&prof->st); 1011 hashmap__add(ftrace->profile_hash, key, prof); 1012 } 1013 1014 update_stats(&prof->st, time_ns); 1015 return 0; 1016 } 1017 1018 /* 1019 * The ftrace function_graph text output normally looks like below: 1020 * 1021 * CPU DURATION FUNCTION 1022 * 1023 * 0) | syscall_trace_enter.isra.0() { 1024 * 0) | __audit_syscall_entry() { 1025 * 0) | auditd_test_task() { 1026 * 0) 0.271 us | __rcu_read_lock(); 1027 * 0) 0.275 us | __rcu_read_unlock(); 1028 * 0) 1.254 us | } /\* auditd_test_task *\/ 1029 * 0) 0.279 us | ktime_get_coarse_real_ts64(); 1030 * 0) 2.227 us | } /\* __audit_syscall_entry *\/ 1031 * 0) 2.713 us | } /\* syscall_trace_enter.isra.0 *\/ 1032 * 1033 * Parse the line and get the duration and function name. 1034 */ 1035 static int parse_func_duration(struct perf_ftrace *ftrace, char *line, size_t len) 1036 { 1037 char *p; 1038 char *func; 1039 double duration; 1040 1041 /* skip CPU */ 1042 p = strchr(line, ')'); 1043 if (p == NULL) 1044 return 0; 1045 1046 /* get duration */ 1047 p = skip_spaces(p + 1); 1048 1049 /* no duration? */ 1050 if (p == NULL || *p == '|') 1051 return 0; 1052 1053 /* skip markers like '*' or '!' for longer than ms */ 1054 if (!isdigit(*p)) 1055 p++; 1056 1057 duration = strtod(p, &p); 1058 1059 if (strncmp(p, " us", 3)) { 1060 pr_debug("non-usec time found.. ignoring\n"); 1061 return 0; 1062 } 1063 1064 /* 1065 * profile stat keeps the max and min values as integer, 1066 * convert to nsec time so that we can have accurate max. 1067 */ 1068 duration *= 1000; 1069 1070 /* skip to the pipe */ 1071 while (p < line + len && *p != '|') 1072 p++; 1073 1074 if (*p++ != '|') 1075 return -EINVAL; 1076 1077 /* get function name */ 1078 func = skip_spaces(p); 1079 1080 /* skip the closing bracket and the start of comment */ 1081 if (*func == '}') 1082 func += 5; 1083 1084 /* remove semi-colon or end of comment at the end */ 1085 p = line + len - 1; 1086 while (!isalnum(*p) && *p != ']') { 1087 *p = '\0'; 1088 --p; 1089 } 1090 1091 return add_func_duration(ftrace, func, duration); 1092 } 1093 1094 enum perf_ftrace_profile_sort_key { 1095 PFP_SORT_TOTAL = 0, 1096 PFP_SORT_AVG, 1097 PFP_SORT_MAX, 1098 PFP_SORT_COUNT, 1099 PFP_SORT_NAME, 1100 }; 1101 1102 static enum perf_ftrace_profile_sort_key profile_sort = PFP_SORT_TOTAL; 1103 1104 static int cmp_profile_data(const void *a, const void *b) 1105 { 1106 const struct hashmap_entry *e1 = *(const struct hashmap_entry **)a; 1107 const struct hashmap_entry *e2 = *(const struct hashmap_entry **)b; 1108 struct ftrace_profile_data *p1 = e1->pvalue; 1109 struct ftrace_profile_data *p2 = e2->pvalue; 1110 double v1, v2; 1111 1112 switch (profile_sort) { 1113 case PFP_SORT_NAME: 1114 return strcmp(e1->pkey, e2->pkey); 1115 case PFP_SORT_AVG: 1116 v1 = p1->st.mean; 1117 v2 = p2->st.mean; 1118 break; 1119 case PFP_SORT_MAX: 1120 v1 = p1->st.max; 1121 v2 = p2->st.max; 1122 break; 1123 case PFP_SORT_COUNT: 1124 v1 = p1->st.n; 1125 v2 = p2->st.n; 1126 break; 1127 case PFP_SORT_TOTAL: 1128 default: 1129 v1 = p1->st.n * p1->st.mean; 1130 v2 = p2->st.n * p2->st.mean; 1131 break; 1132 } 1133 1134 if (v1 > v2) 1135 return -1; 1136 else 1137 return 1; 1138 } 1139 1140 static void print_profile_result(struct perf_ftrace *ftrace) 1141 { 1142 struct hashmap_entry *entry, **profile; 1143 size_t i, nr, bkt; 1144 1145 nr = hashmap__size(ftrace->profile_hash); 1146 if (nr == 0) 1147 return; 1148 1149 profile = calloc(nr, sizeof(*profile)); 1150 if (profile == NULL) { 1151 pr_err("failed to allocate memory for the result\n"); 1152 return; 1153 } 1154 1155 i = 0; 1156 hashmap__for_each_entry(ftrace->profile_hash, entry, bkt) 1157 profile[i++] = entry; 1158 1159 assert(i == nr); 1160 1161 //cmp_profile_data(profile[0], profile[1]); 1162 qsort(profile, nr, sizeof(*profile), cmp_profile_data); 1163 1164 printf("# %10s %10s %10s %10s %s\n", 1165 "Total (us)", "Avg (us)", "Max (us)", "Count", "Function"); 1166 1167 for (i = 0; i < nr; i++) { 1168 const char *name = profile[i]->pkey; 1169 struct ftrace_profile_data *p = profile[i]->pvalue; 1170 1171 printf("%12.3f %10.3f %6"PRIu64".%03"PRIu64" %10.0f %s\n", 1172 p->st.n * p->st.mean / 1000, p->st.mean / 1000, 1173 p->st.max / 1000, p->st.max % 1000, p->st.n, name); 1174 } 1175 1176 free(profile); 1177 1178 hashmap__for_each_entry(ftrace->profile_hash, entry, bkt) { 1179 free((char *)entry->pkey); 1180 free(entry->pvalue); 1181 } 1182 1183 hashmap__free(ftrace->profile_hash); 1184 ftrace->profile_hash = NULL; 1185 } 1186 1187 static int __cmd_profile(struct perf_ftrace *ftrace) 1188 { 1189 char *trace_file; 1190 int trace_fd; 1191 char buf[4096]; 1192 struct io io; 1193 char *line = NULL; 1194 size_t line_len = 0; 1195 1196 if (prepare_func_profile(ftrace) < 0) { 1197 pr_err("failed to prepare func profiler\n"); 1198 goto out; 1199 } 1200 1201 if (reset_tracing_files(ftrace) < 0) { 1202 pr_err("failed to reset ftrace\n"); 1203 goto out; 1204 } 1205 1206 /* reset ftrace buffer */ 1207 if (write_tracing_file("trace", "0") < 0) 1208 goto out; 1209 1210 if (set_tracing_options(ftrace) < 0) 1211 return -1; 1212 1213 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 1214 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 1215 goto out_reset; 1216 } 1217 1218 setup_pager(); 1219 1220 trace_file = get_tracing_file("trace_pipe"); 1221 if (!trace_file) { 1222 pr_err("failed to open trace_pipe\n"); 1223 goto out_reset; 1224 } 1225 1226 trace_fd = open(trace_file, O_RDONLY); 1227 1228 put_tracing_file(trace_file); 1229 1230 if (trace_fd < 0) { 1231 pr_err("failed to open trace_pipe\n"); 1232 goto out_reset; 1233 } 1234 1235 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 1236 1237 if (write_tracing_file("tracing_on", "1") < 0) { 1238 pr_err("can't enable tracing\n"); 1239 goto out_close_fd; 1240 } 1241 1242 evlist__start_workload(ftrace->evlist); 1243 1244 io__init(&io, trace_fd, buf, sizeof(buf)); 1245 io.timeout_ms = -1; 1246 1247 while (!done && !io.eof) { 1248 if (io__getline(&io, &line, &line_len) < 0) 1249 break; 1250 1251 if (parse_func_duration(ftrace, line, line_len) < 0) 1252 break; 1253 } 1254 1255 write_tracing_file("tracing_on", "0"); 1256 1257 if (workload_exec_errno) { 1258 const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf)); 1259 /* flush stdout first so below error msg appears at the end. */ 1260 fflush(stdout); 1261 pr_err("workload failed: %s\n", emsg); 1262 goto out_free_line; 1263 } 1264 1265 /* read remaining buffer contents */ 1266 io.timeout_ms = 0; 1267 while (!io.eof) { 1268 if (io__getline(&io, &line, &line_len) < 0) 1269 break; 1270 1271 if (parse_func_duration(ftrace, line, line_len) < 0) 1272 break; 1273 } 1274 1275 print_profile_result(ftrace); 1276 1277 out_free_line: 1278 free(line); 1279 out_close_fd: 1280 close(trace_fd); 1281 out_reset: 1282 reset_tracing_files(ftrace); 1283 out: 1284 return (done && !workload_exec_errno) ? 0 : -1; 1285 } 1286 1287 static int perf_ftrace_config(const char *var, const char *value, void *cb) 1288 { 1289 struct perf_ftrace *ftrace = cb; 1290 1291 if (!strstarts(var, "ftrace.")) 1292 return 0; 1293 1294 if (strcmp(var, "ftrace.tracer")) 1295 return -1; 1296 1297 if (!strcmp(value, "function_graph") || 1298 !strcmp(value, "function")) { 1299 ftrace->tracer = value; 1300 return 0; 1301 } 1302 1303 pr_err("Please select \"function_graph\" (default) or \"function\"\n"); 1304 return -1; 1305 } 1306 1307 static void list_function_cb(char *str, void *arg) 1308 { 1309 struct strfilter *filter = (struct strfilter *)arg; 1310 1311 if (strfilter__compare(filter, str)) 1312 printf("%s", str); 1313 } 1314 1315 static int opt_list_avail_functions(const struct option *opt __maybe_unused, 1316 const char *str, int unset) 1317 { 1318 struct strfilter *filter; 1319 const char *err = NULL; 1320 int ret; 1321 1322 if (unset || !str) 1323 return -1; 1324 1325 filter = strfilter__new(str, &err); 1326 if (!filter) 1327 return err ? -EINVAL : -ENOMEM; 1328 1329 ret = strfilter__or(filter, str, &err); 1330 if (ret == -EINVAL) { 1331 pr_err("Filter parse error at %td.\n", err - str + 1); 1332 pr_err("Source: \"%s\"\n", str); 1333 pr_err(" %*c\n", (int)(err - str + 1), '^'); 1334 strfilter__delete(filter); 1335 return ret; 1336 } 1337 1338 ret = read_tracing_file_by_line("available_filter_functions", 1339 list_function_cb, filter); 1340 strfilter__delete(filter); 1341 if (ret < 0) 1342 return ret; 1343 1344 exit(0); 1345 } 1346 1347 static int parse_filter_func(const struct option *opt, const char *str, 1348 int unset __maybe_unused) 1349 { 1350 struct list_head *head = opt->value; 1351 struct filter_entry *entry; 1352 1353 entry = malloc(sizeof(*entry) + strlen(str) + 1); 1354 if (entry == NULL) 1355 return -ENOMEM; 1356 1357 strcpy(entry->name, str); 1358 list_add_tail(&entry->list, head); 1359 1360 return 0; 1361 } 1362 1363 static void delete_filter_func(struct list_head *head) 1364 { 1365 struct filter_entry *pos, *tmp; 1366 1367 list_for_each_entry_safe(pos, tmp, head, list) { 1368 list_del_init(&pos->list); 1369 free(pos); 1370 } 1371 } 1372 1373 static int parse_buffer_size(const struct option *opt, 1374 const char *str, int unset) 1375 { 1376 unsigned long *s = (unsigned long *)opt->value; 1377 static struct parse_tag tags_size[] = { 1378 { .tag = 'B', .mult = 1 }, 1379 { .tag = 'K', .mult = 1 << 10 }, 1380 { .tag = 'M', .mult = 1 << 20 }, 1381 { .tag = 'G', .mult = 1 << 30 }, 1382 { .tag = 0 }, 1383 }; 1384 unsigned long val; 1385 1386 if (unset) { 1387 *s = 0; 1388 return 0; 1389 } 1390 1391 val = parse_tag_value(str, tags_size); 1392 if (val != (unsigned long) -1) { 1393 if (val < 1024) { 1394 pr_err("buffer size too small, must larger than 1KB."); 1395 return -1; 1396 } 1397 *s = val; 1398 return 0; 1399 } 1400 1401 return -1; 1402 } 1403 1404 static int parse_func_tracer_opts(const struct option *opt, 1405 const char *str, int unset) 1406 { 1407 int ret; 1408 struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 1409 struct sublevel_option func_tracer_opts[] = { 1410 { .name = "call-graph", .value_ptr = &ftrace->func_stack_trace }, 1411 { .name = "irq-info", .value_ptr = &ftrace->func_irq_info }, 1412 { .name = NULL, } 1413 }; 1414 1415 if (unset) 1416 return 0; 1417 1418 ret = perf_parse_sublevel_options(str, func_tracer_opts); 1419 if (ret) 1420 return ret; 1421 1422 return 0; 1423 } 1424 1425 static int parse_graph_tracer_opts(const struct option *opt, 1426 const char *str, int unset) 1427 { 1428 int ret; 1429 struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 1430 struct sublevel_option graph_tracer_opts[] = { 1431 { .name = "nosleep-time", .value_ptr = &ftrace->graph_nosleep_time }, 1432 { .name = "noirqs", .value_ptr = &ftrace->graph_noirqs }, 1433 { .name = "verbose", .value_ptr = &ftrace->graph_verbose }, 1434 { .name = "thresh", .value_ptr = &ftrace->graph_thresh }, 1435 { .name = "depth", .value_ptr = &ftrace->graph_depth }, 1436 { .name = "tail", .value_ptr = &ftrace->graph_tail }, 1437 { .name = NULL, } 1438 }; 1439 1440 if (unset) 1441 return 0; 1442 1443 ret = perf_parse_sublevel_options(str, graph_tracer_opts); 1444 if (ret) 1445 return ret; 1446 1447 return 0; 1448 } 1449 1450 static int parse_sort_key(const struct option *opt, const char *str, int unset) 1451 { 1452 enum perf_ftrace_profile_sort_key *key = (void *)opt->value; 1453 1454 if (unset) 1455 return 0; 1456 1457 if (!strcmp(str, "total")) 1458 *key = PFP_SORT_TOTAL; 1459 else if (!strcmp(str, "avg")) 1460 *key = PFP_SORT_AVG; 1461 else if (!strcmp(str, "max")) 1462 *key = PFP_SORT_MAX; 1463 else if (!strcmp(str, "count")) 1464 *key = PFP_SORT_COUNT; 1465 else if (!strcmp(str, "name")) 1466 *key = PFP_SORT_NAME; 1467 else { 1468 pr_err("Unknown sort key: %s\n", str); 1469 return -1; 1470 } 1471 return 0; 1472 } 1473 1474 enum perf_ftrace_subcommand { 1475 PERF_FTRACE_NONE, 1476 PERF_FTRACE_TRACE, 1477 PERF_FTRACE_LATENCY, 1478 PERF_FTRACE_PROFILE, 1479 }; 1480 1481 int cmd_ftrace(int argc, const char **argv) 1482 { 1483 int ret; 1484 int (*cmd_func)(struct perf_ftrace *) = NULL; 1485 struct perf_ftrace ftrace = { 1486 .tracer = DEFAULT_TRACER, 1487 .target = { .uid = UINT_MAX, }, 1488 }; 1489 const struct option common_options[] = { 1490 OPT_STRING('p', "pid", &ftrace.target.pid, "pid", 1491 "Trace on existing process id"), 1492 /* TODO: Add short option -t after -t/--tracer can be removed. */ 1493 OPT_STRING(0, "tid", &ftrace.target.tid, "tid", 1494 "Trace on existing thread id (exclusive to --pid)"), 1495 OPT_INCR('v', "verbose", &verbose, 1496 "Be more verbose"), 1497 OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide, 1498 "System-wide collection from all CPUs"), 1499 OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", 1500 "List of cpus to monitor"), 1501 OPT_END() 1502 }; 1503 const struct option ftrace_options[] = { 1504 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 1505 "Tracer to use: function_graph(default) or function"), 1506 OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", 1507 "Show available functions to filter", 1508 opt_list_avail_functions, "*"), 1509 OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 1510 "Trace given functions using function tracer", 1511 parse_filter_func), 1512 OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", 1513 "Do not trace given functions", parse_filter_func), 1514 OPT_CALLBACK(0, "func-opts", &ftrace, "options", 1515 "Function tracer options, available options: call-graph,irq-info", 1516 parse_func_tracer_opts), 1517 OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", 1518 "Trace given functions using function_graph tracer", 1519 parse_filter_func), 1520 OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", 1521 "Set nograph filter on given functions", parse_filter_func), 1522 OPT_CALLBACK(0, "graph-opts", &ftrace, "options", 1523 "Graph tracer options, available options: nosleep-time,noirqs,verbose,thresh=<n>,depth=<n>", 1524 parse_graph_tracer_opts), 1525 OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size", 1526 "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size), 1527 OPT_BOOLEAN(0, "inherit", &ftrace.inherit, 1528 "Trace children processes"), 1529 OPT_INTEGER('D', "delay", &ftrace.target.initial_delay, 1530 "Number of milliseconds to wait before starting tracing after program start"), 1531 OPT_PARENT(common_options), 1532 }; 1533 const struct option latency_options[] = { 1534 OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 1535 "Show latency of given function", parse_filter_func), 1536 #ifdef HAVE_BPF_SKEL 1537 OPT_BOOLEAN('b', "use-bpf", &ftrace.target.use_bpf, 1538 "Use BPF to measure function latency"), 1539 #endif 1540 OPT_BOOLEAN('n', "use-nsec", &ftrace.use_nsec, 1541 "Use nano-second histogram"), 1542 OPT_PARENT(common_options), 1543 }; 1544 const struct option profile_options[] = { 1545 OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 1546 "Trace given functions using function tracer", 1547 parse_filter_func), 1548 OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", 1549 "Do not trace given functions", parse_filter_func), 1550 OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", 1551 "Trace given functions using function_graph tracer", 1552 parse_filter_func), 1553 OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", 1554 "Set nograph filter on given functions", parse_filter_func), 1555 OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size", 1556 "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size), 1557 OPT_CALLBACK('s', "sort", &profile_sort, "key", 1558 "Sort result by key: total (default), avg, max, count, name.", 1559 parse_sort_key), 1560 OPT_PARENT(common_options), 1561 }; 1562 const struct option *options = ftrace_options; 1563 1564 const char * const ftrace_usage[] = { 1565 "perf ftrace [<options>] [<command>]", 1566 "perf ftrace [<options>] -- [<command>] [<options>]", 1567 "perf ftrace {trace|latency|profile} [<options>] [<command>]", 1568 "perf ftrace {trace|latency|profile} [<options>] -- [<command>] [<options>]", 1569 NULL 1570 }; 1571 enum perf_ftrace_subcommand subcmd = PERF_FTRACE_NONE; 1572 1573 INIT_LIST_HEAD(&ftrace.filters); 1574 INIT_LIST_HEAD(&ftrace.notrace); 1575 INIT_LIST_HEAD(&ftrace.graph_funcs); 1576 INIT_LIST_HEAD(&ftrace.nograph_funcs); 1577 1578 signal(SIGINT, sig_handler); 1579 signal(SIGUSR1, sig_handler); 1580 signal(SIGCHLD, sig_handler); 1581 signal(SIGPIPE, sig_handler); 1582 1583 if (!check_ftrace_capable()) 1584 return -1; 1585 1586 ret = perf_config(perf_ftrace_config, &ftrace); 1587 if (ret < 0) 1588 return -1; 1589 1590 if (argc > 1) { 1591 if (!strcmp(argv[1], "trace")) { 1592 subcmd = PERF_FTRACE_TRACE; 1593 } else if (!strcmp(argv[1], "latency")) { 1594 subcmd = PERF_FTRACE_LATENCY; 1595 options = latency_options; 1596 } else if (!strcmp(argv[1], "profile")) { 1597 subcmd = PERF_FTRACE_PROFILE; 1598 options = profile_options; 1599 } 1600 1601 if (subcmd != PERF_FTRACE_NONE) { 1602 argc--; 1603 argv++; 1604 } 1605 } 1606 /* for backward compatibility */ 1607 if (subcmd == PERF_FTRACE_NONE) 1608 subcmd = PERF_FTRACE_TRACE; 1609 1610 argc = parse_options(argc, argv, options, ftrace_usage, 1611 PARSE_OPT_STOP_AT_NON_OPTION); 1612 if (argc < 0) { 1613 ret = -EINVAL; 1614 goto out_delete_filters; 1615 } 1616 1617 /* Make system wide (-a) the default target. */ 1618 if (!argc && target__none(&ftrace.target)) 1619 ftrace.target.system_wide = true; 1620 1621 switch (subcmd) { 1622 case PERF_FTRACE_TRACE: 1623 cmd_func = __cmd_ftrace; 1624 break; 1625 case PERF_FTRACE_LATENCY: 1626 if (list_empty(&ftrace.filters)) { 1627 pr_err("Should provide a function to measure\n"); 1628 parse_options_usage(ftrace_usage, options, "T", 1); 1629 ret = -EINVAL; 1630 goto out_delete_filters; 1631 } 1632 cmd_func = __cmd_latency; 1633 break; 1634 case PERF_FTRACE_PROFILE: 1635 cmd_func = __cmd_profile; 1636 break; 1637 case PERF_FTRACE_NONE: 1638 default: 1639 pr_err("Invalid subcommand\n"); 1640 ret = -EINVAL; 1641 goto out_delete_filters; 1642 } 1643 1644 ret = target__validate(&ftrace.target); 1645 if (ret) { 1646 char errbuf[512]; 1647 1648 target__strerror(&ftrace.target, ret, errbuf, 512); 1649 pr_err("%s\n", errbuf); 1650 goto out_delete_filters; 1651 } 1652 1653 ftrace.evlist = evlist__new(); 1654 if (ftrace.evlist == NULL) { 1655 ret = -ENOMEM; 1656 goto out_delete_filters; 1657 } 1658 1659 ret = evlist__create_maps(ftrace.evlist, &ftrace.target); 1660 if (ret < 0) 1661 goto out_delete_evlist; 1662 1663 if (argc) { 1664 ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target, 1665 argv, false, 1666 ftrace__workload_exec_failed_signal); 1667 if (ret < 0) 1668 goto out_delete_evlist; 1669 } 1670 1671 ret = cmd_func(&ftrace); 1672 1673 out_delete_evlist: 1674 evlist__delete(ftrace.evlist); 1675 1676 out_delete_filters: 1677 delete_filter_func(&ftrace.filters); 1678 delete_filter_func(&ftrace.notrace); 1679 delete_filter_func(&ftrace.graph_funcs); 1680 delete_filter_func(&ftrace.nograph_funcs); 1681 1682 return ret; 1683 } 1684