builtin-report.c 37.7 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
	int			max_stack;
72 73 74
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	const char		*cpu_list;
75
	const char		*symbol_filter_str;
76
	const char		*time_str;
77 78
	struct perf_time_interval *ptime_range;
	int			range_size;
79
	int			range_num;
80
	float			min_percent;
81
	u64			nr_entries;
82
	u64			queue_size;
83
	int			socket_filter;
84
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
85
	struct branch_type_stat	brtype_stat;
86
};
87

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

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

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

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

115
	return 0;
116 117
}

118 119 120 121 122 123 124 125
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;
126
	struct perf_sample *sample = iter->sample;
127 128 129 130 131 132
	struct mem_info *mi;
	struct branch_info *bi;

	if (!ui__has_annotation())
		return 0;

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

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

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

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

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

	} else if (symbol_conf.cumulate_callchain) {
		if (single)
154
			err = hist_entry__inc_addr_samples(he, sample, evsel->idx,
155 156
							   al->addr);
	} else {
157
		err = hist_entry__inc_addr_samples(he, sample, evsel->idx, 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 184 185 186 187 188
	err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx);
	if (err)
		goto out;

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

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
static int process_sample_event(struct perf_tool *tool,
197
				union perf_event *event,
198
				struct perf_sample *sample,
199
				struct perf_evsel *evsel,
200
				struct machine *machine)
201
{
202
	struct report *rep = container_of(tool, struct report, tool);
203
	struct addr_location al;
204
	struct hist_entry_iter iter = {
205 206
		.evsel 			= evsel,
		.sample 		= sample,
207
		.hide_unresolved 	= symbol_conf.hide_unresolved,
208
		.add_entry_cb 		= hist_iter__report_callback,
209
	};
210
	int ret = 0;
211

212 213
	if (perf_time__ranges_skip_sample(rep->ptime_range, rep->range_num,
					  sample->time)) {
214
		return 0;
215
	}
216

217
	if (machine__resolve(machine, &al, sample) < 0) {
218 219
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
220 221
		return -1;
	}
222

223
	if (symbol_conf.hide_unresolved && al.sym == NULL)
224
		goto out_put;
225

226
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
227
		goto out_put;
228

229 230 231 232 233 234 235
	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;
236 237

		iter.add_entry_cb = hist_iter__branch_callback;
238
		iter.ops = &hist_iter_branch;
239
	} else if (rep->mem_mode) {
240
		iter.ops = &hist_iter_mem;
241
	} else if (symbol_conf.cumulate_callchain) {
242
		iter.ops = &hist_iter_cumulative;
243
	} else {
244
		iter.ops = &hist_iter_normal;
245
	}
246 247 248 249

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

250
	ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
251 252
	if (ret < 0)
		pr_debug("problem adding hist entry, skipping event\n");
253 254
out_put:
	addr_location__put(&al);
255
	return ret;
256
}
I
Ingo Molnar 已提交
257

258
static int process_read_event(struct perf_tool *tool,
259
			      union perf_event *event,
260
			      struct perf_sample *sample __maybe_unused,
261
			      struct perf_evsel *evsel,
262
			      struct machine *machine __maybe_unused)
263
{
264
	struct report *rep = container_of(tool, struct report, tool);
265

266
	if (rep->show_threads) {
267
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
268
		int err = perf_read_values_add_value(&rep->show_threads_values,
269
					   event->read.pid, event->read.tid,
270
					   evsel->idx,
271 272
					   name,
					   event->read.value);
273 274 275

		if (err)
			return err;
276 277
	}

278 279 280
	return 0;
}

