builtin-report.c 24.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
	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 461 462 463 464 465 466 467 468 469 470 471 472
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...");

	evlist__for_each(rep->session->evlist, pos)
		hists__output_resort(evsel__hists(pos), &prog);

	ui_progress__finish();
}

473
static int __cmd_report(struct report *rep)
474
{
475
	int ret;
476
	struct perf_session *session = rep->session;
477
	struct perf_evsel *pos;
478
	struct perf_data_file *file = session->file;
479

480 481
	signal(SIGINT, sig_handler);

482 483 484
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
485
		if (ret)
486
			return ret;
487 488
	}

489 490
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
491

492
	ret = report__setup_sample_type(rep);
493
	if (ret)
494
		return ret;
495

496
	ret = perf_session__process_events(session, &rep->tool);
497
	if (ret)
498
		return ret;
499

500
	report__warn_kptr_restrict(rep);
501

502 503 504
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
505

506 507
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
508

509 510
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
511
			perf_evlist__fprintf_nr_events(session->evlist, stdout);
512 513
			return 0;
		}
514 515
	}

516
	report__collapse_hists(rep);
517

518 519 520
	if (session_done())
		return 0;

521 522 523 524 525 526 527 528
	/*
	 * recalculate number of entries after collapsing since it
	 * might be changed during the collapse phase.
	 */
	rep->nr_entries = 0;
	evlist__for_each(session->evlist, pos)
		rep->nr_entries += evsel__hists(pos)->nr_entries;

529
	if (rep->nr_entries == 0) {
530
		ui__error("The %s file has no samples!\n", file->path);
531
		return 0;
532 533
	}

534
	report__output_resort(rep);
535

536
	return report__browse_hists(rep);
537 538
}

539
static int
540
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
541
{
542
	struct report *rep = (struct report *)opt->value;
543

544 545 546 547
	/*
	 * --no-call-graph
	 */
	if (unset) {
548
		rep->dont_use_callchains = true;
549 550 551
		return 0;
	}

552
	return parse_callchain_report_opt(arg);
553 554
}

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
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;
}

573
static int
574 575
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
576
{
577 578 579
	int *branch_mode = opt->value;

	*branch_mode = !unset;
580 581 582
	return 0;
}

583 584 585 586
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
587
	struct report *rep = opt->value;
588 589 590 591 592

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

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

	if (ret < 0)
		return ret;
733

734
	perf_config(report__config, &report);
735

736 737
	argc = parse_options(argc, argv, options, report_usage, 0);

738
	if (report.use_stdio)
739
		use_browser = 0;
740
	else if (report.use_tui)
741
		use_browser = 1;
742 743
	else if (report.use_gtk)
		use_browser = 2;
744

745
	if (report.inverted_callchain)
746 747
		callchain_param.order = ORDER_CALLER;

748
	if (!input_name || !strlen(input_name)) {
749
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
750
			input_name = "-";
751
		else
752
			input_name = "perf.data";
753
	}
754

755 756 757
	file.path  = input_name;
	file.force = report.force;

758
repeat:
759
	session = perf_session__new(&file, false, &report.tool);
760
	if (session == NULL)
761
		return -1;
762

763 764 765 766 767
	if (report.queue_size) {
		ordered_events__set_alloc_size(&session->ordered_events,
					       report.queue_size);
	}

768 769 770 771
	report.session = session;

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

773 774 775 776 777 778 779
	/*
	 * 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) {
780
		sort__mode = SORT_MODE__BRANCH;
781 782
		symbol_conf.cumulate_callchain = false;
	}
783
	if (branch_call_mode) {
784
		callchain_param.key = CCKEY_ADDRESS;
785 786 787 788 789 790
		callchain_param.branch_callstack = 1;
		symbol_conf.use_callchain = true;
		callchain_register_param(&callchain_param);
		if (sort_order == NULL)
			sort_order = "srcline,symbol,dso";
	}
791

792
	if (report.mem_mode) {
793
		if (sort__mode == SORT_MODE__BRANCH) {
794
			pr_err("branch and mem mode incompatible\n");
795 796
			goto error;
		}
797
		sort__mode = SORT_MODE__MEMORY;
798
		symbol_conf.cumulate_callchain = false;
799
	}
800

801
	if (setup_sorting() < 0) {
802 803 804 805 806
		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);
807 808
		goto error;
	}
809

810 811 812 813
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

814 815
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
816
	else
817 818
		use_browser = 0;

819 820 821 822 823 824 825 826 827 828
	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);
	}

829
	/*
830
	 * Only in the TUI browser we are doing integrated annotation,
831 832 833
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
834
	if (ui__has_annotation()) {
835
		symbol_conf.priv_size = sizeof(struct annotation);
836 837
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
		/*
 		 * 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;
		}
	}
854

855
	if (symbol__init(&session->header.env) < 0)
856
		goto error;
857

858 859 860 861 862 863 864 865 866 867
	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];
	}
868

869
	sort__setup_elide(stdout);
870

871
	ret = __cmd_report(&report);
872 873 874 875 876 877
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

878 879 880
error:
	perf_session__delete(session);
	return ret;
881
}