builtin-report.c 38.8 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4 5 6 7 8
/*
 * builtin-report.c
 *
 * Builtin report command: Analyze the perf.data input file,
 * look up and read DSOs and symbol information and display
 * a histogram of results, along various sorting keys.
 */
9
#include "builtin.h"
10

11
#include "util/util.h"
12
#include "util/config.h"
13

14
#include "util/annotate.h"
15
#include "util/color.h"
16
#include <linux/list.h>
17
#include <linux/rbtree.h>
18
#include <linux/err.h>
19
#include "util/symbol.h"
20
#include "util/callchain.h"
21
#include "util/values.h"
22

23
#include "perf.h"
24
#include "util/debug.h"
25 26
#include "util/evlist.h"
#include "util/evsel.h"
27
#include "util/header.h"
28
#include "util/session.h"
29
#include "util/tool.h"
30

31
#include <subcmd/parse-options.h>
32
#include <subcmd/exec-cmd.h>
33 34
#include "util/parse-events.h"

35
#include "util/thread.h"
36
#include "util/sort.h"
37
#include "util/hist.h"
38
#include "util/data.h"
39
#include "arch/common.h"
40
#include "util/time-utils.h"
41
#include "util/auxtrace.h"
42
#include "util/units.h"
43
#include "util/branch.h"
44

45
#include <dlfcn.h>
46
#include <errno.h>
47
#include <inttypes.h>
48
#include <regex.h>
49
#include <signal.h>
50
#include <linux/bitmap.h>
51
#include <linux/stringify.h>
52 53 54
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
55
#include <linux/mman.h>
56

57
struct report {
58
	struct perf_tool	tool;
59
	struct perf_session	*session;
60
	bool			use_tui, use_gtk, use_stdio;
61 62 63
	bool			show_full_info;
	bool			show_threads;
	bool			inverted_callchain;
64
	bool			mem_mode;
65
	bool			stats_mode;
66
	bool			tasks_mode;
67
	bool			mmaps_mode;
68 69
	bool			header;
	bool			header_only;
70
	bool			nonany_branch_mode;
71
	bool			group_set;
72
	int			max_stack;
73 74 75
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	const char		*cpu_list;
76
	const char		*symbol_filter_str;
77
	const char		*time_str;
78 79
	struct perf_time_interval *ptime_range;
	int			range_size;
80
	int			range_num;
81
	float			min_percent;
82
	u64			nr_entries;
83
	u64			queue_size;
84
	int			socket_filter;
85
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
86
	struct branch_type_stat	brtype_stat;
87
};
88

89
static int report__config(const char *var, const char *value, void *cb)
90
{
91 92
	struct report *rep = cb;

93 94 95 96
	if (!strcmp(var, "report.group")) {
		symbol_conf.event_group = perf_config_bool(var, value);
		return 0;
	}
97
	if (!strcmp(var, "report.percent-limit")) {
98 99 100 101
		double pcnt = strtof(value, NULL);

		rep->min_percent = pcnt;
		callchain_param.min_percent = pcnt;
102 103
		return 0;
	}
104 105 106 107
	if (!strcmp(var, "report.children")) {
		symbol_conf.cumulate_callchain = perf_config_bool(var, value);
		return 0;
	}
108 109 110
	if (!strcmp(var, "report.queue-size"))
		return perf_config_u64(&rep->queue_size, var, value);

111 112 113 114
	if (!strcmp(var, "report.sort_order")) {
		default_sort_order = strdup(value);
		return 0;
	}
115

116
	return 0;
117 118
}

119 120 121 122 123 124 125 126
static int hist_iter__report_callback(struct hist_entry_iter *iter,
				      struct addr_location *al, bool single,
				      void *arg)
{
	int err = 0;
	struct report *rep = arg;
	struct hist_entry *he = iter->he;
	struct perf_evsel *evsel = iter->evsel;
127
	struct perf_sample *sample = iter->sample;
128 129 130 131 132 133
	struct mem_info *mi;
	struct branch_info *bi;

	if (!ui__has_annotation())
		return 0;

134
	hist__account_cycles(sample->branch_stack, al, sample,
135 136
			     rep->nonany_branch_mode);

137 138
	if (sort__mode == SORT_MODE__BRANCH) {
		bi = he->branch_info;
139
		err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
140 141 142
		if (err)
			goto out;

143
		err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
144 145 146

	} else if (rep->mem_mode) {
		mi = he->mem_info;
147
		err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel);
148 149 150
		if (err)
			goto out;

151
		err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
152 153 154

	} else if (symbol_conf.cumulate_callchain) {
		if (single)
155
			err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
156
	} else {
157
		err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
158 159 160 161
	}

out:
	return err;
162 163
}

164 165 166 167 168 169 170 171
static int hist_iter__branch_callback(struct hist_entry_iter *iter,
				      struct addr_location *al __maybe_unused,
				      bool single __maybe_unused,
				      void *arg)
{
	struct hist_entry *he = iter->he;
	struct report *rep = arg;
	struct branch_info *bi;
172 173 174 175 176 177 178 179 180
	struct perf_sample *sample = iter->sample;
	struct perf_evsel *evsel = iter->evsel;
	int err;

	if (!ui__has_annotation())
		return 0;

	hist__account_cycles(sample->branch_stack, al, sample,
			     rep->nonany_branch_mode);
181 182

	bi = he->branch_info;
183
	err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
184 185 186
	if (err)
		goto out;

187
	err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
188

189 190 191
	branch_type_count(&rep->brtype_stat, &bi->flags,
			  bi->from.addr, bi->to.addr);

192 193
out:
	return err;
194 195
}

