builtin-report.c 24.4 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
	u64			queue_size;
62
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
63
};
64

65
static int report__config(const char *var, const char *value, void *cb)
66
{
67 68
	struct report *rep = cb;

69 70 71 72
	if (!strcmp(var, "report.group")) {
		symbol_conf.event_group = perf_config_bool(var, value);
		return 0;
	}
73 74 75 76
	if (!strcmp(var, "report.percent-limit")) {
		rep->min_percent = strtof(value, NULL);
		return 0;
	}
77 78 79 80
	if (!strcmp(var, "report.children")) {
		symbol_conf.cumulate_callchain = perf_config_bool(var, value);
		return 0;
	}
81 82 83 84
	if (!strcmp(var, "report.queue-size")) {
		rep->queue_size = perf_config_u64(var, value);
		return 0;
	}
85 86 87 88

	return perf_default_config(var, value, cb);
}

89
static void report__inc_stats(struct report *rep, struct hist_entry *he)
90 91
{
	/*
92 93 94
	 * The @he is either of a newly created one or an existing one
	 * merging current sample.  We only want to count a new one so
	 * checking ->nr_events being 1.
95
	 */
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	if (he->stat.nr_events == 1)
		rep->nr_entries++;
}

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;
	struct mem_info *mi;
	struct branch_info *bi;

	report__inc_stats(rep, he);

	if (!ui__has_annotation())
		return 0;

	if (sort__mode == SORT_MODE__BRANCH) {
		bi = he->branch_info;
		err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
		if (err)
			goto out;

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

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

		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);

	} else if (symbol_conf.cumulate_callchain) {
		if (single)
			err = hist_entry__inc_addr_samples(he, evsel->idx,
							   al->addr);
	} else {
		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
	}

out:
	return err;
142 143
}

144
static int process_sample_event(struct perf_tool *tool,
145
				union perf_event *event,
146
				struct perf_sample *sample,
147
				struct perf_evsel *evsel,
148
				struct machine *machine)
149
{
150
	struct report *rep = container_of(tool, struct report, tool);
151
	struct addr_location al;
152 153
	struct hist_entry_iter iter = {
		.hide_unresolved = rep->hide_unresolved,
154
		.add_entry_cb = hist_iter__report_callback,
155
	};
156
	int ret;
157

158
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
159 160
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
161 162
		return -1;
	}
163

164
	if (rep->hide_unresolved && al.sym == NULL)
165
		return 0;
166

167
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
168 169
		return 0;

170 171 172 173
	if (sort__mode == SORT_MODE__BRANCH)
		iter.ops = &hist_iter_branch;
	else if (rep->mem_mode)
		iter.ops = &hist_iter_mem;
174 175
	else if (symbol_conf.cumulate_callchain)
		iter.ops = &hist_iter_cumulative;
176 177 178 179 180 181
	else
		iter.ops = &hist_iter_normal;

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

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

187
	return ret;
188
}
I
Ingo Molnar 已提交
189

190
static int process_read_event(struct perf_tool *tool,
191
			      union perf_event *event,
192
			      struct perf_sample *sample __maybe_unused,
193
			      struct perf_evsel *evsel,
194
			      struct machine *machine __maybe_unused)
195
{
196
	struct report *rep = container_of(tool, struct report, tool);
197

198
	if (rep->show_threads) {
199
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
200
		perf_read_values_add_value(&rep->show_threads_values,
201 202 203 204 205 206
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

207
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
208
		    evsel ? perf_evsel__name(evsel) : "FAIL",
209
		    event->read.value);
210 211 212 213

	return 0;
}

214
/* For pipe mode, sample_type is not currently set */
215
static int report__setup_sample_type(struct report *rep)
216
{
217 218 219
	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);
220

221
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
222
		if (sort__has_parent) {
223
			ui__error("Selected --sort parent, but no "
224 225
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
226
			return -EINVAL;
227
		}
228
		if (symbol_conf.use_callchain) {
229 230 231
			ui__error("Selected -g or --branch-history but no "
				  "callchain data. Did\n"
				  "you call 'perf record' without -g?\n");
232
			return -1;
233
		}
234 235
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
236
		   !symbol_conf.use_callchain) {
237
			symbol_conf.use_callchain = true;
238
			if (callchain_register_param(&callchain_param) < 0) {
239
				ui__error("Can't register callchain params.\n");
240
				return -EINVAL;
241
			}
242 243
	}

244 245 246 247 248 249 250 251
	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();
		}
	}

252
	if (sort__mode == SORT_MODE__BRANCH) {
253
		if (!is_pipe &&
254
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
255 256
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
257 258 259 260
			return -1;
		}
	}

261 262 263 264 265 266 267
	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
		if ((sample_type & PERF_SAMPLE_REGS_USER) &&
		    (sample_type & PERF_SAMPLE_STACK_USER))
			callchain_param.record_mode = CALLCHAIN_DWARF;
		else
			callchain_param.record_mode = CALLCHAIN_FP;
	}