281
/* For pipe mode, sample_type is not currently set */
282
static int report__setup_sample_type(struct report *rep)
283
{
284 285
	struct perf_session *session = rep->session;
	u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
286
	bool is_pipe = perf_data__is_pipe(session->data);
287

288 289 290 291 292 293
	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;

294 295 296
	if (session->itrace_synth_opts->last_branch)
		sample_type |= PERF_SAMPLE_BRANCH_STACK;

297
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
298
		if (perf_hpp_list.parent) {
299
			ui__error("Selected --sort parent, but no "
300 301
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
302
			return -EINVAL;
303
		}
304 305 306 307 308
		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");
309
			return -1;
310
		}
311
	} else if (!callchain_param.enabled &&
312
		   callchain_param.mode != CHAIN_NONE &&
313
		   !symbol_conf.use_callchain) {
314
			symbol_conf.use_callchain = true;
315
			if (callchain_register_param(&callchain_param) < 0) {
316
				ui__error("Can't register callchain params.\n");
317
				return -EINVAL;
318
			}
319 320
	}

321 322 323 324 325 326 327 328
	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();
		}
	}

329
	if (sort__mode == SORT_MODE__BRANCH) {
330
		if (!is_pipe &&
331
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
332 333
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
334 335 336 337
			return -1;
		}
	}

338 339
	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
		if ((sample_type & PERF_SAMPLE_REGS_USER) &&
340
		    (sample_type & PERF_SAMPLE_STACK_USER)) {
341
			callchain_param.record_mode = CALLCHAIN_DWARF;
342 343
			dwarf_callchain_users = true;
		} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
344
			callchain_param.record_mode = CALLCHAIN_LBR;
345 346 347
		else
			callchain_param.record_mode = CALLCHAIN_FP;
	}
348 349 350 351 352 353

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

354 355
	return 0;
}
356

357
static void sig_handler(int sig __maybe_unused)
358 359 360 361
{
	session_done = 1;
}

362
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
363 364 365 366
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
367 368 369
	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);
370 371
	char buf[512];
	size_t size = sizeof(buf);
372
	int socked_id = hists->socket_filter;
373

374 375 376
	if (quiet)
		return 0;

377 378 379 380 381
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

382
	if (perf_evsel__is_group_event(evsel)) {
383 384 385 386 387 388
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
389 390
			const struct hists *pos_hists = evsel__hists(pos);

391
			if (symbol_conf.filter_relative) {
392 393
				nr_samples += pos_hists->stats.nr_non_filtered_samples;
				nr_events += pos_hists->stats.total_non_filtered_period;
394
			} else {
395 396
				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos_hists->stats.total_period;
397
			}
398 399
		}
	}
400

401 402
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
403
	if (evname != NULL)
404 405
		ret += fprintf(fp, " of event '%s'", evname);

406 407 408
	if (rep->time_str)
		ret += fprintf(fp, " (time slices: %s)", rep->time_str);

409 410 411 412 413
	if (symbol_conf.show_ref_callgraph &&
	    strstr(evname, "call-graph=no")) {
		ret += fprintf(fp, ", show reference callgraph");
	}

414 415
	if (rep->mem_mode) {
		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
416
		ret += fprintf(fp, "\n# Sort order   : %s", sort_order ? : default_mem_sort_order);
417 418
	} else
		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
419

420 421
	if (socked_id > -1)
		ret += fprintf(fp, "\n# Processor Socket: %d", socked_id);
422

423 424 425
	return ret + fprintf(fp, "\n#\n");
}

426
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
427
					 struct report *rep,
428
					 const char *help)
429
{
430
	struct perf_evsel *pos;
431

432 433 434 435 436
	if (!quiet) {
		fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n",
			evlist->stats.total_lost_samples);
	}

437
	evlist__for_each_entry(evlist, pos) {
438
		struct hists *hists = evsel__hists(pos);
439
		const char *evname = perf_evsel__name(pos);
440

441 442 443 444
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

445
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
446
		hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout,
447 448
			       symbol_conf.use_callchain ||
			       symbol_conf.show_branchflag_count);
449 450 451
		fprintf(stdout, "\n\n");
	}

452
	if (!quiet)
453 454
		fprintf(stdout, "#\n# (%s)\n#\n", help);

455 456 457 458 459
	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);
460 461
	}

462 463 464
	if (sort__mode == SORT_MODE__BRANCH)
		branch_type_stat_display(stdout, &rep->brtype_stat);

465 466 467
	return 0;
}