196 197 198
static void setup_forced_leader(struct report *report,
				struct perf_evlist *evlist)
{
199 200
	if (report->group_set)
		perf_evlist__force_leader(evlist);
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
}

static int process_feature_event(struct perf_tool *tool,
				 union perf_event *event,
				 struct perf_session *session __maybe_unused)
{
	struct report *rep = container_of(tool, struct report, tool);

	if (event->feat.feat_id < HEADER_LAST_FEATURE)
		return perf_event__process_feature(tool, event, session);

	if (event->feat.feat_id != HEADER_LAST_FEATURE) {
		pr_err("failed: wrong feature ID: %" PRIu64 "\n",
		       event->feat.feat_id);
		return -1;
	}

	/*
	 * All features are received, we can force the
	 * group if needed.
	 */
	setup_forced_leader(rep, session->evlist);
	return 0;
}

226
static int process_sample_event(struct perf_tool *tool,
227
				union perf_event *event,
228
				struct perf_sample *sample,
229
				struct perf_evsel *evsel,
230
				struct machine *machine)
231
{
232
	struct report *rep = container_of(tool, struct report, tool);
233
	struct addr_location al;
234
	struct hist_entry_iter iter = {
235 236
		.evsel 			= evsel,
		.sample 		= sample,
237
		.hide_unresolved 	= symbol_conf.hide_unresolved,
238
		.add_entry_cb 		= hist_iter__report_callback,
239
	};
240
	int ret = 0;
241

242 243
	if (perf_time__ranges_skip_sample(rep->ptime_range, rep->range_num,
					  sample->time)) {
244
		return 0;
245
	}
246

247
	if (machine__resolve(machine, &al, sample) < 0) {
248 249
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
250 251
		return -1;
	}
252

253
	if (symbol_conf.hide_unresolved && al.sym == NULL)
254
		goto out_put;
255

256
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
257
		goto out_put;
258

259 260 261 262 263 264 265
	if (sort__mode == SORT_MODE__BRANCH) {
		/*
		 * A non-synthesized event might not have a branch stack if
		 * branch stacks have been synthesized (using itrace options).
		 */
		if (!sample->branch_stack)
			goto out_put;
266 267

		iter.add_entry_cb = hist_iter__branch_callback;
268
		iter.ops = &hist_iter_branch;
269
	} else if (rep->mem_mode) {
270
		iter.ops = &hist_iter_mem;
271
	} else if (symbol_conf.cumulate_callchain) {
272
		iter.ops = &hist_iter_cumulative;
273
	} else {
274
		iter.ops = &hist_iter_normal;
275
	}
276 277 278 279

	if (al.map != NULL)
		al.map->dso->hit = 1;

280
	ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
281 282
	if (ret < 0)
		pr_debug("problem adding hist entry, skipping event\n");
283 284
out_put:
	addr_location__put(&al);
285
	return ret;
286
}
I
Ingo Molnar 已提交
287

288
static int process_read_event(struct perf_tool *tool,
289
			      union perf_event *event,
290
			      struct perf_sample *sample __maybe_unused,
291
			      struct perf_evsel *evsel,
292
			      struct machine *machine __maybe_unused)
293
{
294
	struct report *rep = container_of(tool, struct report, tool);
295

296
	if (rep->show_threads) {
297
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
298
		int err = perf_read_values_add_value(&rep->show_threads_values,
299
					   event->read.pid, event->read.tid,
300
					   evsel->idx,
301 302
					   name,
					   event->read.value);
303 304 305

		if (err)
			return err;
306 307
	}

308 309 310
	return 0;
}

311
/* For pipe mode, sample_type is not currently set */
312
static int report__setup_sample_type(struct report *rep)
313
{
314 315
	struct perf_session *session = rep->session;
	u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
316
	bool is_pipe = perf_data__is_pipe(session->data);
317

318 319 320 321 322 323
	if (session->itrace_synth_opts->callchain ||
	    (!is_pipe &&
	     perf_header__has_feat(&session->header, HEADER_AUXTRACE) &&
	     !session->itrace_synth_opts->set))
		sample_type |= PERF_SAMPLE_CALLCHAIN;

324 325 326
	if (session->itrace_synth_opts->last_branch)
		sample_type |= PERF_SAMPLE_BRANCH_STACK;

327
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
328
		if (perf_hpp_list.parent) {
329
			ui__error("Selected --sort parent, but no "
330 331
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
332
			return -EINVAL;
333
		}
334 335 336 337 338
		if (symbol_conf.use_callchain &&
			!symbol_conf.show_branchflag_count) {
			ui__error("Selected -g or --branch-history.\n"
				  "But no callchain or branch data.\n"
				  "Did you call 'perf record' without -g or -b?\n");
339
			return -1;
340
		}
341
	} else if (!callchain_param.enabled &&
342
		   callchain_param.mode != CHAIN_NONE &&
343
		   !symbol_conf.use_callchain) {
344
			symbol_conf.use_callchain = true;
345
			if (callchain_register_param(&callchain_param) < 0) {
346
				ui__error("Can't register callchain params.\n");
347
				return -EINVAL;
348
			}
349 350
	}

351 352 353 354 355 356 357 358
	if (symbol_conf.cumulate_callchain) {
		/* Silently ignore if callchain is missing */
		if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
			symbol_conf.cumulate_callchain = false;
			perf_hpp__cancel_cumulate();
		}
	}