268 269
	return 0;
}
270

271
static void sig_handler(int sig __maybe_unused)
272 273 274 275
{
	session_done = 1;
}

276
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
277 278 279 280
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
281 282 283
	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);
284 285 286
	char buf[512];
	size_t size = sizeof(buf);

287 288 289 290 291
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

292
	if (perf_evsel__is_group_event(evsel)) {
293 294 295 296 297 298
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
299 300
			const struct hists *pos_hists = evsel__hists(pos);

301
			if (symbol_conf.filter_relative) {
302 303
				nr_samples += pos_hists->stats.nr_non_filtered_samples;
				nr_events += pos_hists->stats.total_non_filtered_period;
304
			} else {
305 306
				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos_hists->stats.total_period;
307
			}
308 309
		}
	}
310

311 312
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
313
	if (evname != NULL)
314 315
		ret += fprintf(fp, " of event '%s'", evname);

316 317 318 319 320
	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);
321 322 323
	return ret + fprintf(fp, "\n#\n");
}

324
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
325
					 struct report *rep,
326
					 const char *help)
327
{
328
	struct perf_evsel *pos;
329

330
	evlist__for_each(evlist, pos) {
331
		struct hists *hists = evsel__hists(pos);
332
		const char *evname = perf_evsel__name(pos);
333

334 335 336 337
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

338
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
339
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
340 341 342 343 344 345 346
		fprintf(stdout, "\n\n");
	}

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

347 348 349
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
350
						 style);
351
			perf_read_values_destroy(&rep->show_threads_values);
352 353 354 355 356 357
		}
	}

	return 0;
}

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
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);
	}
}

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
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;
}

432
static void report__collapse_hists(struct report *rep)
433 434 435 436
{
	struct ui_progress prog;
	struct perf_evsel *pos;

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

439
	evlist__for_each(rep->session->evlist, pos) {
440
		struct hists *hists = evsel__hists(pos);
441 442 443 444 445 446 447 448 449

		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)) {
450
			struct hists *leader_hists = evsel__hists(pos->leader);
451 452 453 454 455 456 457 458 459

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

	ui_progress__finish();
}

460
static int __cmd_report(struct report *rep)
461
{
462
	int ret;
463
	struct perf_session *session = rep->session;
464
	struct perf_evsel *pos;
465
	struct perf_data_file *file = session->file;
466

467 468
	signal(SIGINT, sig_handler);

469 470 471
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
472
		if (ret)
473
			return ret;
474 475
	}

476 477
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
478

479
	ret = report__setup_sample_type(rep);
480
	if (ret)
481
		return ret;
482

483
	ret = perf_session__process_events(session, &rep->tool);
484
	if (ret)
485
		return ret;
486

487
	report__warn_kptr_restrict(rep);
488

489 490 491
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
492

493 494
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
495

496 497
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
498
			perf_evlist__fprintf_nr_events(session->evlist, stdout);
499 500
			return 0;
		}
501 502
	}

503
	report__collapse_hists(rep);
504

505 506 507
	if (session_done())
		return 0;

508
	if (rep->nr_entries == 0) {
509
		ui__error("The %s file has no samples!\n", file->path);
510
		return 0;
511 512
	}

513
	evlist__for_each(session->evlist, pos)
514
		hists__output_resort(evsel__hists(pos));
515

516
	return report__browse_hists(rep);
517 518
}

519
static int
520
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
521
{
522
	struct report *rep = (struct report *)opt->value;
523

524 525 526 527
	/*
	 * --no-call-graph
	 */
	if (unset) {
528
		rep->dont_use_callchains = true;
529 530 531
		return 0;
	}

532
	return parse_callchain_report_opt(arg);
533 534
}

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

553
static int
554 555
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
556
{
557 558 559
	int *branch_mode = opt->value;

	*branch_mode = !unset;
560 561 562
	return 0;
}

563 564 565 566
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
567
	struct report *rep = opt->value;
568 569 570 571 572

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

573
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
574
{
575
	struct perf_session *session;
576
	struct stat st;
577
	bool has_br_stack = false;
578
	int branch_mode = -1;
579
	bool branch_call_mode = false;
580 581
	char callchain_default_opt[] = "fractal,0.5,callee";
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
582
		"perf report [<options>]",
583 584
		NULL
	};
585
	struct report report = {
586
		.tool = {
587 588
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
589
			.mmap2		 = perf_event__process_mmap2,
590
			.comm		 = perf_event__process_comm,
591 592
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
593 594 595 596 597
			.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,
598
			.ordered_events	 = true,
599 600
			.ordering_requires_timestamps = true,
		},
601
		.max_stack		 = PERF_MAX_STACK_DEPTH,
602 603 604
		.pretty_printing_style	 = "normal",
	};
	const struct option options[] = {
605
	OPT_STRING('i', "input", &input_name, "file",
606
		    "input file name"),
607
	OPT_INCR('v', "verbose", &verbose,
608
		    "be more verbose (show symbol address, etc)"),
609 610
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
611 612
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
613 614
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
615
	OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
616
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
617
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
618
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
619
		    "Show a column with the number of samples"),
