builtin-report.c 21.8 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

	return perf_default_config(var, value, cb);
}

79 80
static void report__inc_stats(struct report *rep,
			      struct hist_entry *he __maybe_unused)
81 82
{
	/*
83 84
	 * 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.
85
	 */
86
	rep->nr_entries++;
87 88
}

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

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

108
	if (rep->hide_unresolved && al.sym == NULL)
109
		return 0;
110

111
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
112 113
		return 0;

114 115 116 117
	if (sort__mode == SORT_MODE__BRANCH)
		iter.ops = &hist_iter_branch;
	else if (rep->mem_mode)
		iter.ops = &hist_iter_mem;
118 119
	else if (symbol_conf.cumulate_callchain)
		iter.ops = &hist_iter_cumulative;
120 121 122 123 124 125 126 127 128 129 130
	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");
131

132
	return ret;
133
}
I
Ingo Molnar 已提交
134

135
static int process_read_event(struct perf_tool *tool,
136
			      union perf_event *event,
137
			      struct perf_sample *sample __maybe_unused,
138
			      struct perf_evsel *evsel,
139
			      struct machine *machine __maybe_unused)
140
{
141
	struct report *rep = container_of(tool, struct report, tool);
142

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

152
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
153
		    evsel ? perf_evsel__name(evsel) : "FAIL",
154
		    event->read.value);
155 156 157 158

	return 0;
}

159
/* For pipe mode, sample_type is not currently set */
160
static int report__setup_sample_type(struct report *rep)
161
{
162 163 164
	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);
165

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

188 189 190 191 192 193 194 195
	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();
		}
	}

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

205 206
	return 0;
}
207

208
static void sig_handler(int sig __maybe_unused)
209 210 211 212
{
	session_done = 1;
}

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

224 225 226 227 228
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

229
	if (perf_evsel__is_group_event(evsel)) {
230 231 232 233 234 235
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
236 237 238 239 240 241 242
			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;
			}
243 244
		}
	}
245

246 247
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
248
	if (evname != NULL)
249 250
		ret += fprintf(fp, " of event '%s'", evname);

251 252 253 254 255
	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);
256 257 258
	return ret + fprintf(fp, "\n#\n");
}

259
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
260
					 struct report *rep,
261
					 const char *help)
262
{
263
	struct perf_evsel *pos;
264

265
	evlist__for_each(evlist, pos) {
266
		struct hists *hists = &pos->hists;
267
		const char *evname = perf_evsel__name(pos);
268

269 270 271 272
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

273
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
274
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
275 276 277 278 279 280 281
		fprintf(stdout, "\n\n");
	}

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

282 283 284
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
285
						 style);
286
			perf_read_values_destroy(&rep->show_threads_values);
287 288 289 290 291 292
		}
	}

	return 0;
}

293 294 295 296 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
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);
	}
}

322 323 324 325 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
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;
}

367
static void report__collapse_hists(struct report *rep)
368 369 370 371
{
	struct ui_progress prog;
	struct perf_evsel *pos;

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

374
	evlist__for_each(rep->session->evlist, pos) {
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
		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();
}

395
static int __cmd_report(struct report *rep)
396
{
397
	int ret;
398
	struct perf_session *session = rep->session;
399
	struct perf_evsel *pos;
400
	struct perf_data_file *file = session->file;
401

402 403
	signal(SIGINT, sig_handler);

404 405 406
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
407
		if (ret)
408
			return ret;
409 410
	}

411 412
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
413

414
	ret = report__setup_sample_type(rep);
415
	if (ret)
416
		return ret;
417

418
	ret = perf_session__process_events(session, &rep->tool);
419
	if (ret)
420
		return ret;
421

422
	report__warn_kptr_restrict(rep);
423

424 425 426
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
427

428 429
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
430

431 432 433 434
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
			return 0;
		}
435 436
	}

437
	report__collapse_hists(rep);
438

439 440 441
	if (session_done())
		return 0;

442
	if (rep->nr_entries == 0) {
443
		ui__error("The %s file has no samples!\n", file->path);
444
		return 0;
445 446
	}

447
	evlist__for_each(session->evlist, pos)
448 449
		hists__output_resort(&pos->hists);

450
	return report__browse_hists(rep);
451 452
}

453
static int
454
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
455
{
456
	struct report *rep = (struct report *)opt->value;
457

458 459 460 461
	/*
	 * --no-call-graph
	 */
	if (unset) {
462
		rep->dont_use_callchains = true;
463 464 465
		return 0;
	}

466
	return parse_callchain_report_opt(arg);
467 468
}

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
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;
}

487
static int
488 489
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
490
{
491 492 493
	int *branch_mode = opt->value;

	*branch_mode = !unset;
494 495 496
	return 0;
}

497 498 499 500
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
501
	struct report *rep = opt->value;
502 503 504 505 506

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

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

639
	perf_config(report__config, &report);
640

641 642
	argc = parse_options(argc, argv, options, report_usage, 0);

643
	if (report.use_stdio)
644
		use_browser = 0;
645
	else if (report.use_tui)
646
		use_browser = 1;
647 648
	else if (report.use_gtk)
		use_browser = 2;
649

650
	if (report.inverted_callchain)
651 652
		callchain_param.order = ORDER_CALLER;

653
	if (!input_name || !strlen(input_name)) {
654
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
655
			input_name = "-";
656
		else
657
			input_name = "perf.data";
658
	}
659

660 661 662
	file.path  = input_name;
	file.force = report.force;

663
repeat:
664
	session = perf_session__new(&file, false, &report.tool);
665 666 667 668 669 670 671
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

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

673
	if (branch_mode == -1 && has_br_stack) {
674
		sort__mode = SORT_MODE__BRANCH;
675 676
		symbol_conf.cumulate_callchain = false;
	}
677

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

687
	if (setup_sorting() < 0) {
688 689 690 691 692
		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);
693 694
		goto error;
	}
695

696 697 698 699
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

700 701
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
702
	else
703 704
		use_browser = 0;

705 706 707 708 709 710 711 712 713 714
	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);
	}

715
	/*
716
	 * Only in the TUI browser we are doing integrated annotation,
717 718 719
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
720
	if (ui__has_annotation()) {
721
		symbol_conf.priv_size = sizeof(struct annotation);
722 723
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
		/*
 		 * 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;
		}
	}
740

741
	if (symbol__init() < 0)
742
		goto error;
743

744 745 746 747 748 749 750 751 752 753
	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];
	}
754

755
	sort__setup_elide(stdout);
756

757
	ret = __cmd_report(&report);
758 759 760 761 762 763
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

764 765 766
error:
	perf_session__delete(session);
	return ret;
767
}