359
	if (sort__mode == SORT_MODE__BRANCH) {
360
		if (!is_pipe &&
361
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
362 363
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
364 365 366 367
			return -1;
		}
	}

368 369
	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
		if ((sample_type & PERF_SAMPLE_REGS_USER) &&
370
		    (sample_type & PERF_SAMPLE_STACK_USER)) {
371
			callchain_param.record_mode = CALLCHAIN_DWARF;
372 373
			dwarf_callchain_users = true;
		} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
374
			callchain_param.record_mode = CALLCHAIN_LBR;
375 376 377
		else
			callchain_param.record_mode = CALLCHAIN_FP;
	}
378 379 380 381 382 383

	/* ??? handle more cases than just ANY? */
	if (!(perf_evlist__combined_branch_type(session->evlist) &
				PERF_SAMPLE_BRANCH_ANY))
		rep->nonany_branch_mode = true;

384 385
	return 0;
}
386

387
static void sig_handler(int sig __maybe_unused)
388 389 390 391
{
	session_done = 1;
}

392
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
393 394 395 396
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
397 398 399
	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
	u64 nr_events = hists->stats.total_period;
	struct perf_evsel *evsel = hists_to_evsel(hists);
400 401
	char buf[512];
	size_t size = sizeof(buf);
402
	int socked_id = hists->socket_filter;
403

404 405 406
	if (quiet)
		return 0;

407 408 409 410 411
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

412
	if (perf_evsel__is_group_event(evsel)) {
413 414 415 416 417 418
		struct perf_evsel *pos;

		perf_evsel__group_desc(evsel, buf, size);
		evname = buf;

		for_each_group_member(pos, evsel) {
419 420
			const struct hists *pos_hists = evsel__hists(pos);

421
			if (symbol_conf.filter_relative) {
422 423
				nr_samples += pos_hists->stats.nr_non_filtered_samples;
				nr_events += pos_hists->stats.total_non_filtered_period;
424
			} else {
425 426
				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos_hists->stats.total_period;
427
			}
428 429
		}
	}
430

431 432
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
433 434 435 436
	if (evname != NULL) {
		ret += fprintf(fp, " of event%s '%s'",
			       evsel->nr_members > 1 ? "s" : "", evname);
	}
437

438 439 440
	if (rep->time_str)
		ret += fprintf(fp, " (time slices: %s)", rep->time_str);

441 442 443 444 445
	if (symbol_conf.show_ref_callgraph &&
	    strstr(evname, "call-graph=no")) {
		ret += fprintf(fp, ", show reference callgraph");
	}

446 447
	if (rep->mem_mode) {
		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
448
		ret += fprintf(fp, "\n# Sort order   : %s", sort_order ? : default_mem_sort_order);
449 450
	} else
		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
451

452 453
	if (socked_id > -1)
		ret += fprintf(fp, "\n# Processor Socket: %d", socked_id);
454

455 456 457
	return ret + fprintf(fp, "\n#\n");
}

458
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
459
					 struct report *rep,
460
					 const char *help)
461
{
462
	struct perf_evsel *pos;
463

464 465 466 467 468
	if (!quiet) {
		fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n",
			evlist->stats.total_lost_samples);
	}

469
	evlist__for_each_entry(evlist, pos) {
470
		struct hists *hists = evsel__hists(pos);
471
		const char *evname = perf_evsel__name(pos);
472

473 474 475 476
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

477
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
478
		hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout,
479 480
			       symbol_conf.use_callchain ||
			       symbol_conf.show_branchflag_count);
481 482 483
		fprintf(stdout, "\n\n");
	}

484
	if (!quiet)
485 486
		fprintf(stdout, "#\n# (%s)\n#\n", help);

487 488 489 490 491
	if (rep->show_threads) {
		bool style = !strcmp(rep->pretty_printing_style, "raw");
		perf_read_values_display(stdout, &rep->show_threads_values,
					 style);
		perf_read_values_destroy(&rep->show_threads_values);
492 493
	}

494 495 496
	if (sort__mode == SORT_MODE__BRANCH)
		branch_type_stat_display(stdout, &rep->brtype_stat);

497 498 499
	return 0;
}

500 501
static void report__warn_kptr_restrict(const struct report *rep)
{
502
	struct map *kernel_map = machine__kernel_map(&rep->session->machines.host);
503
	struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
504

505 506 507
	if (perf_evlist__exclude_kernel(rep->session->evlist))
		return;

508 509 510 511 512 513 514 515
	if (kernel_map == NULL ||
	    (kernel_map->dso->hit &&
	     (kernel_kmap->ref_reloc_sym == NULL ||
	      kernel_kmap->ref_reloc_sym->addr == 0))) {
		const char *desc =
		    "As no suitable kallsyms nor vmlinux was found, kernel samples\n"
		    "can't be resolved.";

516 517 518
		if (kernel_map && map__has_symbols(kernel_map)) {
			desc = "If some relocation was applied (e.g. "
			       "kexec) symbols may be misresolved.";
519 520 521 522 523 524 525 526 527 528
		}

		ui__warning(
"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
"Samples in kernel modules can't be resolved as well.\n\n",
		desc);
	}
}

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
static int report__gtk_browse_hists(struct report *rep, const char *help)
{
	int (*hist_browser)(struct perf_evlist *evlist, const char *help,
			    struct hist_browser_timer *timer, float min_pcnt);

	hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");

	if (hist_browser == NULL) {
		ui__error("GTK browser not found!\n");
		return -1;
	}

	return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
}

