linux/tools/perf/builtin-report.c
<<
>>
Prefs
   1/*
   2 * builtin-report.c
   3 *
   4 * Builtin report command: Analyze the perf.data input file,
   5 * look up and read DSOs and symbol information and display
   6 * a histogram of results, along various sorting keys.
   7 */
   8#include "builtin.h"
   9
  10#include "util/util.h"
  11#include "util/cache.h"
  12
  13#include "util/annotate.h"
  14#include "util/color.h"
  15#include <linux/list.h>
  16#include <linux/rbtree.h>
  17#include "util/symbol.h"
  18#include "util/callchain.h"
  19#include "util/strlist.h"
  20#include "util/values.h"
  21
  22#include "perf.h"
  23#include "util/debug.h"
  24#include "util/evlist.h"
  25#include "util/evsel.h"
  26#include "util/header.h"
  27#include "util/session.h"
  28#include "util/tool.h"
  29
  30#include "util/parse-options.h"
  31#include "util/parse-events.h"
  32
  33#include "util/thread.h"
  34#include "util/sort.h"
  35#include "util/hist.h"
  36#include "util/data.h"
  37#include "arch/common.h"
  38
  39#include <dlfcn.h>
  40#include <linux/bitmap.h>
  41
  42struct report {
  43        struct perf_tool        tool;
  44        struct perf_session     *session;
  45        bool                    force, use_tui, use_gtk, use_stdio;
  46        bool                    hide_unresolved;
  47        bool                    dont_use_callchains;
  48        bool                    show_full_info;
  49        bool                    show_threads;
  50        bool                    inverted_callchain;
  51        bool                    mem_mode;
  52        bool                    header;
  53        bool                    header_only;
  54        int                     max_stack;
  55        struct perf_read_values show_threads_values;
  56        const char              *pretty_printing_style;
  57        const char              *cpu_list;
  58        const char              *symbol_filter_str;
  59        float                   min_percent;
  60        u64                     nr_entries;
  61        u64                     queue_size;
  62        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
  63};
  64
  65static int report__config(const char *var, const char *value, void *cb)
  66{
  67        struct report *rep = cb;
  68
  69        if (!strcmp(var, "report.group")) {
  70                symbol_conf.event_group = perf_config_bool(var, value);
  71                return 0;
  72        }
  73        if (!strcmp(var, "report.percent-limit")) {
  74                rep->min_percent = strtof(value, NULL);
  75                return 0;
  76        }
  77        if (!strcmp(var, "report.children")) {
  78                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
  79                return 0;
  80        }
  81        if (!strcmp(var, "report.queue-size")) {
  82                rep->queue_size = perf_config_u64(var, value);
  83                return 0;
  84        }
  85
  86        return perf_default_config(var, value, cb);
  87}
  88
  89static int hist_iter__report_callback(struct hist_entry_iter *iter,
  90                                      struct addr_location *al, bool single,
  91                                      void *arg)
  92{
  93        int err = 0;
  94        struct report *rep = arg;
  95        struct hist_entry *he = iter->he;
  96        struct perf_evsel *evsel = iter->evsel;
  97        struct mem_info *mi;
  98        struct branch_info *bi;
  99
 100        if (!ui__has_annotation())
 101                return 0;
 102
 103        if (sort__mode == SORT_MODE__BRANCH) {
 104                bi = he->branch_info;
 105                err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
 106                if (err)
 107                        goto out;
 108
 109                err = addr_map_symbol__inc_samples(&bi->to, evsel->idx);
 110
 111        } else if (rep->mem_mode) {
 112                mi = he->mem_info;
 113                err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx);
 114                if (err)
 115                        goto out;
 116
 117                err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
 118
 119        } else if (symbol_conf.cumulate_callchain) {
 120                if (single)
 121                        err = hist_entry__inc_addr_samples(he, evsel->idx,
 122                                                           al->addr);
 123        } else {
 124                err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
 125        }
 126
 127out:
 128        return err;
 129}
 130
 131static int process_sample_event(struct perf_tool *tool,
 132                                union perf_event *event,
 133                                struct perf_sample *sample,
 134                                struct perf_evsel *evsel,
 135                                struct machine *machine)
 136{
 137        struct report *rep = container_of(tool, struct report, tool);
 138        struct addr_location al;
 139        struct hist_entry_iter iter = {
 140                .hide_unresolved = rep->hide_unresolved,
 141                .add_entry_cb = hist_iter__report_callback,
 142        };
 143        int ret;
 144
 145        if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 146                pr_debug("problem processing %d event, skipping it.\n",
 147                         event->header.type);
 148                return -1;
 149        }
 150
 151        if (rep->hide_unresolved && al.sym == NULL)
 152                return 0;
 153
 154        if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
 155                return 0;
 156
 157        if (sort__mode == SORT_MODE__BRANCH)
 158                iter.ops = &hist_iter_branch;
 159        else if (rep->mem_mode)
 160                iter.ops = &hist_iter_mem;
 161        else if (symbol_conf.cumulate_callchain)
 162                iter.ops = &hist_iter_cumulative;
 163        else
 164                iter.ops = &hist_iter_normal;
 165
 166        if (al.map != NULL)
 167                al.map->dso->hit = 1;
 168
 169        ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack,
 170                                   rep);
 171        if (ret < 0)
 172                pr_debug("problem adding hist entry, skipping event\n");
 173
 174        return ret;
 175}
 176
 177static int process_read_event(struct perf_tool *tool,
 178                              union perf_event *event,
 179                              struct perf_sample *sample __maybe_unused,
 180                              struct perf_evsel *evsel,
 181                              struct machine *machine __maybe_unused)
 182{
 183        struct report *rep = container_of(tool, struct report, tool);
 184
 185        if (rep->show_threads) {
 186                const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
 187                perf_read_values_add_value(&rep->show_threads_values,
 188                                           event->read.pid, event->read.tid,
 189                                           event->read.id,
 190                                           name,
 191                                           event->read.value);
 192        }
 193
 194        dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
 195                    evsel ? perf_evsel__name(evsel) : "FAIL",
 196                    event->read.value);
 197
 198        return 0;
 199}
 200
 201/* For pipe mode, sample_type is not currently set */
 202static int report__setup_sample_type(struct report *rep)
 203{
 204        struct perf_session *session = rep->session;
 205        u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
 206        bool is_pipe = perf_data_file__is_pipe(session->file);
 207
 208        if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
 209                if (sort__has_parent) {
 210                        ui__error("Selected --sort parent, but no "
 211                                    "callchain data. Did you call "
 212                                    "'perf record' without -g?\n");
 213                        return -EINVAL;
 214                }
 215                if (symbol_conf.use_callchain) {
 216                        ui__error("Selected -g or --branch-history but no "
 217                                  "callchain data. Did\n"
 218                                  "you call 'perf record' without -g?\n");
 219                        return -1;
 220                }
 221        } else if (!rep->dont_use_callchains &&
 222                   callchain_param.mode != CHAIN_NONE &&
 223                   !symbol_conf.use_callchain) {
 224                        symbol_conf.use_callchain = true;
 225                        if (callchain_register_param(&callchain_param) < 0) {
 226                                ui__error("Can't register callchain params.\n");
 227                                return -EINVAL;
 228                        }
 229        }
 230
 231        if (symbol_conf.cumulate_callchain) {
 232                /* Silently ignore if callchain is missing */
 233                if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
 234                        symbol_conf.cumulate_callchain = false;
 235                        perf_hpp__cancel_cumulate();
 236                }
 237        }
 238
 239        if (sort__mode == SORT_MODE__BRANCH) {
 240                if (!is_pipe &&
 241                    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
 242                        ui__error("Selected -b but no branch data. "
 243                                  "Did you call perf record without -b?\n");
 244                        return -1;
 245                }
 246        }
 247
 248        if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
 249                if ((sample_type & PERF_SAMPLE_REGS_USER) &&
 250                    (sample_type & PERF_SAMPLE_STACK_USER))
 251                        callchain_param.record_mode = CALLCHAIN_DWARF;
 252                else
 253                        callchain_param.record_mode = CALLCHAIN_FP;
 254        }
 255        return 0;
 256}
 257
 258static void sig_handler(int sig __maybe_unused)
 259{
 260        session_done = 1;
 261}
 262
 263static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
 264                                              const char *evname, FILE *fp)
 265{
 266        size_t ret;
 267        char unit;
 268        unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
 269        u64 nr_events = hists->stats.total_period;
 270        struct perf_evsel *evsel = hists_to_evsel(hists);
 271        char buf[512];
 272        size_t size = sizeof(buf);
 273
 274        if (symbol_conf.filter_relative) {
 275                nr_samples = hists->stats.nr_non_filtered_samples;
 276                nr_events = hists->stats.total_non_filtered_period;
 277        }
 278
 279        if (perf_evsel__is_group_event(evsel)) {
 280                struct perf_evsel *pos;
 281
 282                perf_evsel__group_desc(evsel, buf, size);
 283                evname = buf;
 284
 285                for_each_group_member(pos, evsel) {
 286                        const struct hists *pos_hists = evsel__hists(pos);
 287
 288                        if (symbol_conf.filter_relative) {
 289                                nr_samples += pos_hists->stats.nr_non_filtered_samples;
 290                                nr_events += pos_hists->stats.total_non_filtered_period;
 291                        } else {
 292                                nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
 293                                nr_events += pos_hists->stats.total_period;
 294                        }
 295                }
 296        }
 297
 298        nr_samples = convert_unit(nr_samples, &unit);
 299        ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
 300        if (evname != NULL)
 301                ret += fprintf(fp, " of event '%s'", evname);
 302
 303        if (rep->mem_mode) {
 304                ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
 305                ret += fprintf(fp, "\n# Sort order   : %s", sort_order);
 306        } else
 307                ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
 308        return ret + fprintf(fp, "\n#\n");
 309}
 310
 311static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 312                                         struct report *rep,
 313                                         const char *help)
 314{
 315        struct perf_evsel *pos;
 316
 317        evlist__for_each(evlist, pos) {
 318                struct hists *hists = evsel__hists(pos);
 319                const char *evname = perf_evsel__name(pos);
 320
 321                if (symbol_conf.event_group &&
 322                    !perf_evsel__is_group_leader(pos))
 323                        continue;
 324
 325                hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
 326                hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
 327                fprintf(stdout, "\n\n");
 328        }
 329
 330        if (sort_order == default_sort_order &&
 331            parent_pattern == default_parent_pattern) {
 332                fprintf(stdout, "#\n# (%s)\n#\n", help);
 333
 334                if (rep->show_threads) {
 335                        bool style = !strcmp(rep->pretty_printing_style, "raw");
 336                        perf_read_values_display(stdout, &rep->show_threads_values,
 337                                                 style);
 338                        perf_read_values_destroy(&rep->show_threads_values);
 339                }
 340        }
 341
 342        return 0;
 343}
 344
 345static void report__warn_kptr_restrict(const struct report *rep)
 346{
 347        struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
 348        struct kmap *kernel_kmap = map__kmap(kernel_map);
 349
 350        if (kernel_map == NULL ||
 351            (kernel_map->dso->hit &&
 352             (kernel_kmap->ref_reloc_sym == NULL ||
 353              kernel_kmap->ref_reloc_sym->addr == 0))) {
 354                const char *desc =
 355                    "As no suitable kallsyms nor vmlinux was found, kernel samples\n"
 356                    "can't be resolved.";
 357
 358                if (kernel_map) {
 359                        const struct dso *kdso = kernel_map->dso;
 360                        if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
 361                                desc = "If some relocation was applied (e.g. "
 362                                       "kexec) symbols may be misresolved.";
 363                        }
 364                }
 365
 366                ui__warning(
 367"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
 368"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
 369"Samples in kernel modules can't be resolved as well.\n\n",
 370                desc);
 371        }
 372}
 373
 374static int report__gtk_browse_hists(struct report *rep, const char *help)
 375{
 376        int (*hist_browser)(struct perf_evlist *evlist, const char *help,
 377                            struct hist_browser_timer *timer, float min_pcnt);
 378
 379        hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");
 380
 381        if (hist_browser == NULL) {
 382                ui__error("GTK browser not found!\n");
 383                return -1;
 384        }
 385
 386        return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
 387}
 388
 389static int report__browse_hists(struct report *rep)
 390{
 391        int ret;
 392        struct perf_session *session = rep->session;
 393        struct perf_evlist *evlist = session->evlist;
 394        const char *help = "For a higher level overview, try: perf report --sort comm,dso";
 395
 396        switch (use_browser) {
 397        case 1:
 398                ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
 399                                                    rep->min_percent,
 400                                                    &session->header.env);
 401                /*
 402                 * Usually "ret" is the last pressed key, and we only
 403                 * care if the key notifies us to switch data file.
 404                 */
 405                if (ret != K_SWITCH_INPUT_DATA)
 406                        ret = 0;
 407                break;
 408        case 2:
 409                ret = report__gtk_browse_hists(rep, help);
 410                break;
 411        default:
 412                ret = perf_evlist__tty_browse_hists(evlist, rep, help);
 413                break;
 414        }
 415
 416        return ret;
 417}
 418
 419static void report__collapse_hists(struct report *rep)
 420{
 421        struct ui_progress prog;
 422        struct perf_evsel *pos;
 423
 424        ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
 425
 426        evlist__for_each(rep->session->evlist, pos) {
 427                struct hists *hists = evsel__hists(pos);
 428
 429                if (pos->idx == 0)
 430                        hists->symbol_filter_str = rep->symbol_filter_str;
 431
 432                hists__collapse_resort(hists, &prog);
 433
 434                /* Non-group events are considered as leader */
 435                if (symbol_conf.event_group &&
 436                    !perf_evsel__is_group_leader(pos)) {
 437                        struct hists *leader_hists = evsel__hists(pos->leader);
 438
 439                        hists__match(leader_hists, hists);
 440                        hists__link(leader_hists, hists);
 441                }
 442        }
 443
 444        ui_progress__finish();
 445}
 446
 447static void report__output_resort(struct report *rep)
 448{
 449        struct ui_progress prog;
 450        struct perf_evsel *pos;
 451
 452        ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
 453
 454        evlist__for_each(rep->session->evlist, pos)
 455                hists__output_resort(evsel__hists(pos), &prog);
 456
 457        ui_progress__finish();
 458}
 459
 460static int __cmd_report(struct report *rep)
 461{
 462        int ret;
 463        struct perf_session *session = rep->session;
 464        struct perf_evsel *pos;
 465        struct perf_data_file *file = session->file;
 466
 467        signal(SIGINT, sig_handler);
 468
 469        if (rep->cpu_list) {
 470                ret = perf_session__cpu_bitmap(session, rep->cpu_list,
 471                                               rep->cpu_bitmap);
 472                if (ret)
 473                        return ret;
 474        }
 475
 476        if (rep->show_threads)
 477                perf_read_values_init(&rep->show_threads_values);
 478
 479        ret = report__setup_sample_type(rep);
 480        if (ret)
 481                return ret;
 482
 483        ret = perf_session__process_events(session, &rep->tool);
 484        if (ret)
 485                return ret;
 486
 487        report__warn_kptr_restrict(rep);
 488
 489        evlist__for_each(session->evlist, pos)
 490                rep->nr_entries += evsel__hists(pos)->nr_entries;
 491
 492        if (use_browser == 0) {
 493                if (verbose > 3)
 494                        perf_session__fprintf(session, stdout);
 495
 496                if (verbose > 2)
 497                        perf_session__fprintf_dsos(session, stdout);
 498
 499                if (dump_trace) {
 500                        perf_session__fprintf_nr_events(session, stdout);
 501                        perf_evlist__fprintf_nr_events(session->evlist, stdout);
 502                        return 0;
 503                }
 504        }
 505
 506        report__collapse_hists(rep);
 507
 508        if (session_done())
 509                return 0;
 510
 511        /*
 512         * recalculate number of entries after collapsing since it
 513         * might be changed during the collapse phase.
 514         */
 515        rep->nr_entries = 0;
 516        evlist__for_each(session->evlist, pos)
 517                rep->nr_entries += evsel__hists(pos)->nr_entries;
 518
 519        if (rep->nr_entries == 0) {
 520                ui__error("The %s file has no samples!\n", file->path);
 521                return 0;
 522        }
 523
 524        report__output_resort(rep);
 525
 526        return report__browse_hists(rep);
 527}
 528
 529static int
 530report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 531{
 532        struct report *rep = (struct report *)opt->value;
 533
 534        /*
 535         * --no-call-graph
 536         */
 537        if (unset) {
 538                rep->dont_use_callchains = true;
 539                return 0;
 540        }
 541
 542        return parse_callchain_report_opt(arg);
 543}
 544
 545int
 546report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
 547                                const char *arg, int unset __maybe_unused)
 548{
 549        if (arg) {
 550                int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
 551                if (err) {
 552                        char buf[BUFSIZ];
 553                        regerror(err, &ignore_callees_regex, buf, sizeof(buf));
 554                        pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
 555                        return -1;
 556                }
 557                have_ignore_callees = 1;
 558        }
 559
 560        return 0;
 561}
 562
 563static int
 564parse_branch_mode(const struct option *opt __maybe_unused,
 565                  const char *str __maybe_unused, int unset)
 566{
 567        int *branch_mode = opt->value;
 568
 569        *branch_mode = !unset;
 570        return 0;
 571}
 572
 573static int
 574parse_percent_limit(const struct option *opt, const char *str,
 575                    int unset __maybe_unused)
 576{
 577        struct report *rep = opt->value;
 578
 579        rep->min_percent = strtof(str, NULL);
 580        return 0;
 581}
 582
 583int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 584{
 585        struct perf_session *session;
 586        struct stat st;
 587        bool has_br_stack = false;
 588        int branch_mode = -1;
 589        bool branch_call_mode = false;
 590        char callchain_default_opt[] = "fractal,0.5,callee";
 591        const char * const report_usage[] = {
 592                "perf report [<options>]",
 593                NULL
 594        };
 595        struct report report = {
 596                .tool = {
 597                        .sample          = process_sample_event,
 598                        .mmap            = perf_event__process_mmap,
 599                        .mmap2           = perf_event__process_mmap2,
 600                        .comm            = perf_event__process_comm,
 601                        .exit            = perf_event__process_exit,
 602                        .fork            = perf_event__process_fork,
 603                        .lost            = perf_event__process_lost,
 604                        .read            = process_read_event,
 605                        .attr            = perf_event__process_attr,
 606                        .tracing_data    = perf_event__process_tracing_data,
 607                        .build_id        = perf_event__process_build_id,
 608                        .ordered_events  = true,
 609                        .ordering_requires_timestamps = true,
 610                },
 611                .max_stack               = PERF_MAX_STACK_DEPTH,
 612                .pretty_printing_style   = "normal",
 613        };
 614        const struct option options[] = {
 615        OPT_STRING('i', "input", &input_name, "file",
 616                    "input file name"),
 617        OPT_INCR('v', "verbose", &verbose,
 618                    "be more verbose (show symbol address, etc)"),
 619        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
 620                    "dump raw trace in ASCII"),
 621        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 622                   "file", "vmlinux pathname"),
 623        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
 624                   "file", "kallsyms pathname"),
 625        OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
 626        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
 627                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
 628        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
 629                    "Show a column with the number of samples"),
 630        OPT_BOOLEAN('T', "threads", &report.show_threads,
 631                    "Show per-thread event counters"),
 632        OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
 633                   "pretty printing style key: normal raw"),
 634        OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
 635        OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
 636        OPT_BOOLEAN(0, "stdio", &report.use_stdio,
 637                    "Use the stdio interface"),
 638        OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
 639        OPT_BOOLEAN(0, "header-only", &report.header_only,
 640                    "Show only data header."),
 641        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
 642                   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
 643                   " Please refer the man page for the complete list."),
 644        OPT_STRING('F', "fields", &field_order, "key[,keys...]",
 645                   "output field(s): overhead, period, sample plus all of sort keys"),
 646        OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
 647                    "Show sample percentage for different cpu modes"),
 648        OPT_STRING('p', "parent", &parent_pattern, "regex",
 649                   "regex filter to identify parent, see: '--sort parent'"),
 650        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
 651                    "Only display entries with parent-match"),
 652        OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
 653                     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
 654                     "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
 655        OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
 656                    "Accumulate callchains of children and show total overhead as well"),
 657        OPT_INTEGER(0, "max-stack", &report.max_stack,
 658                    "Set the maximum stack depth when parsing the callchain, "
 659                    "anything beyond the specified depth will be ignored. "
 660                    "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
 661        OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
 662                    "alias for inverted call graph"),
 663        OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
 664                   "ignore callees of these functions in call graphs",
 665                   report_parse_ignore_callees_opt),
 666        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
 667                   "only consider symbols in these dsos"),
 668        OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
 669                   "only consider symbols in these comms"),
 670        OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
 671                   "only consider these symbols"),
 672        OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
 673                   "only show symbols that (partially) match with this filter"),
 674        OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
 675                   "width[,width...]",
 676                   "don't try to adjust column width, use these fixed values"),
 677        OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
 678                   "separator for columns, no spaces will be added between "
 679                   "columns '.' is reserved."),
 680        OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
 681                    "Only display entries resolved to a symbol"),
 682        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
 683                    "Look for files with symbols relative to this directory"),
 684        OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
 685                   "list of cpus to profile"),
 686        OPT_BOOLEAN('I', "show-info", &report.show_full_info,
 687                    "Display extended information about perf.data file"),
 688        OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
 689                    "Interleave source code with assembly code (default)"),
 690        OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
 691                    "Display raw encoding of assembly instructions (default)"),
 692        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 693                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
 694        OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
 695                    "Show a column with the sum of periods"),
 696        OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
 697                    "Show event group information together"),
 698        OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
 699                    "use branch records for per branch histogram filling",
 700                    parse_branch_mode),
 701        OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
 702                    "add last branch records to call history"),
 703        OPT_STRING(0, "objdump", &objdump_path, "path",
 704                   "objdump binary to use for disassembly and annotations"),
 705        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 706                    "Disable symbol demangling"),
 707        OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
 708                    "Enable kernel symbol demangling"),
 709        OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
 710        OPT_CALLBACK(0, "percent-limit", &report, "percent",
 711                     "Don't show entries under that percent", parse_percent_limit),
 712        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
 713                     "how to display percentage of filtered entries", parse_filter_percentage),
 714        OPT_END()
 715        };
 716        struct perf_data_file file = {
 717                .mode  = PERF_DATA_MODE_READ,
 718        };
 719        int ret = hists__init();
 720
 721        if (ret < 0)
 722                return ret;
 723
 724        perf_config(report__config, &report);
 725
 726        argc = parse_options(argc, argv, options, report_usage, 0);
 727
 728        if (report.use_stdio)
 729                use_browser = 0;
 730        else if (report.use_tui)
 731                use_browser = 1;
 732        else if (report.use_gtk)
 733                use_browser = 2;
 734
 735        if (report.inverted_callchain)
 736                callchain_param.order = ORDER_CALLER;
 737
 738        if (!input_name || !strlen(input_name)) {
 739                if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
 740                        input_name = "-";
 741                else
 742                        input_name = "perf.data";
 743        }
 744
 745        file.path  = input_name;
 746        file.force = report.force;
 747
 748repeat:
 749        session = perf_session__new(&file, false, &report.tool);
 750        if (session == NULL)
 751                return -1;
 752
 753        if (report.queue_size) {
 754                ordered_events__set_alloc_size(&session->ordered_events,
 755                                               report.queue_size);
 756        }
 757
 758        report.session = session;
 759
 760        has_br_stack = perf_header__has_feat(&session->header,
 761                                             HEADER_BRANCH_STACK);
 762
 763        /*
 764         * Branch mode is a tristate:
 765         * -1 means default, so decide based on the file having branch data.
 766         * 0/1 means the user chose a mode.
 767         */
 768        if (((branch_mode == -1 && has_br_stack) || branch_mode == 1) &&
 769            branch_call_mode == -1) {
 770                sort__mode = SORT_MODE__BRANCH;
 771                symbol_conf.cumulate_callchain = false;
 772        }
 773        if (branch_call_mode) {
 774                callchain_param.key = CCKEY_ADDRESS;
 775                callchain_param.branch_callstack = 1;
 776                symbol_conf.use_callchain = true;
 777                callchain_register_param(&callchain_param);
 778                if (sort_order == NULL)
 779                        sort_order = "srcline,symbol,dso";
 780        }
 781
 782        if (report.mem_mode) {
 783                if (sort__mode == SORT_MODE__BRANCH) {
 784                        pr_err("branch and mem mode incompatible\n");
 785                        goto error;
 786                }
 787                sort__mode = SORT_MODE__MEMORY;
 788                symbol_conf.cumulate_callchain = false;
 789        }
 790
 791        if (setup_sorting() < 0) {
 792                if (sort_order)
 793                        parse_options_usage(report_usage, options, "s", 1);
 794                if (field_order)
 795                        parse_options_usage(sort_order ? NULL : report_usage,
 796                                            options, "F", 1);
 797                goto error;
 798        }
 799
 800        /* Force tty output for header output. */
 801        if (report.header || report.header_only)
 802                use_browser = 0;
 803
 804        if (strcmp(input_name, "-") != 0)
 805                setup_browser(true);
 806        else
 807                use_browser = 0;
 808
 809        if (report.header || report.header_only) {
 810                perf_session__fprintf_info(session, stdout,
 811                                           report.show_full_info);
 812                if (report.header_only)
 813                        return 0;
 814        } else if (use_browser == 0) {
 815                fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
 816                      stdout);
 817        }
 818
 819        /*
 820         * Only in the TUI browser we are doing integrated annotation,
 821         * so don't allocate extra space that won't be used in the stdio
 822         * implementation.
 823         */
 824        if (ui__has_annotation()) {
 825                symbol_conf.priv_size = sizeof(struct annotation);
 826                machines__set_symbol_filter(&session->machines,
 827                                            symbol__annotate_init);
 828                /*
 829                 * For searching by name on the "Browse map details".
 830                 * providing it only in verbose mode not to bloat too
 831                 * much struct symbol.
 832                 */
 833                if (verbose) {
 834                        /*
 835                         * XXX: Need to provide a less kludgy way to ask for
 836                         * more space per symbol, the u32 is for the index on
 837                         * the ui browser.
 838                         * See symbol__browser_index.
 839                         */
 840                        symbol_conf.priv_size += sizeof(u32);
 841                        symbol_conf.sort_by_name = true;
 842                }
 843        }
 844
 845        if (symbol__init(&session->header.env) < 0)
 846                goto error;
 847
 848        if (argc) {
 849                /*
 850                 * Special case: if there's an argument left then assume that
 851                 * it's a symbol filter:
 852                 */
 853                if (argc > 1)
 854                        usage_with_options(report_usage, options);
 855
 856                report.symbol_filter_str = argv[0];
 857        }
 858
 859        sort__setup_elide(stdout);
 860
 861        ret = __cmd_report(&report);
 862        if (ret == K_SWITCH_INPUT_DATA) {
 863                perf_session__delete(session);
 864                goto repeat;
 865        } else
 866                ret = 0;
 867
 868error:
 869        perf_session__delete(session);
 870        return ret;
 871}
 872