builtin-report.c 21.9 KB
Newer Older
1 2 3 4 5 6 7
/*
 * 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.
 */
8
#include "builtin.h"
9

10
#include "util/util.h"
11
#include "util/cache.h"
12

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

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

#include "util/parse-options.h"
#include "util/parse-events.h"

33
#include "util/thread.h"
34
#include "util/sort.h"
35
#include "util/hist.h"
36
#include "util/data.h"
37
#include "arch/common.h"
38

39
#include <dlfcn.h>
40 41
#include <linux/bitmap.h>

42
struct report {
43
	struct perf_tool	tool;
44
	struct perf_session	*session;
45
	bool			force, use_tui, use_gtk, use_stdio;
46 47 48 49 50
	bool			hide_unresolved;
	bool			dont_use_callchains;
	bool			show_full_info;
	bool			show_threads;
	bool			inverted_callchain;
51
	bool			mem_mode;
52 53
	bool			header;
	bool			header_only;
54
	int			max_stack;
55 56 57
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	const char		*cpu_list;
58
	const char		*symbol_filter_str;
59
	float			min_percent;
60
	u64			nr_entries;
61
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
62
};
63

64
static int report__config(const char *var, const char *value, void *cb)
65 66 67 68 69
{
	if (!strcmp(var, "report.group")) {
		symbol_conf.event_group = perf_config_bool(var, value);
		return 0;
	}
70
	if (!strcmp(var, "report.percent-limit")) {
71
		struct report *rep = cb;
72 73 74
		rep->min_percent = strtof(value, NULL);
		return 0;
	}
75 76 77 78
	if (!strcmp(var, "report.children")) {
		symbol_conf.cumulate_callchain = perf_config_bool(var, value);
		return 0;
	}
79 80 81 82

	return perf_default_config(var, value, cb);
}

83 84
static void report__inc_stats(struct report *rep,
			      struct hist_entry *he __maybe_unused)
85 86
{
	/*
87 88
	 * We cannot access @he at this time.  Just assume it's a new entry.
	 * It'll be fixed once we have a callback mechanism in hist_iter.
89
	 */
90
	rep->nr_entries++;
91 92
}

93
static int process_sample_event(struct perf_tool *tool,
94
				union perf_event *event,
95
				struct perf_sample *sample,
96
				struct perf_evsel *evsel,
97
				struct machine *machine)
98
{
99
	struct report *rep = container_of(tool, struct report, tool);
100
	struct addr_location al;
101 102 103
	struct hist_entry_iter iter = {
		.hide_unresolved = rep->hide_unresolved,
	};
104
	int ret;
105

106
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
107 108
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
109 110
		return -1;
	}
111

112
	if (rep->hide_unresolved && al.sym == NULL)
113
		return 0;
114

115
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
116 117
		return 0;

118 119 120 121
	if (sort__mode == SORT_MODE__BRANCH)
		iter.ops = &hist_iter_branch;
	else if (rep->mem_mode)
		iter.ops = &hist_iter_mem;
122 123
	else if (symbol_conf.cumulate_callchain)
		iter.ops = &hist_iter_cumulative;
124 125 126 127 128 129 130 131 132 133 134
	else
		iter.ops = &hist_iter_normal;

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

	report__inc_stats(rep, NULL);

	ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack);
	if (ret < 0)
		pr_debug("problem adding hist entry, skipping event\n");
135

136
	return ret;
137
}
I
Ingo Molnar 已提交
138

139
static int process_read_event(struct perf_tool *tool,
140
			      union perf_event *event,
141
			      struct perf_sample *sample __maybe_unused,
142
			      struct perf_evsel *evsel,
143
			      struct machine *machine __maybe_unused)
144
{
145
	struct report *rep = container_of(tool, struct report, tool);
146

147
	if (rep->show_threads) {
148
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
149
		perf_read_values_add_value(&rep->show_threads_values,
150 151 152 153 154 155
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

156
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
157
		    evsel ? perf_evsel__name(evsel) : "FAIL",
158
		    event->read.value);
159 160 161 162

	return 0;
}

163
/* For pipe mode, sample_type is not currently set */
164
static int report__setup_sample_type(struct report *rep)
165
{
166 167 168
	struct perf_session *session = rep->session;
	u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
	bool is_pipe = perf_data_file__is_pipe(session->file);
169

170
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
171
		if (sort__has_parent) {
172
			ui__error("Selected --sort parent, but no "
173 174
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
175
			return -EINVAL;
176
		}
177
		if (symbol_conf.use_callchain) {
178
			ui__error("Selected -g but no callchain data. Did "
179
				    "you call 'perf record' without -g?\n");
180
			return -1;
181
		}
182 183
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
184
		   !symbol_conf.use_callchain) {
185
			symbol_conf.use_callchain = true;
186
			if (callchain_register_param(&callchain_param) < 0) {
187
				ui__error("Can't register callchain params.\n");
188
				return -EINVAL;
189
			}
190 191
	}

192 193 194 195 196 197 198 199
	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();
		}
	}