static int report__browse_hists(struct report *rep)
{
	int ret;
	struct perf_session *session = rep->session;
	struct perf_evlist *evlist = session->evlist;
549 550 551 552 553 554 555 556
	const char *help = perf_tip(system_path(TIPDIR));

	if (help == NULL) {
		/* fallback for people who don't install perf ;-) */
		help = perf_tip(DOCDIR);
		if (help == NULL)
			help = "Cannot load tips.txt file, please install perf!";
	}
557 558 559 560 561

	switch (use_browser) {
	case 1:
		ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
						    rep->min_percent,
562 563
						    &session->header.env,
						    true);
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
		/*
		 * Usually "ret" is the last pressed key, and we only
		 * care if the key notifies us to switch data file.
		 */
		if (ret != K_SWITCH_INPUT_DATA)
			ret = 0;
		break;
	case 2:
		ret = report__gtk_browse_hists(rep, help);
		break;
	default:
		ret = perf_evlist__tty_browse_hists(evlist, rep, help);
		break;
	}

	return ret;
}

582
static int report__collapse_hists(struct report *rep)
583 584 585
{
	struct ui_progress prog;
	struct perf_evsel *pos;
586
	int ret = 0;
587

588
	ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
589

590
	evlist__for_each_entry(rep->session->evlist, pos) {
591
		struct hists *hists = evsel__hists(pos);
592 593 594 595

		if (pos->idx == 0)
			hists->symbol_filter_str = rep->symbol_filter_str;

596 597
		hists->socket_filter = rep->socket_filter;

598 599 600
		ret = hists__collapse_resort(hists, &prog);
		if (ret < 0)
			break;
601 602 603 604

		/* Non-group events are considered as leader */
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos)) {
605
			struct hists *leader_hists = evsel__hists(pos->leader);
606 607 608 609 610 611 612

			hists__match(leader_hists, hists);
			hists__link(leader_hists, hists);
		}
	}

	ui_progress__finish();
613
	return ret;
614 615
}

616 617 618 619 620 621 622
static void report__output_resort(struct report *rep)
{
	struct ui_progress prog;
	struct perf_evsel *pos;

	ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");

623
	evlist__for_each_entry(rep->session->evlist, pos)
624
		perf_evsel__output_resort(pos, &prog);
625 626 627 628

	ui_progress__finish();
}

629 630 631 632 633 634 635 636 637 638 639 640 641 642
static void stats_setup(struct report *rep)
{
	memset(&rep->tool, 0, sizeof(rep->tool));
	rep->tool.no_warn = true;
}

static int stats_print(struct report *rep)
{
	struct perf_session *session = rep->session;

	perf_session__fprintf_nr_events(session, stdout);
	return 0;
}

643 644 645
static void tasks_setup(struct report *rep)
{
	memset(&rep->tool, 0, sizeof(rep->tool));
646
	rep->tool.ordered_events = true;
647 648 649 650
	if (rep->mmaps_mode) {
		rep->tool.mmap = perf_event__process_mmap;
		rep->tool.mmap2 = perf_event__process_mmap2;
	}
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
	rep->tool.comm = perf_event__process_comm;
	rep->tool.exit = perf_event__process_exit;
	rep->tool.fork = perf_event__process_fork;
	rep->tool.no_warn = true;
}

struct task {
	struct thread		*thread;
	struct list_head	 list;
	struct list_head	 children;
};

static struct task *tasks_list(struct task *task, struct machine *machine)
{
	struct thread *parent_thread, *thread = task->thread;
	struct task   *parent_task;

	/* Already listed. */
	if (!list_empty(&task->list))
		return NULL;

	/* Last one in the chain. */
	if (thread->ppid == -1)
		return task;

	parent_thread = machine__find_thread(machine, -1, thread->ppid);
	if (!parent_thread)
		return ERR_PTR(-ENOENT);

	parent_task = thread__priv(parent_thread);
	list_add_tail(&task->list, &parent_task->children);
	return tasks_list(parent_task, machine);
}

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
{
	size_t printed = 0;
	struct rb_node *nd;

	for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
		struct map *map = rb_entry(nd, struct map, rb_node);

		printed += fprintf(fp, "%*s  %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",
				   indent, "", map->start, map->end,
				   map->prot & PROT_READ ? 'r' : '-',
				   map->prot & PROT_WRITE ? 'w' : '-',
				   map->prot & PROT_EXEC ? 'x' : '-',
				   map->flags & MAP_SHARED ? 's' : 'p',
				   map->pgoff,
				   map->ino, map->dso->name);
	}

	return printed;
}

static int map_groups__fprintf_task(struct map_groups *mg, int indent, FILE *fp)
{
708
	return maps__fprintf_task(&mg->maps, indent, fp);
709 710
}

