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 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

	switch (use_browser) {
	case 1:
		ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
						    rep->min_percent,
						    &session->header.env);
		/*
		 * 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;
}

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

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

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

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

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

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

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

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

	ui_progress__finish();
583
	return ret;
584 585
}

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

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

	ui_progress__finish();
}

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

613 614 615
static void tasks_setup(struct report *rep)
{
	memset(&rep->tool, 0, sizeof(rep->tool));
616 617 618 619
	if (rep->mmaps_mode) {
		rep->tool.mmap = perf_event__process_mmap;
		rep->tool.mmap2 = perf_event__process_mmap2;
	}
620 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
	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);
}

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

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

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

693
	map_groups__fprintf_task(thread->mg, comm_indent, fp);
694 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

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

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

774 775
	signal(SIGINT, sig_handler);

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

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

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

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

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

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

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

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

816
	report__warn_kptr_restrict(rep);
817

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

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

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

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

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

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

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

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

857
	report__output_resort(rep);
858

859
	return report__browse_hists(rep);
860 861
}

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

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

877
	return parse_callchain_report_opt(arg);
878 879
}

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

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

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

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

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

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

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

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

	if (ret < 0)
		return ret;
1105

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

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

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

1125 1126 1127
	if (quiet)
		perf_quiet_option();

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

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

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

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

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

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

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

1168 1169
	session->itrace_synth_opts = &itrace_synth_opts;

1170 1171 1172 1173
	report.session = session;

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

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

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

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

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

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

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

1222
		perf_hpp_list.need_collapse = true;
1223 1224
	}

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

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

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

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

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

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

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

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

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

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

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

1334
	sort__setup_elide(stdout);
1335

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

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

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