200
	if (sort__mode == SORT_MODE__BRANCH) {
201
		if (!is_pipe &&
202
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
203 204
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
205 206 207 208
			return -1;
		}
	}

209 210
	return 0;
}
211

212
static void sig_handler(int sig __maybe_unused)
213 214 215 216
{
	session_done = 1;
}

217
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
218 219 220 221
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
222 223 224
	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);
225 226 227
	char buf[512];
	size_t size = sizeof(buf);

228 229 230 231 232
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

233
	if (perf_evsel__is_group_event(evsel)) {
234 235 236 237 238 239
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
240 241 242 243 244 245 246
			if (symbol_conf.filter_relative) {
				nr_samples += pos->hists.stats.nr_non_filtered_samples;
				nr_events += pos->hists.stats.total_non_filtered_period;
			} else {
				nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos->hists.stats.total_period;
			}
247 248
		}
	}
249

250 251
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
252
	if (evname != NULL)
253 254
		ret += fprintf(fp, " of event '%s'", evname);

255 256 257 258 259
	if (rep->mem_mode) {
		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
		ret += fprintf(fp, "\n# Sort order   : %s", sort_order);
	} else
		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
260 261 262
	return ret + fprintf(fp, "\n#\n");
}

263
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
264
					 struct report *rep,
265
					 const char *help)
266
{
267
	struct perf_evsel *pos;
268

269
	evlist__for_each(evlist, pos) {
270
		struct hists *hists = &pos->hists;
271
		const char *evname = perf_evsel__name(pos);
272

273 274 275 276
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

277
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
278
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
279 280 281 282 283 284 285
		fprintf(stdout, "\n\n");
	}

	if (sort_order == default_sort_order &&
	    parent_pattern == default_parent_pattern) {
		fprintf(stdout, "#\n# (%s)\n#\n", help);

286 287 288
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
289
						 style);
290
			perf_read_values_destroy(&rep->show_threads_values);
291 292 293 294 295 296
		}
	}

	return 0;
}

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
static void report__warn_kptr_restrict(const struct report *rep)
{
	struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
	struct kmap *kernel_kmap = map__kmap(kernel_map);

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

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
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;
	const char *help = "For a higher level overview, try: perf report --sort comm,dso";

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

371
static void report__collapse_hists(struct report *rep)
372 373 374 375
{
	struct ui_progress prog;
	struct perf_evsel *pos;

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

378
	evlist__for_each(rep->session->evlist, pos) {
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
		struct hists *hists = &pos->hists;

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

		hists__collapse_resort(hists, &prog);

		/* Non-group events are considered as leader */
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos)) {
			struct hists *leader_hists = &pos->leader->hists;

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

	ui_progress__finish();
}

399
static int __cmd_report(struct report *rep)
400
{
401
	int ret;
402
	struct perf_session *session = rep->session;
403
	struct perf_evsel *pos;
404
	struct perf_data_file *file = session->file;
405

406 407
	signal(SIGINT, sig_handler);

408 409 410
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
411
		if (ret)
412
			return ret;
413 414
	}

415 416
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
417

418
	ret = report__setup_sample_type(rep);
419
	if (ret)
420
		return ret;
421

422
	ret = perf_session__process_events(session, &rep->tool);
423
	if (ret)
424
		return ret;
425

426
	report__warn_kptr_restrict(rep);
427

428 429 430
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
431

432 433
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
434

435 436 437 438
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
			return 0;
		}
439 440
	}

441
	report__collapse_hists(rep);
442

443 444 445
	if (session_done())
		return 0;

446
	if (rep->nr_entries == 0) {
447
		ui__error("The %s file has no samples!\n", file->path);
448
		return 0;
449 450
	}

451
	evlist__for_each(session->evlist, pos)
452 453
		hists__output_resort(&pos->hists);

454
	return report__browse_hists(rep);
455 456
}

457
static int
458
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
459
{
460
	struct report *rep = (struct report *)opt->value;
461

462 463 464 465
	/*
	 * --no-call-graph
	 */
	if (unset) {
466
		rep->dont_use_callchains = true;
467 468 469
		return 0;
	}

470
	return parse_callchain_report_opt(arg);
471 472
}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
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;
}

491
static int
492 493
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
494
{
495 496 497
	int *branch_mode = opt->value;

	*branch_mode = !unset;
498 499 500
	return 0;
}

501 502 503 504
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
505
	struct report *rep = opt->value;
506 507 508 509 510

	rep->min_percent = strtof(str, NULL);
	return 0;
}

511
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
512
{
513
	struct perf_session *session;
514
	struct stat st;
515
	bool has_br_stack = false;
516
	int branch_mode = -1;
517
	int ret = -1;
518 519
	char callchain_default_opt[] = "fractal,0.5,callee";
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
520
		"perf report [<options>]",
521 522
		NULL
	};