711 712 713 714
static void task__print_level(struct task *task, FILE *fp, int level)
{
	struct thread *thread = task->thread;
	struct task *child;
715 716 717 718 719
	int comm_indent = fprintf(fp, "  %8d %8d %8d |%*s",
				  thread->pid_, thread->tid, thread->ppid,
				  level, "");

	fprintf(fp, "%s\n", thread__comm_str(thread));
720

721
	map_groups__fprintf_task(thread->mg, comm_indent, fp);
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794

	if (!list_empty(&task->children)) {
		list_for_each_entry(child, &task->children, list)
			task__print_level(child, fp, level + 1);
	}
}

static int tasks_print(struct report *rep, FILE *fp)
{
	struct perf_session *session = rep->session;
	struct machine      *machine = &session->machines.host;
	struct task *tasks, *task;
	unsigned int nr = 0, itask = 0, i;
	struct rb_node *nd;
	LIST_HEAD(list);

	/*
	 * No locking needed while accessing machine->threads,
	 * because --tasks is single threaded command.
	 */

	/* Count all the threads. */
	for (i = 0; i < THREADS__TABLE_SIZE; i++)
		nr += machine->threads[i].nr;

	tasks = malloc(sizeof(*tasks) * nr);
	if (!tasks)
		return -ENOMEM;

	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
		struct threads *threads = &machine->threads[i];

		for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
			task = tasks + itask++;

			task->thread = rb_entry(nd, struct thread, rb_node);
			INIT_LIST_HEAD(&task->children);
			INIT_LIST_HEAD(&task->list);
			thread__set_priv(task->thread, task);
		}
	}

	/*
	 * Iterate every task down to the unprocessed parent
	 * and link all in task children list. Task with no
	 * parent is added into 'list'.
	 */
	for (itask = 0; itask < nr; itask++) {
		task = tasks + itask;

		if (!list_empty(&task->list))
			continue;

		task = tasks_list(task, machine);
		if (IS_ERR(task)) {
			pr_err("Error: failed to process tasks\n");
			free(tasks);
			return PTR_ERR(task);
		}

		if (task)
			list_add_tail(&task->list, &list);
	}

	fprintf(fp, "# %8s %8s %8s  %s\n", "pid", "tid", "ppid", "comm");

	list_for_each_entry(task, &list, list)
		task__print_level(task, fp, 0);

	free(tasks);
	return 0;
}

795
static int __cmd_report(struct report *rep)
796
{
797
	int ret;
798
	struct perf_session *session = rep->session;
799
	struct perf_evsel *pos;
800
	struct perf_data *data = session->data;
801

802 803
	signal(SIGINT, sig_handler);

804 805 806
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
807 808
		if (ret) {
			ui__error("failed to set cpu bitmap\n");
809
			return ret;
810
		}
811
		session->itrace_synth_opts->cpu_bitmap = rep->cpu_bitmap;
812 813
	}

814 815 816 817 818
	if (rep->show_threads) {
		ret = perf_read_values_init(&rep->show_threads_values);
		if (ret)
			return ret;
	}
819

820
	ret = report__setup_sample_type(rep);
821 822
	if (ret) {
		/* report__setup_sample_type() already showed error message */
823
		return ret;
824
	}
825

826 827 828
	if (rep->stats_mode)
		stats_setup(rep);

829 830 831
	if (rep->tasks_mode)
		tasks_setup(rep);

832
	ret = perf_session__process_events(session);
833 834
	if (ret) {
		ui__error("failed to process sample\n");
835
		return ret;
836
	}
837

838 839 840
	if (rep->stats_mode)
		return stats_print(rep);

841 842 843
	if (rep->tasks_mode)
		return tasks_print(rep, stdout);

844
	report__warn_kptr_restrict(rep);
845

846
	evlist__for_each_entry(session->evlist, pos)
847 848
		rep->nr_entries += evsel__hists(pos)->nr_entries;

849 850 851
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
852

853 854
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
855

856 857
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
858
			perf_evlist__fprintf_nr_events(session->evlist, stdout);
859 860
			return 0;
		}
861 862
	}

863 864 865 866 867
	ret = report__collapse_hists(rep);
	if (ret) {
		ui__error("failed to process hist entry\n");
		return ret;
	}
868

869 870 871
	if (session_done())
		return 0;

872 873 874 875 876
	/*
	 * recalculate number of entries after collapsing since it
	 * might be changed during the collapse phase.
	 */
	rep->nr_entries = 0;
877
	evlist__for_each_entry(session->evlist, pos)
878 879
		rep->nr_entries += evsel__hists(pos)->nr_entries;

880
	if (rep->nr_entries == 0) {
J
Jiri Olsa 已提交
881
		ui__error("The %s file has no samples!\n", data->file.path);
882
		return 0;
883 884
	}

885
	report__output_resort(rep);
886

887
	return report__browse_hists(rep);
888 889
}

890
static int
891
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
892
{
893
	struct callchain_param *callchain = opt->value;
894

895
	callchain->enabled = !unset;
896 897 898 899
	/*
	 * --no-call-graph
	 */
	if (unset) {
900 901
		symbol_conf.use_callchain = false;
		callchain->mode = CHAIN_NONE;
902 903 904
		return 0;
	}

905
	return parse_callchain_report_opt(arg);
906 907
}

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
int
report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
				const char *arg, int unset __maybe_unused)
{
	if (arg) {
		int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
		if (err) {
			char buf[BUFSIZ];
			regerror(err, &ignore_callees_regex, buf, sizeof(buf));
			pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
			return -1;
		}
		have_ignore_callees = 1;
	}

	return 0;
}

