linux/tools/perf/builtin-ftrace.c
<<
>>
Prefs
   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 <poll.h>
  17#include <linux/capability.h>
  18#include <linux/string.h>
  19
  20#include "debug.h"
  21#include <subcmd/pager.h>
  22#include <subcmd/parse-options.h>
  23#include <api/fs/tracing_path.h>
  24#include "evlist.h"
  25#include "target.h"
  26#include "cpumap.h"
  27#include "thread_map.h"
  28#include "strfilter.h"
  29#include "util/cap.h"
  30#include "util/config.h"
  31#include "util/units.h"
  32#include "util/parse-sublevel-options.h"
  33
  34#define DEFAULT_TRACER  "function_graph"
  35
  36struct perf_ftrace {
  37        struct evlist           *evlist;
  38        struct target           target;
  39        const char              *tracer;
  40        struct list_head        filters;
  41        struct list_head        notrace;
  42        struct list_head        graph_funcs;
  43        struct list_head        nograph_funcs;
  44        int                     graph_depth;
  45        unsigned long           percpu_buffer_size;
  46        bool                    inherit;
  47        int                     func_stack_trace;
  48        int                     func_irq_info;
  49        int                     graph_nosleep_time;
  50        int                     graph_noirqs;
  51        int                     graph_verbose;
  52        int                     graph_thresh;
  53        unsigned int            initial_delay;
  54};
  55
  56struct filter_entry {
  57        struct list_head        list;
  58        char                    name[];
  59};
  60
  61static volatile int workload_exec_errno;
  62static bool done;
  63
  64static void sig_handler(int sig __maybe_unused)
  65{
  66        done = true;
  67}
  68
  69/*
  70 * evlist__prepare_workload will send a SIGUSR1 if the fork fails, since
  71 * we asked by setting its exec_error to the function below,
  72 * ftrace__workload_exec_failed_signal.
  73 *
  74 * XXX We need to handle this more appropriately, emitting an error, etc.
  75 */
  76static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
  77                                                siginfo_t *info __maybe_unused,
  78                                                void *ucontext __maybe_unused)
  79{
  80        workload_exec_errno = info->si_value.sival_int;
  81        done = true;
  82}
  83
  84static int __write_tracing_file(const char *name, const char *val, bool append)
  85{
  86        char *file;
  87        int fd, ret = -1;
  88        ssize_t size = strlen(val);
  89        int flags = O_WRONLY;
  90        char errbuf[512];
  91        char *val_copy;
  92
  93        file = get_tracing_file(name);
  94        if (!file) {
  95                pr_debug("cannot get tracing file: %s\n", name);
  96                return -1;
  97        }
  98
  99        if (append)
 100                flags |= O_APPEND;
 101        else
 102                flags |= O_TRUNC;
 103
 104        fd = open(file, flags);
 105        if (fd < 0) {
 106                pr_debug("cannot open tracing file: %s: %s\n",
 107                         name, str_error_r(errno, errbuf, sizeof(errbuf)));
 108                goto out;
 109        }
 110
 111        /*
 112         * Copy the original value and append a '\n'. Without this,
 113         * the kernel can hide possible errors.
 114         */
 115        val_copy = strdup(val);
 116        if (!val_copy)
 117                goto out_close;
 118        val_copy[size] = '\n';
 119
 120        if (write(fd, val_copy, size + 1) == size + 1)
 121                ret = 0;
 122        else
 123                pr_debug("write '%s' to tracing/%s failed: %s\n",
 124                         val, name, str_error_r(errno, errbuf, sizeof(errbuf)));
 125
 126        free(val_copy);
 127out_close:
 128        close(fd);
 129out:
 130        put_tracing_file(file);
 131        return ret;
 132}
 133
 134static int write_tracing_file(const char *name, const char *val)
 135{
 136        return __write_tracing_file(name, val, false);
 137}
 138
 139static int append_tracing_file(const char *name, const char *val)
 140{
 141        return __write_tracing_file(name, val, true);
 142}
 143
 144static int read_tracing_file_to_stdout(const char *name)
 145{
 146        char buf[4096];
 147        char *file;
 148        int fd;
 149        int ret = -1;
 150
 151        file = get_tracing_file(name);
 152        if (!file) {
 153                pr_debug("cannot get tracing file: %s\n", name);
 154                return -1;
 155        }
 156
 157        fd = open(file, O_RDONLY);
 158        if (fd < 0) {
 159                pr_debug("cannot open tracing file: %s: %s\n",
 160                         name, str_error_r(errno, buf, sizeof(buf)));
 161                goto out;
 162        }
 163
 164        /* read contents to stdout */
 165        while (true) {
 166                int n = read(fd, buf, sizeof(buf));
 167                if (n == 0)
 168                        break;
 169                else if (n < 0)
 170                        goto out_close;
 171
 172                if (fwrite(buf, n, 1, stdout) != 1)
 173                        goto out_close;
 174        }
 175        ret = 0;
 176
 177out_close:
 178        close(fd);
 179out:
 180        put_tracing_file(file);
 181        return ret;
 182}
 183
 184static int read_tracing_file_by_line(const char *name,
 185                                     void (*cb)(char *str, void *arg),
 186                                     void *cb_arg)
 187{
 188        char *line = NULL;
 189        size_t len = 0;
 190        char *file;
 191        FILE *fp;
 192
 193        file = get_tracing_file(name);
 194        if (!file) {
 195                pr_debug("cannot get tracing file: %s\n", name);
 196                return -1;
 197        }
 198
 199        fp = fopen(file, "r");
 200        if (fp == NULL) {
 201                pr_debug("cannot open tracing file: %s\n", name);
 202                put_tracing_file(file);
 203                return -1;
 204        }
 205
 206        while (getline(&line, &len, fp) != -1) {
 207                cb(line, cb_arg);
 208        }
 209
 210        if (line)
 211                free(line);
 212
 213        fclose(fp);
 214        put_tracing_file(file);
 215        return 0;
 216}
 217
 218static int write_tracing_file_int(const char *name, int value)
 219{
 220        char buf[16];
 221
 222        snprintf(buf, sizeof(buf), "%d", value);
 223        if (write_tracing_file(name, buf) < 0)
 224                return -1;
 225
 226        return 0;
 227}
 228
 229static int write_tracing_option_file(const char *name, const char *val)
 230{
 231        char *file;
 232        int ret;
 233
 234        if (asprintf(&file, "options/%s", name) < 0)
 235                return -1;
 236
 237        ret = __write_tracing_file(file, val, false);
 238        free(file);
 239        return ret;
 240}
 241
 242static int reset_tracing_cpu(void);
 243static void reset_tracing_filters(void);
 244
 245static void reset_tracing_options(struct perf_ftrace *ftrace __maybe_unused)
 246{
 247        write_tracing_option_file("function-fork", "0");
 248        write_tracing_option_file("func_stack_trace", "0");
 249        write_tracing_option_file("sleep-time", "1");
 250        write_tracing_option_file("funcgraph-irqs", "1");
 251        write_tracing_option_file("funcgraph-proc", "0");
 252        write_tracing_option_file("funcgraph-abstime", "0");
 253        write_tracing_option_file("latency-format", "0");
 254        write_tracing_option_file("irq-info", "0");
 255}
 256
 257static 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
 282static 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
 299static 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 = cpu_map__cpu(cpumap, cpumap->nr - 1);
 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
 324static int set_tracing_cpu(struct perf_ftrace *ftrace)
 325{
 326        struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus;
 327
 328        if (!target__has_cpu(&ftrace->target))
 329                return 0;
 330
 331        return set_tracing_cpumask(cpumap);
 332}
 333
 334static 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
 345static 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
 356static int reset_tracing_cpu(void)
 357{
 358        struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL);
 359        int ret;
 360
 361        ret = set_tracing_cpumask(cpumap);
 362        perf_cpu_map__put(cpumap);
 363        return ret;
 364}
 365
 366static 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
 378static 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
 400static 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
 408static 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
 424static 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
 439static 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
 450static 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
 461static 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
 472static 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
 489static int set_tracing_thresh(struct perf_ftrace *ftrace)
 490{
 491        int ret;
 492
 493        if (ftrace->graph_thresh == 0)
 494                return 0;
 495
 496        ret = write_tracing_file_int("tracing_thresh", ftrace->graph_thresh);
 497        if (ret < 0)
 498                return ret;
 499
 500        return 0;
 501}
 502
 503static int set_tracing_options(struct perf_ftrace *ftrace)
 504{
 505        if (set_tracing_pid(ftrace) < 0) {
 506                pr_err("failed to set ftrace pid\n");
 507                return -1;
 508        }
 509
 510        if (set_tracing_cpu(ftrace) < 0) {
 511                pr_err("failed to set tracing cpumask\n");
 512                return -1;
 513        }
 514
 515        if (set_tracing_func_stack_trace(ftrace) < 0) {
 516                pr_err("failed to set tracing option func_stack_trace\n");
 517                return -1;
 518        }
 519
 520        if (set_tracing_func_irqinfo(ftrace) < 0) {
 521                pr_err("failed to set tracing option irq-info\n");
 522                return -1;
 523        }
 524
 525        if (set_tracing_filters(ftrace) < 0) {
 526                pr_err("failed to set tracing filters\n");
 527                return -1;
 528        }
 529
 530        if (set_tracing_depth(ftrace) < 0) {
 531                pr_err("failed to set graph depth\n");
 532                return -1;
 533        }
 534
 535        if (set_tracing_percpu_buffer_size(ftrace) < 0) {
 536                pr_err("failed to set tracing per-cpu buffer size\n");
 537                return -1;
 538        }
 539
 540        if (set_tracing_trace_inherit(ftrace) < 0) {
 541                pr_err("failed to set tracing option function-fork\n");
 542                return -1;
 543        }
 544
 545        if (set_tracing_sleep_time(ftrace) < 0) {
 546                pr_err("failed to set tracing option sleep-time\n");
 547                return -1;
 548        }
 549
 550        if (set_tracing_funcgraph_irqs(ftrace) < 0) {
 551                pr_err("failed to set tracing option funcgraph-irqs\n");
 552                return -1;
 553        }
 554
 555        if (set_tracing_funcgraph_verbose(ftrace) < 0) {
 556                pr_err("failed to set tracing option funcgraph-proc/funcgraph-abstime\n");
 557                return -1;
 558        }
 559
 560        if (set_tracing_thresh(ftrace) < 0) {
 561                pr_err("failed to set tracing thresh\n");
 562                return -1;
 563        }
 564
 565        return 0;
 566}
 567
 568static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 569{
 570        char *trace_file;
 571        int trace_fd;
 572        char buf[4096];
 573        struct pollfd pollfd = {
 574                .events = POLLIN,
 575        };
 576
 577        if (!(perf_cap__capable(CAP_PERFMON) ||
 578              perf_cap__capable(CAP_SYS_ADMIN))) {
 579                pr_err("ftrace only works for %s!\n",
 580#ifdef HAVE_LIBCAP_SUPPORT
 581                "users with the CAP_PERFMON or CAP_SYS_ADMIN capability"
 582#else
 583                "root"
 584#endif
 585                );
 586                return -1;
 587        }
 588
 589        signal(SIGINT, sig_handler);
 590        signal(SIGUSR1, sig_handler);
 591        signal(SIGCHLD, sig_handler);
 592        signal(SIGPIPE, sig_handler);
 593
 594        if (reset_tracing_files(ftrace) < 0) {
 595                pr_err("failed to reset ftrace\n");
 596                goto out;
 597        }
 598
 599        /* reset ftrace buffer */
 600        if (write_tracing_file("trace", "0") < 0)
 601                goto out;
 602
 603        if (argc && evlist__prepare_workload(ftrace->evlist, &ftrace->target, argv, false,
 604                                             ftrace__workload_exec_failed_signal) < 0) {
 605                goto out;
 606        }
 607
 608        if (set_tracing_options(ftrace) < 0)
 609                goto out_reset;
 610
 611        if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
 612                pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
 613                goto out_reset;
 614        }
 615
 616        setup_pager();
 617
 618        trace_file = get_tracing_file("trace_pipe");
 619        if (!trace_file) {
 620                pr_err("failed to open trace_pipe\n");
 621                goto out_reset;
 622        }
 623
 624        trace_fd = open(trace_file, O_RDONLY);
 625
 626        put_tracing_file(trace_file);
 627
 628        if (trace_fd < 0) {
 629                pr_err("failed to open trace_pipe\n");
 630                goto out_reset;
 631        }
 632
 633        fcntl(trace_fd, F_SETFL, O_NONBLOCK);
 634        pollfd.fd = trace_fd;
 635
 636        /* display column headers */
 637        read_tracing_file_to_stdout("trace");
 638
 639        if (!ftrace->initial_delay) {
 640                if (write_tracing_file("tracing_on", "1") < 0) {
 641                        pr_err("can't enable tracing\n");
 642                        goto out_close_fd;
 643                }
 644        }
 645
 646        evlist__start_workload(ftrace->evlist);
 647
 648        if (ftrace->initial_delay) {
 649                usleep(ftrace->initial_delay * 1000);
 650                if (write_tracing_file("tracing_on", "1") < 0) {
 651                        pr_err("can't enable tracing\n");
 652                        goto out_close_fd;
 653                }
 654        }
 655
 656        while (!done) {
 657                if (poll(&pollfd, 1, -1) < 0)
 658                        break;
 659
 660                if (pollfd.revents & POLLIN) {
 661                        int n = read(trace_fd, buf, sizeof(buf));
 662                        if (n < 0)
 663                                break;
 664                        if (fwrite(buf, n, 1, stdout) != 1)
 665                                break;
 666                }
 667        }
 668
 669        write_tracing_file("tracing_on", "0");
 670
 671        if (workload_exec_errno) {
 672                const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf));
 673                /* flush stdout first so below error msg appears at the end. */
 674                fflush(stdout);
 675                pr_err("workload failed: %s\n", emsg);
 676                goto out_close_fd;
 677        }
 678
 679        /* read remaining buffer contents */
 680        while (true) {
 681                int n = read(trace_fd, buf, sizeof(buf));
 682                if (n <= 0)
 683                        break;
 684                if (fwrite(buf, n, 1, stdout) != 1)
 685                        break;
 686        }
 687
 688out_close_fd:
 689        close(trace_fd);
 690out_reset:
 691        reset_tracing_files(ftrace);
 692out:
 693        return (done && !workload_exec_errno) ? 0 : -1;
 694}
 695
 696static int perf_ftrace_config(const char *var, const char *value, void *cb)
 697{
 698        struct perf_ftrace *ftrace = cb;
 699
 700        if (!strstarts(var, "ftrace."))
 701                return 0;
 702
 703        if (strcmp(var, "ftrace.tracer"))
 704                return -1;
 705
 706        if (!strcmp(value, "function_graph") ||
 707            !strcmp(value, "function")) {
 708                ftrace->tracer = value;
 709                return 0;
 710        }
 711
 712        pr_err("Please select \"function_graph\" (default) or \"function\"\n");
 713        return -1;
 714}
 715
 716static void list_function_cb(char *str, void *arg)
 717{
 718        struct strfilter *filter = (struct strfilter *)arg;
 719
 720        if (strfilter__compare(filter, str))
 721                printf("%s", str);
 722}
 723
 724static int opt_list_avail_functions(const struct option *opt __maybe_unused,
 725                                    const char *str, int unset)
 726{
 727        struct strfilter *filter;
 728        const char *err = NULL;
 729        int ret;
 730
 731        if (unset || !str)
 732                return -1;
 733
 734        filter = strfilter__new(str, &err);
 735        if (!filter)
 736                return err ? -EINVAL : -ENOMEM;
 737
 738        ret = strfilter__or(filter, str, &err);
 739        if (ret == -EINVAL) {
 740                pr_err("Filter parse error at %td.\n", err - str + 1);
 741                pr_err("Source: \"%s\"\n", str);
 742                pr_err("         %*c\n", (int)(err - str + 1), '^');
 743                strfilter__delete(filter);
 744                return ret;
 745        }
 746
 747        ret = read_tracing_file_by_line("available_filter_functions",
 748                                        list_function_cb, filter);
 749        strfilter__delete(filter);
 750        if (ret < 0)
 751                return ret;
 752
 753        exit(0);
 754}
 755
 756static int parse_filter_func(const struct option *opt, const char *str,
 757                             int unset __maybe_unused)
 758{
 759        struct list_head *head = opt->value;
 760        struct filter_entry *entry;
 761
 762        entry = malloc(sizeof(*entry) + strlen(str) + 1);
 763        if (entry == NULL)
 764                return -ENOMEM;
 765
 766        strcpy(entry->name, str);
 767        list_add_tail(&entry->list, head);
 768
 769        return 0;
 770}
 771
 772static void delete_filter_func(struct list_head *head)
 773{
 774        struct filter_entry *pos, *tmp;
 775
 776        list_for_each_entry_safe(pos, tmp, head, list) {
 777                list_del_init(&pos->list);
 778                free(pos);
 779        }
 780}
 781
 782static int parse_buffer_size(const struct option *opt,
 783                             const char *str, int unset)
 784{
 785        unsigned long *s = (unsigned long *)opt->value;
 786        static struct parse_tag tags_size[] = {
 787                { .tag  = 'B', .mult = 1       },
 788                { .tag  = 'K', .mult = 1 << 10 },
 789                { .tag  = 'M', .mult = 1 << 20 },
 790                { .tag  = 'G', .mult = 1 << 30 },
 791                { .tag  = 0 },
 792        };
 793        unsigned long val;
 794
 795        if (unset) {
 796                *s = 0;
 797                return 0;
 798        }
 799
 800        val = parse_tag_value(str, tags_size);
 801        if (val != (unsigned long) -1) {
 802                if (val < 1024) {
 803                        pr_err("buffer size too small, must larger than 1KB.");
 804                        return -1;
 805                }
 806                *s = val;
 807                return 0;
 808        }
 809
 810        return -1;
 811}
 812
 813static int parse_func_tracer_opts(const struct option *opt,
 814                                  const char *str, int unset)
 815{
 816        int ret;
 817        struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value;
 818        struct sublevel_option func_tracer_opts[] = {
 819                { .name = "call-graph", .value_ptr = &ftrace->func_stack_trace },
 820                { .name = "irq-info",   .value_ptr = &ftrace->func_irq_info },
 821                { .name = NULL, }
 822        };
 823
 824        if (unset)
 825                return 0;
 826
 827        ret = perf_parse_sublevel_options(str, func_tracer_opts);
 828        if (ret)
 829                return ret;
 830
 831        return 0;
 832}
 833
 834static int parse_graph_tracer_opts(const struct option *opt,
 835                                  const char *str, int unset)
 836{
 837        int ret;
 838        struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value;
 839        struct sublevel_option graph_tracer_opts[] = {
 840                { .name = "nosleep-time",       .value_ptr = &ftrace->graph_nosleep_time },
 841                { .name = "noirqs",             .value_ptr = &ftrace->graph_noirqs },
 842                { .name = "verbose",            .value_ptr = &ftrace->graph_verbose },
 843                { .name = "thresh",             .value_ptr = &ftrace->graph_thresh },
 844                { .name = "depth",              .value_ptr = &ftrace->graph_depth },
 845                { .name = NULL, }
 846        };
 847
 848        if (unset)
 849                return 0;
 850
 851        ret = perf_parse_sublevel_options(str, graph_tracer_opts);
 852        if (ret)
 853                return ret;
 854
 855        return 0;
 856}
 857
 858static void select_tracer(struct perf_ftrace *ftrace)
 859{
 860        bool graph = !list_empty(&ftrace->graph_funcs) ||
 861                     !list_empty(&ftrace->nograph_funcs);
 862        bool func = !list_empty(&ftrace->filters) ||
 863                    !list_empty(&ftrace->notrace);
 864
 865        /* The function_graph has priority over function tracer. */
 866        if (graph)
 867                ftrace->tracer = "function_graph";
 868        else if (func)
 869                ftrace->tracer = "function";
 870        /* Otherwise, the default tracer is used. */
 871
 872        pr_debug("%s tracer is used\n", ftrace->tracer);
 873}
 874
 875int cmd_ftrace(int argc, const char **argv)
 876{
 877        int ret;
 878        struct perf_ftrace ftrace = {
 879                .tracer = DEFAULT_TRACER,
 880                .target = { .uid = UINT_MAX, },
 881        };
 882        const char * const ftrace_usage[] = {
 883                "perf ftrace [<options>] [<command>]",
 884                "perf ftrace [<options>] -- <command> [<options>]",
 885                NULL
 886        };
 887        const struct option ftrace_options[] = {
 888        OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
 889                   "Tracer to use: function_graph(default) or function"),
 890        OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]",
 891                             "Show available functions to filter",
 892                             opt_list_avail_functions, "*"),
 893        OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
 894                   "Trace on existing process id"),
 895        /* TODO: Add short option -t after -t/--tracer can be removed. */
 896        OPT_STRING(0, "tid", &ftrace.target.tid, "tid",
 897                   "Trace on existing thread id (exclusive to --pid)"),
 898        OPT_INCR('v', "verbose", &verbose,
 899                 "Be more verbose"),
 900        OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
 901                    "System-wide collection from all CPUs"),
 902        OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
 903                    "List of cpus to monitor"),
 904        OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func",
 905                     "Trace given functions using function tracer",
 906                     parse_filter_func),
 907        OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func",
 908                     "Do not trace given functions", parse_filter_func),
 909        OPT_CALLBACK(0, "func-opts", &ftrace, "options",
 910                     "Function tracer options, available options: call-graph,irq-info",
 911                     parse_func_tracer_opts),
 912        OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func",
 913                     "Trace given functions using function_graph tracer",
 914                     parse_filter_func),
 915        OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func",
 916                     "Set nograph filter on given functions", parse_filter_func),
 917        OPT_CALLBACK(0, "graph-opts", &ftrace, "options",
 918                     "Graph tracer options, available options: nosleep-time,noirqs,verbose,thresh=<n>,depth=<n>",
 919                     parse_graph_tracer_opts),
 920        OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size",
 921                     "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size),
 922        OPT_BOOLEAN(0, "inherit", &ftrace.inherit,
 923                    "Trace children processes"),
 924        OPT_UINTEGER('D', "delay", &ftrace.initial_delay,
 925                     "Number of milliseconds to wait before starting tracing after program start"),
 926        OPT_END()
 927        };
 928
 929        INIT_LIST_HEAD(&ftrace.filters);
 930        INIT_LIST_HEAD(&ftrace.notrace);
 931        INIT_LIST_HEAD(&ftrace.graph_funcs);
 932        INIT_LIST_HEAD(&ftrace.nograph_funcs);
 933
 934        ret = perf_config(perf_ftrace_config, &ftrace);
 935        if (ret < 0)
 936                return -1;
 937
 938        argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
 939                            PARSE_OPT_STOP_AT_NON_OPTION);
 940        if (!argc && target__none(&ftrace.target))
 941                ftrace.target.system_wide = true;
 942
 943        select_tracer(&ftrace);
 944
 945        ret = target__validate(&ftrace.target);
 946        if (ret) {
 947                char errbuf[512];
 948
 949                target__strerror(&ftrace.target, ret, errbuf, 512);
 950                pr_err("%s\n", errbuf);
 951                goto out_delete_filters;
 952        }
 953
 954        ftrace.evlist = evlist__new();
 955        if (ftrace.evlist == NULL) {
 956                ret = -ENOMEM;
 957                goto out_delete_filters;
 958        }
 959
 960        ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
 961        if (ret < 0)
 962                goto out_delete_evlist;
 963
 964        ret = __cmd_ftrace(&ftrace, argc, argv);
 965
 966out_delete_evlist:
 967        evlist__delete(ftrace.evlist);
 968
 969out_delete_filters:
 970        delete_filter_func(&ftrace.filters);
 971        delete_filter_func(&ftrace.notrace);
 972        delete_filter_func(&ftrace.graph_funcs);
 973        delete_filter_func(&ftrace.nograph_funcs);
 974
 975        return ret;
 976}
 977
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.