620
	OPT_BOOLEAN('T', "threads", &report.show_threads,
621
		    "Show per-thread event counters"),
622
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
623
		   "pretty printing style key: normal raw"),
624
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
625
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
626 627
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
628 629 630
	OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
	OPT_BOOLEAN(0, "header-only", &report.header_only,
		    "Show only data header."),
631
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
632 633
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
		   " Please refer the man page for the complete list."),
634 635
	OPT_STRING('F', "fields", &field_order, "key[,keys...]",
		   "output field(s): overhead, period, sample plus all of sort keys"),
636 637
	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes"),
638 639
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
640
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
641
		    "Only display entries with parent-match"),
642 643
	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
644
		     "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
645 646
	OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
		    "Accumulate callchains of children and show total overhead as well"),
647 648 649 650
	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)),
651 652
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
653 654 655
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
656
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
657
		   "only consider symbols in these dsos"),
658
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
659
		   "only consider symbols in these comms"),
660
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
661
		   "only consider these symbols"),
662 663
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
664
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
665 666
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
667
	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
668 669
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
670
	OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
671
		    "Only display entries resolved to a symbol"),
672 673
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
674
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
675 676
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
677
		    "Display extended information about perf.data file"),
678 679 680 681
	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)"),
682 683
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
684 685
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
N
Namhyung Kim 已提交
686 687
	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
		    "Show event group information together"),
688
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
689 690 691 692
		    "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"),
693 694
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
695 696
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
697 698
	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
		    "Enable kernel symbol demangling"),
699
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
700 701
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
702
	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
N
Namhyung Kim 已提交
703
		     "how to display percentage of filtered entries", parse_filter_percentage),
704
	OPT_END()
705
	};
706 707 708
	struct perf_data_file file = {
		.mode  = PERF_DATA_MODE_READ,
	};
709 710 711 712
	int ret = hists__init();

	if (ret < 0)
		return ret;
713

714
	perf_config(report__config, &report);
715

716 717
	argc = parse_options(argc, argv, options, report_usage, 0);

718
	if (report.use_stdio)
719
		use_browser = 0;
720
	else if (report.use_tui)
721
		use_browser = 1;
722 723
	else if (report.use_gtk)
		use_browser = 2;
724

725
	if (report.inverted_callchain)
726 727
		callchain_param.order = ORDER_CALLER;

728
	if (!input_name || !strlen(input_name)) {
729
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
730
			input_name = "-";
731
		else
732
			input_name = "perf.data";
733
	}
734

735 736 737
	file.path  = input_name;
	file.force = report.force;

738
repeat:
739
	session = perf_session__new(&file, false, &report.tool);
740
	if (session == NULL)
741
		return -1;
742

743 744 745 746 747
	if (report.queue_size) {
		ordered_events__set_alloc_size(&session->ordered_events,
					       report.queue_size);
	}

748 749 750 751
	report.session = session;

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

753 754 755 756 757 758 759
	/*
	 * 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) &&
	    branch_call_mode == -1) {
760
		sort__mode = SORT_MODE__BRANCH;
761 762
		symbol_conf.cumulate_callchain = false;
	}
763 764 765 766 767 768 769
	if (branch_call_mode) {
		callchain_param.branch_callstack = 1;
		symbol_conf.use_callchain = true;
		callchain_register_param(&callchain_param);
		if (sort_order == NULL)
			sort_order = "srcline,symbol,dso";
	}
770

771
	if (report.mem_mode) {
772
		if (sort__mode == SORT_MODE__BRANCH) {
773
			pr_err("branch and mem mode incompatible\n");
774 775
			goto error;
		}
776
		sort__mode = SORT_MODE__MEMORY;
777
		symbol_conf.cumulate_callchain = false;
778
	}
779

780
	if (setup_sorting() < 0) {
781 782 783 784 785
		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);
786 787
		goto error;
	}
788

789 790 791 792
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

793 794
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
795
	else
796 797
		use_browser = 0;

798 799 800 801 802 803 804 805 806 807
	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);
	}

808
	/*
809
	 * Only in the TUI browser we are doing integrated annotation,
810 811 812
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
813
	if (ui__has_annotation()) {
814
		symbol_conf.priv_size = sizeof(struct annotation);
815 816
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
		/*
 		 * 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;
		}
	}
833

834
	if (symbol__init(&session->header.env) < 0)
835
		goto error;
836

837 838 839 840 841 842 843 844 845 846
	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];
	}
847

848
	sort__setup_elide(stdout);
849

850
	ret = __cmd_report(&report);
851 852 853 854 855 856
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

857 858 859
error:
	perf_session__delete(session);
	return ret;
860
}