926
static int
927
parse_branch_mode(const struct option *opt,
928
		  const char *str __maybe_unused, int unset)
929
{
930 931 932
	int *branch_mode = opt->value;

	*branch_mode = !unset;
933 934 935
	return 0;
}

936 937 938 939
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
940
	struct report *rep = opt->value;
941
	double pcnt = strtof(str, NULL);
942

943 944
	rep->min_percent = pcnt;
	callchain_param.min_percent = pcnt;
945 946 947
	return 0;
}

948
#define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function,percent"
949 950 951 952

const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
				     CALLCHAIN_REPORT_HELP
				     "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
953

954
int cmd_report(int argc, const char **argv)
955
{
956
	struct perf_session *session;
957
	struct itrace_synth_opts itrace_synth_opts = { .set = 0, };
958
	struct stat st;
959
	bool has_br_stack = false;
960
	int branch_mode = -1;
961
	bool branch_call_mode = false;
962
	char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
963
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
964
		"perf report [<options>]",
965 966
		NULL
	};
967
	struct report report = {
968
		.tool = {
969 970
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
971
			.mmap2		 = perf_event__process_mmap2,
972
			.comm		 = perf_event__process_comm,
973
			.namespaces	 = perf_event__process_namespaces,
974 975
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
976 977 978 979 980
			.lost		 = perf_event__process_lost,
			.read		 = process_read_event,
			.attr		 = perf_event__process_attr,
			.tracing_data	 = perf_event__process_tracing_data,
			.build_id	 = perf_event__process_build_id,
981 982 983
			.id_index	 = perf_event__process_id_index,
			.auxtrace_info	 = perf_event__process_auxtrace_info,
			.auxtrace	 = perf_event__process_auxtrace,
984
			.feature	 = process_feature_event,
985
			.ordered_events	 = true,
986 987
			.ordering_requires_timestamps = true,
		},
988
		.max_stack		 = PERF_MAX_STACK_DEPTH,
989
		.pretty_printing_style	 = "normal",
990
		.socket_filter		 = -1,
991 992
	};
	const struct option options[] = {
993
	OPT_STRING('i', "input", &input_name, "file",
994
		    "input file name"),
995
	OPT_INCR('v', "verbose", &verbose,
996
		    "be more verbose (show symbol address, etc)"),
997
	OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any message"),
998 999
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
1000
	OPT_BOOLEAN(0, "stats", &report.stats_mode, "Display event stats"),
1001
	OPT_BOOLEAN(0, "tasks", &report.tasks_mode, "Display recorded tasks"),
1002
	OPT_BOOLEAN(0, "mmaps", &report.mmaps_mode, "Display recorded tasks memory maps"),
1003 1004
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
1005 1006
	OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
                    "don't load vmlinux even if found"),
1007 1008
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
1009
	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
1010
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1011
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
1012
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1013
		    "Show a column with the number of samples"),
1014
	OPT_BOOLEAN('T', "threads", &report.show_threads,
1015
		    "Show per-thread event counters"),
1016
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
1017
		   "pretty printing style key: normal raw"),
1018
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
1019
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
1020 1021
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
1022 1023 1024
	OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
	OPT_BOOLEAN(0, "header-only", &report.header_only,
		    "Show only data header."),
1025
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1026 1027
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
		   " Please refer the man page for the complete list."),
1028 1029
	OPT_STRING('F', "fields", &field_order, "key[,keys...]",
		   "output field(s): overhead, period, sample plus all of sort keys"),
1030
	OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
1031
		    "Show sample percentage for different cpu modes"),
1032 1033
	OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes", PARSE_OPT_HIDDEN),
1034 1035
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
1036
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
1037
		    "Only display entries with parent-match"),
1038
	OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
1039
			     "print_type,threshold[,print_limit],order,sort_key[,branch],value",
1040 1041
			     report_callchain_help, &report_parse_callchain_opt,
			     callchain_default_opt),
1042 1043
	OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
		    "Accumulate callchains of children and show total overhead as well"),
1044 1045 1046
	OPT_INTEGER(0, "max-stack", &report.max_stack,
		    "Set the maximum stack depth when parsing the callchain, "
		    "anything beyond the specified depth will be ignored. "
1047
		    "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
1048 1049
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
1050 1051 1052
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
1053
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1054
		   "only consider symbols in these dsos"),
1055
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1056
		   "only consider symbols in these comms"),
1057 1058 1059 1060
	OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
		   "only consider symbols in these pids"),
	OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
		   "only consider symbols in these tids"),
1061
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1062
		   "only consider these symbols"),
1063 1064
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
1065
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1066 1067
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
1068
	OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
1069 1070
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
1071
	OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
1072
		    "Only display entries resolved to a symbol"),
1073 1074 1075
	OPT_CALLBACK(0, "symfs", NULL, "directory",
		     "Look for files with symbols relative to this directory",
		     symbol__config_symfs),
1076
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
1077 1078
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
1079
		    "Display extended information about perf.data file"),