468 469
static void report__warn_kptr_restrict(const struct report *rep)
{
470
	struct map *kernel_map = machine__kernel_map(&rep->session->machines.host);
471
	struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
472

473 474 475
	if (perf_evlist__exclude_kernel(rep->session->evlist))
		return;

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	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.";

		if (kernel_map) {
			const struct dso *kdso = kernel_map->dso;
			if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
				desc = "If some relocation was applied (e.g. "
				       "kexec) symbols may be misresolved.";
			}
		}

		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);
	}
}

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
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;
520 521 522 523 524 525 526 527
	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!";
	}
528 529 530 531 532

	switch (use_browser) {
	case 1:
		ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
						    rep->min_percent,
533 534
						    &session->header.env,
						    true);
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
		/*
		 * 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;
}

553
static int report__collapse_hists(struct report *rep)
554 555 556
{
	struct ui_progress prog;
	struct perf_evsel *pos;
557
	int ret = 0;
558

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

561
	evlist__for_each_entry(rep->session->evlist, pos) {
562
		struct hists *hists = evsel__hists(pos);
563 564 565 566

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

567 568
		hists->socket_filter = rep->socket_filter;

569 570 571
		ret = hists__collapse_resort(hists, &prog);
		if (ret < 0)
			break;
572 573 574 575

		/* Non-group events are considered as leader */
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos)) {
576
			struct hists *leader_hists = evsel__hists(pos->leader);
577 578 579 580 581 582 583

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

	ui_progress__finish();
584
	return ret;
585 586
}

587 588 589 590 591 592 593
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...");

594
	evlist__for_each_entry(rep->session->evlist, pos)
595
		perf_evsel__output_resort(pos, &prog);
596 597 598 599

	ui_progress__finish();
}

600 601 602 603 604 605 606 607 608 609 610 611 612 613
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;
}

614 615 616
static void tasks_setup(struct report *rep)
{
	memset(&rep->tool, 0, sizeof(rep->tool));
617 618 619 620
	if (rep->mmaps_mode) {
		rep->tool.mmap = perf_event__process_mmap;
		rep->tool.mmap2 = perf_event__process_mmap2;
	}
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
	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);
}

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
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)
{
	int printed = 0, i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
		printed += maps__fprintf_task(&mg->maps[i], indent, fp);
	return printed;
}

684 685 686 687
static void task__print_level(struct task *task, FILE *fp, int level)
{
	struct thread *thread = task->thread;
	struct task *child;
688 689 690 691 692
	int comm_indent = fprintf(fp, "  %8d %8d %8d |%*s",
				  thread->pid_, thread->tid, thread->ppid,
				  level, "");

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

694
	map_groups__fprintf_task(thread->mg, comm_indent, fp);
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 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

	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;
}

768
static int __cmd_report(struct report *rep)
769
{
770
	int ret;
771
	struct perf_session *session = rep->session;
772
	struct perf_evsel *pos;
773
	struct perf_data *data = session->data;
774

775 776
	signal(SIGINT, sig_handler);

777 778 779
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
780 781
		if (ret) {
			ui__error("failed to set cpu bitmap\n");
782
			return ret;
783
		}
784
		session->itrace_synth_opts->cpu_bitmap = rep->cpu_bitmap;
785 786
	}

787 788 789 790 791
	if (rep->show_threads) {
		ret = perf_read_values_init(&rep->show_threads_values);
		if (ret)
			return ret;
	}
792

793
	ret = report__setup_sample_type(rep);
794 795
	if (ret) {
		/* report__setup_sample_type() already showed error message */
796
		return ret;
797
	}
798

799 800 801
	if (rep->stats_mode)
		stats_setup(rep);

802 803 804
	if (rep->tasks_mode)
		tasks_setup(rep);

805
	ret = perf_session__process_events(session);
806 807
	if (ret) {
		ui__error("failed to process sample\n");
808
		return ret;
809
	}
810

811 812 813
	if (rep->stats_mode)
		return stats_print(rep);

814 815 816
	if (rep->tasks_mode)
		return tasks_print(rep, stdout);

817
	report__warn_kptr_restrict(rep);
818

819
	evlist__for_each_entry(session->evlist, pos)