523
	struct report report = {
524
		.tool = {
525 526
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
527
			.mmap2		 = perf_event__process_mmap2,
528
			.comm		 = perf_event__process_comm,
529 530
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
531 532 533 534 535 536 537 538
			.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,
			.ordered_samples = true,
			.ordering_requires_timestamps = true,
		},
539
		.max_stack		 = PERF_MAX_STACK_DEPTH,
540 541 542
		.pretty_printing_style	 = "normal",
	};
	const struct option options[] = {
543
	OPT_STRING('i', "input", &input_name, "file",
544
		    "input file name"),
545
	OPT_INCR('v', "verbose", &verbose,
546
		    "be more verbose (show symbol address, etc)"),
547 548
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
549 550
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
551 552
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
553
	OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
554
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
555
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
556
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
557
		    "Show a column with the number of samples"),
558
	OPT_BOOLEAN('T', "threads", &report.show_threads,
559
		    "Show per-thread event counters"),
560
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
561
		   "pretty printing style key: normal raw"),
562
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
563
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
564 565
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
566 567 568
	OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
	OPT_BOOLEAN(0, "header-only", &report.header_only,
		    "Show only data header."),
569
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
570 571
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
		   " Please refer the man page for the complete list."),
572 573
	OPT_STRING('F', "fields", &field_order, "key[,keys...]",
		   "output field(s): overhead, period, sample plus all of sort keys"),
574 575
	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes"),
576 577
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
578
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
579
		    "Only display entries with parent-match"),
580
	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
581
		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
582
		     "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
583 584
	OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
		    "Accumulate callchains of children and show total overhead as well"),
585 586 587 588
	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. "
		    "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
589 590
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
591 592 593
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
594
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
595
		   "only consider symbols in these dsos"),
596
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
597
		   "only consider symbols in these comms"),
598
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
599
		   "only consider these symbols"),
600 601
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
602
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
603 604
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
605
	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
606 607
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
608
	OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
609
		    "Only display entries resolved to a symbol"),
610 611
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
612
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
613 614
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
615
		    "Display extended information about perf.data file"),
616 617 618 619
	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)"),
620 621
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
622 623
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
N
Namhyung Kim 已提交
624 625
	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
		    "Show event group information together"),
626
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
627
		    "use branch records for histogram filling", parse_branch_mode),
628 629
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
630 631
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
632
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
633 634
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
635
	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
N
Namhyung Kim 已提交
636
		     "how to display percentage of filtered entries", parse_filter_percentage),
637
	OPT_END()
638
	};
639 640 641
	struct perf_data_file file = {
		.mode  = PERF_DATA_MODE_READ,
	};
642

643
	perf_config(report__config, &report);
644

645 646
	argc = parse_options(argc, argv, options, report_usage, 0);

647
	if (report.use_stdio)
648
		use_browser = 0;
649
	else if (report.use_tui)
650
		use_browser = 1;
651 652
	else if (report.use_gtk)
		use_browser = 2;
653

654
	if (report.inverted_callchain)
655 656
		callchain_param.order = ORDER_CALLER;

657
	if (!input_name || !strlen(input_name)) {
658
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
659
			input_name = "-";
660
		else
661
			input_name = "perf.data";
662
	}
663

664 665 666
	file.path  = input_name;
	file.force = report.force;

667
repeat:
668
	session = perf_session__new(&file, false, &report.tool);
669 670 671 672 673 674 675
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

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

677
	if (branch_mode == -1 && has_br_stack) {
678
		sort__mode = SORT_MODE__BRANCH;
679 680
		symbol_conf.cumulate_callchain = false;
	}
681

682
	if (report.mem_mode) {
683
		if (sort__mode == SORT_MODE__BRANCH) {
684
			pr_err("branch and mem mode incompatible\n");
685 686
			goto error;
		}
687
		sort__mode = SORT_MODE__MEMORY;
688
		symbol_conf.cumulate_callchain = false;
689
	}
690

691
	if (setup_sorting() < 0) {
692 693 694 695 696
		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);
697 698
		goto error;
	}
699

700 701 702 703
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

704 705
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
706
	else
707 708
		use_browser = 0;

709 710 711 712 713 714 715 716 717 718
	if (report.header || report.header_only) {
		perf_session__fprintf_info(session, stdout,
					   report.show_full_info);
		if (report.header_only)
			return 0;
	} else if (use_browser == 0) {
		fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
		      stdout);
	}

719
	/*
720
	 * Only in the TUI browser we are doing integrated annotation,
721 722 723
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
724
	if (ui__has_annotation()) {
725
		symbol_conf.priv_size = sizeof(struct annotation);
726 727
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
		/*
 		 * For searching by name on the "Browse map details".
 		 * providing it only in verbose mode not to bloat too
 		 * much struct symbol.
 		 */
		if (verbose) {
			/*
			 * 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;
		}
	}
744

745
	if (symbol__init() < 0)
746
		goto error;
747

748 749 750 751 752 753 754 755 756 757
	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];
	}
758

759
	sort__setup_elide(stdout);
760

761
	ret = __cmd_report(&report);
762 763 764 765 766 767
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

768 769 770
error:
	perf_session__delete(session);
	return ret;
771
}