1080 1081 1082 1083
	OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
		    "Interleave source code with assembly code (default)"),
	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
		    "Display raw encoding of assembly instructions (default)"),
1084 1085
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
1086 1087
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
1088
	OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set,
N
Namhyung Kim 已提交
1089
		    "Show event group information together"),
1090
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
1091 1092 1093 1094
		    "use branch records for per branch histogram filling",
		    parse_branch_mode),
	OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
		    "add last branch records to call history"),
1095 1096
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
1097 1098
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
1099 1100
	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
		    "Enable kernel symbol demangling"),
1101
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
1102 1103
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
1104
	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
N
Namhyung Kim 已提交
1105
		     "how to display percentage of filtered entries", parse_filter_percentage),
1106 1107 1108
	OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
			    "Instruction Tracing options",
			    itrace_parse_synth_opts),
1109 1110
	OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
			"Show full source file name path for source lines"),
1111 1112
	OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
		    "Show callgraph from reference event"),
1113 1114
	OPT_INTEGER(0, "socket-filter", &report.socket_filter,
		    "only show processor socket that match with this filter"),
1115 1116
	OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
		    "Show raw trace event output (do not use print fmt or plugins)"),
1117 1118
	OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
		    "Show entries in a hierarchy"),
1119 1120 1121
	OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",
			     "'always' (default), 'never' or 'auto' only applicable to --stdio mode",
			     stdio__config_color, "always"),
1122 1123
	OPT_STRING(0, "time", &report.time_str, "str",
		   "Time span of interest (start,stop)"),
J
Jin Yao 已提交
1124 1125
	OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
		    "Show inline function"),
1126
	OPT_END()
1127
	};
1128
	struct perf_data data = {
1129 1130
		.mode  = PERF_DATA_MODE_READ,
	};
1131 1132 1133 1134
	int ret = hists__init();

	if (ret < 0)
		return ret;
1135

1136 1137 1138
	ret = perf_config(report__config, &report);
	if (ret)
		return ret;
1139

1140
	argc = parse_options(argc, argv, options, report_usage, 0);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
	if (argc) {
		/*
		 * Special case: if there's an argument left then assume that
		 * it's a symbol filter:
		 */
		if (argc > 1)
			usage_with_options(report_usage, options);

		report.symbol_filter_str = argv[0];
	}
1151

1152 1153 1154
	if (report.mmaps_mode)
		report.tasks_mode = true;

1155 1156 1157
	if (quiet)
		perf_quiet_option();