820 821
		rep->nr_entries += evsel__hists(pos)->nr_entries;

822 823 824
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
825

826 827
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
828

829 830
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
831
			perf_evlist__fprintf_nr_events(session->evlist, stdout);
832 833
			return 0;
		}
834 835
	}

836 837 838 839 840
	ret = report__collapse_hists(rep);
	if (ret) {
		ui__error("failed to process hist entry\n");
		return ret;
	}
841

842 843 844
	if (session_done())
		return 0;

845 846 847 848 849
	/*
	 * recalculate number of entries after collapsing since it
	 * might be changed during the collapse phase.
	 */
	rep->nr_entries = 0;
850
	evlist__for_each_entry(session->evlist, pos)
851 852
		rep->nr_entries += evsel__hists(pos)->nr_entries;

853
	if (rep->nr_entries == 0) {
J
Jiri Olsa 已提交
854
		ui__error("The %s file has no samples!\n", data->file.path);
855
		return 0;
856 857
	}

858
	report__output_resort(rep);
859

860
	return report__browse_hists(rep);
861 862
}

863
static int
864
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
865
{
866
	struct callchain_param *callchain = opt->value;
867

868
	callchain->enabled = !unset;
869 870 871 872
	/*
	 * --no-call-graph
	 */
	if (unset) {
873 874
		symbol_conf.use_callchain = false;
		callchain->mode = CHAIN_NONE;
875 876 877
		return 0;
	}

878
	return parse_callchain_report_opt(arg);
879 880
}

881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
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;
}

899
static int
900
parse_branch_mode(const struct option *opt,
901
		  const char *str __maybe_unused, int unset)
902
{
903 904 905
	int *branch_mode = opt->value;

	*branch_mode = !unset;
906 907 908
	return 0;
}

909 910 911 912
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
913
	struct report *rep = opt->value;
914
	double pcnt = strtof(str, NULL);
915

916 917
	rep->min_percent = pcnt;
	callchain_param.min_percent = pcnt;
918 919 920
	return 0;
}

921
#define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function,percent"
922 923 924 925

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

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

	if (ret < 0)
		return ret;
1106

1107 1108 1109
	ret = perf_config(report__config, &report);
	if (ret)
		return ret;
1110

1111
	argc = parse_options(argc, argv, options, report_usage, 0);
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
	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];
	}
1122

1123 1124 1125
	if (report.mmaps_mode)
		report.tasks_mode = true;

1126 1127 1128
	if (quiet)
		perf_quiet_option();

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
	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;
	}

1140
	if (report.inverted_callchain)
1141
		callchain_param.order = ORDER_CALLER;
1142 1143
	if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
		callchain_param.order = ORDER_CALLER;
1144

1145 1146 1147 1148
	if (itrace_synth_opts.callchain &&
	    (int)itrace_synth_opts.callchain_sz > report.max_stack)
		report.max_stack = itrace_synth_opts.callchain_sz;

1149
	if (!input_name || !strlen(input_name)) {
1150
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
1151
			input_name = "-";
1152
		else
1153
			input_name = "perf.data";
1154
	}
1155

J
Jiri Olsa 已提交
1156 1157
	data.file.path = input_name;
	data.force     = symbol_conf.force;
1158

1159
repeat:
1160
	session = perf_session__new(&data, false, &report.tool);
1161
	if (session == NULL)
1162
		return -1;
1163

1164 1165 1166 1167 1168
	if (report.queue_size) {
		ordered_events__set_alloc_size(&session->ordered_events,
					       report.queue_size);
	}

1169 1170
	session->itrace_synth_opts = &itrace_synth_opts;

1171 1172 1173 1174
	report.session = session;

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

1176 1177 1178
	if (itrace_synth_opts.last_branch)
		has_br_stack = true;

1179 1180 1181
	if (has_br_stack && branch_call_mode)
		symbol_conf.show_branchflag_count = true;

1182 1183
	memset(&report.brtype_stat, 0, sizeof(struct branch_type_stat));

1184 1185 1186 1187 1188 1189
	/*
	 * 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) &&
1190
	    !branch_call_mode) {
1191
		sort__mode = SORT_MODE__BRANCH;
1192 1193
		symbol_conf.cumulate_callchain = false;
	}
1194
	if (branch_call_mode) {
1195
		callchain_param.key = CCKEY_ADDRESS;
1196 1197 1198 1199 1200 1201
		callchain_param.branch_callstack = 1;
		symbol_conf.use_callchain = true;
		callchain_register_param(&callchain_param);
		if (sort_order == NULL)
			sort_order = "srcline,symbol,dso";
	}
1202

1203
	if (report.mem_mode) {
1204
		if (sort__mode == SORT_MODE__BRANCH) {
1205
			pr_err("branch and mem mode incompatible\n");
1206 1207
			goto error;
		}
1208
		sort__mode = SORT_MODE__MEMORY;
1209
		symbol_conf.cumulate_callchain = false;
1210
	}
1211

1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
	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;
		}

1223
		perf_hpp_list.need_collapse = true;
1224 1225
	}

1226 1227 1228 1229 1230 1231 1232
	if (report.use_stdio)
		use_browser = 0;
	else if (report.use_tui)
		use_browser = 1;
	else if (report.use_gtk)
		use_browser = 2;

1233 1234
	/* Force tty output for header output and per-thread stat. */
	if (report.header || report.header_only || report.show_threads)
1235
		use_browser = 0;
1236 1237 1238 1239
	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;
1240
	if (report.stats_mode || report.tasks_mode)
1241
		use_browser = 0;
1242
	if (report.stats_mode && report.tasks_mode) {
1243
		pr_err("Error: --tasks and --mmaps can't be used together with --stats\n");
1244 1245
		goto error;
	}
1246

1247 1248
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
1249
	else
1250 1251
		use_browser = 0;

1252 1253 1254 1255 1256 1257 1258 1259 1260
	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;
	}

1261
	if ((report.header || report.header_only) && !quiet) {
1262 1263
		perf_session__fprintf_info(session, stdout,
					   report.show_full_info);
1264 1265 1266 1267
		if (report.header_only) {
			ret = 0;
			goto error;
		}
1268 1269
	} else if (use_browser == 0 && !quiet &&
		   !report.stats_mode && !report.tasks_mode) {
1270 1271 1272 1273
		fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
		      stdout);
	}

1274
	/*
1275
	 * Only in the TUI browser we are doing integrated annotation,
1276 1277 1278
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
1279
	if (ui__has_annotation()) {
1280 1281 1282
		ret = symbol__annotation_init();
		if (ret < 0)
			goto error;
1283 1284 1285 1286 1287
		/*
 		 * For searching by name on the "Browse map details".
 		 * providing it only in verbose mode not to bloat too
 		 * much struct symbol.
 		 */
1288
		if (verbose > 0) {
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
			/*
			 * 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;
		}
	}
1299

1300
	if (symbol__init(&session->header.env) < 0)
1301
		goto error;
1302

1303 1304 1305 1306 1307 1308 1309
	report.ptime_range = perf_time__range_alloc(report.time_str,
						    &report.range_size);
	if (!report.ptime_range) {
		ret = -ENOMEM;
		goto error;
	}

1310 1311 1312
	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) {
1313 1314 1315
			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");
1316 1317
			ret = -EINVAL;
			goto error;
1318 1319 1320
		}

		report.range_num = perf_time__percent_parse_str(
1321
					report.ptime_range, report.range_size,
1322 1323 1324 1325 1326 1327
					report.time_str,
					session->evlist->first_sample_time,
					session->evlist->last_sample_time);

		if (report.range_num < 0) {
			pr_err("Invalid time string\n");
1328 1329
			ret = -EINVAL;
			goto error;
1330 1331 1332
		}
	} else {
		report.range_num = 1;
1333 1334
	}

1335
	sort__setup_elide(stdout);
1336

1337
	ret = __cmd_report(&report);
1338 1339 1340 1341 1342 1343
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

1344
error:
1345 1346
	zfree(&report.ptime_range);

1347 1348
	perf_session__delete(session);
	return ret;
1349
}