1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
	if (symbol_conf.vmlinux_name &&
	    access(symbol_conf.vmlinux_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
		return -EINVAL;
	}
	if (symbol_conf.kallsyms_name &&
	    access(symbol_conf.kallsyms_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
		return -EINVAL;
	}

1169
	if (report.inverted_callchain)
1170
		callchain_param.order = ORDER_CALLER;
1171 1172
	if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
		callchain_param.order = ORDER_CALLER;
1173

1174 1175 1176 1177
	if (itrace_synth_opts.callchain &&
	    (int)itrace_synth_opts.callchain_sz > report.max_stack)
		report.max_stack = itrace_synth_opts.callchain_sz;

1178
	if (!input_name || !strlen(input_name)) {
1179
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
1180
			input_name = "-";
1181
		else
1182
			input_name = "perf.data";
1183
	}
1184

J
Jiri Olsa 已提交
1185 1186
	data.file.path = input_name;
	data.force     = symbol_conf.force;
1187

1188
repeat:
1189
	session = perf_session__new(&data, false, &report.tool);
1190
	if (session == NULL)
1191
		return -1;
1192

1193 1194 1195 1196 1197
	if (report.queue_size) {
		ordered_events__set_alloc_size(&session->ordered_events,
					       report.queue_size);
	}

1198 1199
	session->itrace_synth_opts = &itrace_synth_opts;

1200 1201 1202 1203
	report.session = session;

	has_br_stack = perf_header__has_feat(&session->header,
					     HEADER_BRANCH_STACK);
1204

1205
	setup_forced_leader(&report, session->evlist);
1206

1207 1208 1209
	if (itrace_synth_opts.last_branch)
		has_br_stack = true;

1210 1211 1212
	if (has_br_stack && branch_call_mode)
		symbol_conf.show_branchflag_count = true;

1213 1214
	memset(&report.brtype_stat, 0, sizeof(struct branch_type_stat));

1215 1216 1217 1218 1219 1220
	/*
	 * Branch mode is a tristate:
	 * -1 means default, so decide based on the file having branch data.
	 * 0/1 means the user chose a mode.
	 */
	if (((branch_mode == -1 && has_br_stack) || branch_mode == 1) &&
1221
	    !branch_call_mode) {
1222
		sort__mode = SORT_MODE__BRANCH;
1223 1224
		symbol_conf.cumulate_callchain = false;
	}
1225
	if (branch_call_mode) {
1226
		callchain_param.key = CCKEY_ADDRESS;
1227 1228 1229 1230 1231 1232
		callchain_param.branch_callstack = 1;
		symbol_conf.use_callchain = true;
		callchain_register_param(&callchain_param);
		if (sort_order == NULL)
			sort_order = "srcline,symbol,dso";
	}
1233

1234
	if (report.mem_mode) {
1235
		if (sort__mode == SORT_MODE__BRANCH) {
1236
			pr_err("branch and mem mode incompatible\n");
1237 1238
			goto error;
		}
1239
		sort__mode = SORT_MODE__MEMORY;
1240
		symbol_conf.cumulate_callchain = false;
1241
	}
1242

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
	if (symbol_conf.report_hierarchy) {
		/* disable incompatible options */
		symbol_conf.cumulate_callchain = false;

		if (field_order) {
			pr_err("Error: --hierarchy and --fields options cannot be used together\n");
			parse_options_usage(report_usage, options, "F", 1);
			parse_options_usage(NULL, options, "hierarchy", 0);
			goto error;
		}

1254
		perf_hpp_list.need_collapse = true;
1255 1256
	}

1257 1258 1259 1260 1261 1262 1263
	if (report.use_stdio)
		use_browser = 0;
	else if (report.use_tui)
		use_browser = 1;
	else if (report.use_gtk)
		use_browser = 2;

1264 1265
	/* Force tty output for header output and per-thread stat. */
	if (report.header || report.header_only || report.show_threads)
1266
		use_browser = 0;
1267 1268 1269 1270
	if (report.header || report.header_only)
		report.tool.show_feat_hdr = SHOW_FEAT_HEADER;
	if (report.show_full_info)
		report.tool.show_feat_hdr = SHOW_FEAT_HEADER_FULL_INFO;
1271
	if (report.stats_mode || report.tasks_mode)
1272
		use_browser = 0;
1273
	if (report.stats_mode && report.tasks_mode) {
1274
		pr_err("Error: --tasks and --mmaps can't be used together with --stats\n");
1275 1276
		goto error;
	}
1277

1278 1279
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
1280
	else
1281 1282
		use_browser = 0;

1283 1284 1285 1286 1287 1288 1289 1290 1291
	if (setup_sorting(session->evlist) < 0) {
		if (sort_order)
			parse_options_usage(report_usage, options, "s", 1);
		if (field_order)
			parse_options_usage(sort_order ? NULL : report_usage,
					    options, "F", 1);
		goto error;
	}

1292
	if ((report.header || report.header_only) && !quiet) {
1293 1294
		perf_session__fprintf_info(session, stdout,
					   report.show_full_info);
1295 1296 1297 1298
		if (report.header_only) {
			ret = 0;
			goto error;
		}
1299 1300
	} else if (use_browser == 0 && !quiet &&
		   !report.stats_mode && !report.tasks_mode) {
1301 1302 1303 1304
		fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
		      stdout);
	}

1305
	/*
1306
	 * Only in the TUI browser we are doing integrated annotation,
1307 1308 1309
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
1310
	if (ui__has_annotation()) {
1311 1312 1313
		ret = symbol__annotation_init();
		if (ret < 0)
			goto error;
1314 1315 1316 1317 1318
		/*
 		 * For searching by name on the "Browse map details".
 		 * providing it only in verbose mode not to bloat too
 		 * much struct symbol.
 		 */
1319
		if (verbose > 0) {
1320 1321 1322 1323 1324 1325 1326 1327 1328
			/*
			 * XXX: Need to provide a less kludgy way to ask for
			 * more space per symbol, the u32 is for the index on
			 * the ui browser.
			 * See symbol__browser_index.
			 */
			symbol_conf.priv_size += sizeof(u32);
			symbol_conf.sort_by_name = true;
		}
1329
		annotation_config__init();
1330
	}
1331

1332
	if (symbol__init(&session->header.env) < 0)
1333
		goto error;
1334

1335 1336 1337 1338 1339 1340 1341
	report.ptime_range = perf_time__range_alloc(report.time_str,
						    &report.range_size);
	if (!report.ptime_range) {
		ret = -ENOMEM;
		goto error;
	}

1342 1343 1344
	if (perf_time__parse_str(report.ptime_range, report.time_str) != 0) {
		if (session->evlist->first_sample_time == 0 &&
		    session->evlist->last_sample_time == 0) {
1345 1346 1347
			pr_err("HINT: no first/last sample time found in perf data.\n"
			       "Please use latest perf binary to execute 'perf record'\n"
			       "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
1348 1349
			ret = -EINVAL;
			goto error;
1350 1351 1352
		}

		report.range_num = perf_time__percent_parse_str(
1353
					report.ptime_range, report.range_size,
1354 1355 1356 1357 1358 1359
					report.time_str,
					session->evlist->first_sample_time,
					session->evlist->last_sample_time);

		if (report.range_num < 0) {
			pr_err("Invalid time string\n");
1360 1361
			ret = -EINVAL;
			goto error;
1362 1363 1364
		}
	} else {
		report.range_num = 1;
1365 1366
	}

1367 1368 1369 1370 1371 1372 1373 1374 1375
	if (session->tevent.pevent &&
	    pevent_set_function_resolver(session->tevent.pevent,
					 machine__resolve_kernel_addr,
					 &session->machines.host) < 0) {
		pr_err("%s: failed to set libtraceevent function resolver\n",
		       __func__);
		return -1;
	}

1376
	sort__setup_elide(stdout);
1377

1378
	ret = __cmd_report(&report);
1379 1380 1381 1382 1383 1384
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

1385
error:
1386 1387
	zfree(&report.ptime_range);

1388 1389
	perf_session__delete(session);
	return ret;
1390
}