builtin-report.c 27.2 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 40
#include "util/auxtrace.h"

41
#include <dlfcn.h>
42 43
#include <linux/bitmap.h>

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

69
static int report__config(const char *var, const char *value, void *cb)
70
{
71 72
	struct report *rep = cb;

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

	return perf_default_config(var, value, cb);
}

93 94 95 96 97 98 99 100 101 102 103 104 105 106
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;

	if (!ui__has_annotation())
		return 0;

107 108 109
	hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
			     rep->nonany_branch_mode);

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

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

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

160
	if (rep->hide_unresolved && al.sym == NULL)
161
		goto out_put;
162

163
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
164
		goto out_put;
165

166 167 168 169
	if (sort__mode == SORT_MODE__BRANCH)
		iter.ops = &hist_iter_branch;
	else if (rep->mem_mode)
		iter.ops = &hist_iter_mem;
170 171
	else if (symbol_conf.cumulate_callchain)
		iter.ops = &hist_iter_cumulative;
172 173 174 175 176 177
	else
		iter.ops = &hist_iter_normal;

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

178
	ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
179 180
	if (ret < 0)
		pr_debug("problem adding hist entry, skipping event\n");
181 182
out_put:
	addr_location__put(&al);
183
	return ret;
184
}
I
Ingo Molnar 已提交
185

186
static int process_read_event(struct perf_tool *tool,
187
			      union perf_event *event,
188
			      struct perf_sample *sample __maybe_unused,
189
			      struct perf_evsel *evsel,
190
			      struct machine *machine __maybe_unused)
191
{
192
	struct report *rep = container_of(tool, struct report, tool);
193

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

203
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
204
		    evsel ? perf_evsel__name(evsel) : "FAIL",
205
		    event->read.value);
206 207 208 209

	return 0;
}

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

217 218 219 220 221 222
	if (session->itrace_synth_opts->callchain ||
	    (!is_pipe &&
	     perf_header__has_feat(&session->header, HEADER_AUXTRACE) &&
	     !session->itrace_synth_opts->set))
		sample_type |= PERF_SAMPLE_CALLCHAIN;

223 224 225
	if (session->itrace_synth_opts->last_branch)
		sample_type |= PERF_SAMPLE_BRANCH_STACK;

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

249 250 251 252 253 254 255 256
	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();
		}
	}

257
	if (sort__mode == SORT_MODE__BRANCH) {
258
		if (!is_pipe &&
259
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
260 261
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
262 263 264 265
			return -1;
		}
	}

266 267 268 269
	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;
270 271
		else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
			callchain_param.record_mode = CALLCHAIN_LBR;
272 273 274
		else
			callchain_param.record_mode = CALLCHAIN_FP;
	}
275 276 277 278 279 280

	/* ??? handle more cases than just ANY? */
	if (!(perf_evlist__combined_branch_type(session->evlist) &
				PERF_SAMPLE_BRANCH_ANY))
		rep->nonany_branch_mode = true;

281 282
	return 0;
}
283

284
static void sig_handler(int sig __maybe_unused)
285 286 287 288
{
	session_done = 1;
}

289
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
290 291 292 293
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
294 295 296
	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);
297 298
	char buf[512];
	size_t size = sizeof(buf);
299
	int socked_id = hists->socket_filter;
300

301 302 303 304 305
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

306
	if (perf_evsel__is_group_event(evsel)) {
307 308 309 310 311 312
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
313 314
			const struct hists *pos_hists = evsel__hists(pos);

315
			if (symbol_conf.filter_relative) {
316 317
				nr_samples += pos_hists->stats.nr_non_filtered_samples;
				nr_events += pos_hists->stats.total_non_filtered_period;
318
			} else {
319 320
				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos_hists->stats.total_period;
321
			}
322 323
		}
	}
324

325 326
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
327
	if (evname != NULL)
328 329
		ret += fprintf(fp, " of event '%s'", evname);

330 331 332 333 334
	if (symbol_conf.show_ref_callgraph &&
	    strstr(evname, "call-graph=no")) {
		ret += fprintf(fp, ", show reference callgraph");
	}

335 336
	if (rep->mem_mode) {
		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
337
		ret += fprintf(fp, "\n# Sort order   : %s", sort_order ? : default_mem_sort_order);
338 339
	} else
		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
340

341 342
	if (socked_id > -1)
		ret += fprintf(fp, "\n# Processor Socket: %d", socked_id);
343

344 345 346
	return ret + fprintf(fp, "\n#\n");
}

347
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
348
					 struct report *rep,
349
					 const char *help)
350
{
351
	struct perf_evsel *pos;
352

353
	fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples);
354
	evlist__for_each(evlist, pos) {
355
		struct hists *hists = evsel__hists(pos);
356
		const char *evname = perf_evsel__name(pos);
357

358 359 360 361
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

362
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
363
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
364 365 366
		fprintf(stdout, "\n\n");
	}

367
	if (sort_order == NULL &&
368
	    parent_pattern == default_parent_pattern)
369 370
		fprintf(stdout, "#\n# (%s)\n#\n", help);

371 372 373 374 375
	if (rep->show_threads) {
		bool style = !strcmp(rep->pretty_printing_style, "raw");
		perf_read_values_display(stdout, &rep->show_threads_values,
					 style);
		perf_read_values_destroy(&rep->show_threads_values);
376 377 378 379 380
	}

	return 0;
}

381 382 383
static void report__warn_kptr_restrict(const struct report *rep)
{
	struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
384
	struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

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

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
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;
}

455
static void report__collapse_hists(struct report *rep)
456 457 458 459
{
	struct ui_progress prog;
	struct perf_evsel *pos;

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

462
	evlist__for_each(rep->session->evlist, pos) {
463
		struct hists *hists = evsel__hists(pos);
464 465 466 467

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

468 469
		hists->socket_filter = rep->socket_filter;

470 471 472 473 474
		hists__collapse_resort(hists, &prog);

		/* Non-group events are considered as leader */
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos)) {
475
			struct hists *leader_hists = evsel__hists(pos->leader);
476 477 478 479 480 481 482 483 484

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

	ui_progress__finish();
}

485 486 487 488 489 490 491 492 493 494 495 496 497
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();
}

498
static int __cmd_report(struct report *rep)
499
{
500
	int ret;
501
	struct perf_session *session = rep->session;
502
	struct perf_evsel *pos;
503
	struct perf_data_file *file = session->file;
504

505 506
	signal(SIGINT, sig_handler);

507 508 509
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
510
		if (ret)
511
			return ret;
512 513
	}

514 515
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
516

517
	ret = report__setup_sample_type(rep);
518
	if (ret)
519
		return ret;
520

521
	ret = perf_session__process_events(session);
522
	if (ret)
523
		return ret;
524

525
	report__warn_kptr_restrict(rep);
526

527 528 529
	evlist__for_each(session->evlist, pos)
		rep->nr_entries += evsel__hists(pos)->nr_entries;

530 531 532
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
533

534 535
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
536

537 538
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
539
			perf_evlist__fprintf_nr_events(session->evlist, stdout);
540 541
			return 0;
		}
542 543
	}

544
	report__collapse_hists(rep);
545

546 547 548
	if (session_done())
		return 0;

549 550 551 552 553 554 555 556
	/*
	 * 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;

557
	if (rep->nr_entries == 0) {
558
		ui__error("The %s file has no samples!\n", file->path);
559
		return 0;
560 561
	}

562
	report__output_resort(rep);
563

564
	return report__browse_hists(rep);
565 566
}

567
static int
568
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
569
{
570
	struct report *rep = (struct report *)opt->value;
571

572 573 574 575
	/*
	 * --no-call-graph
	 */
	if (unset) {
576
		rep->dont_use_callchains = true;
577 578 579
		return 0;
	}

580
	return parse_callchain_report_opt(arg);
581 582
}

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
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;
}

601
static int
602 603
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
604
{
605 606 607
	int *branch_mode = opt->value;

	*branch_mode = !unset;
608 609 610
	return 0;
}

611 612 613 614
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
615
	struct report *rep = opt->value;
616 617 618 619 620

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

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

	if (ret < 0)
		return ret;
779

780
	perf_config(report__config, &report);
781

782 783
	argc = parse_options(argc, argv, options, report_usage, 0);

784 785 786 787 788 789 790 791 792 793 794
	if (symbol_conf.vmlinux_name &&
	    access(symbol_conf.vmlinux_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
		return -EINVAL;
	}
	if (symbol_conf.kallsyms_name &&
	    access(symbol_conf.kallsyms_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
		return -EINVAL;
	}

795
	if (report.use_stdio)
796
		use_browser = 0;
797
	else if (report.use_tui)
798
		use_browser = 1;
799 800
	else if (report.use_gtk)
		use_browser = 2;
801

802
	if (report.inverted_callchain)
803 804
		callchain_param.order = ORDER_CALLER;

805
	if (!input_name || !strlen(input_name)) {
806
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
807
			input_name = "-";
808
		else
809
			input_name = "perf.data";
810
	}
811

812 813 814
	file.path  = input_name;
	file.force = report.force;

815
repeat:
816
	session = perf_session__new(&file, false, &report.tool);
817
	if (session == NULL)
818
		return -1;
819

820 821 822 823 824
	if (report.queue_size) {
		ordered_events__set_alloc_size(&session->ordered_events,
					       report.queue_size);
	}

825 826
	session->itrace_synth_opts = &itrace_synth_opts;

827 828 829 830
	report.session = session;

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

832 833 834 835 836 837
	/*
	 * 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) &&
838
	    !branch_call_mode) {
839
		sort__mode = SORT_MODE__BRANCH;
840 841
		symbol_conf.cumulate_callchain = false;
	}
842
	if (branch_call_mode) {
843
		callchain_param.key = CCKEY_ADDRESS;
844 845 846 847 848 849
		callchain_param.branch_callstack = 1;
		symbol_conf.use_callchain = true;
		callchain_register_param(&callchain_param);
		if (sort_order == NULL)
			sort_order = "srcline,symbol,dso";
	}
850

851
	if (report.mem_mode) {
852
		if (sort__mode == SORT_MODE__BRANCH) {
853
			pr_err("branch and mem mode incompatible\n");
854 855
			goto error;
		}
856
		sort__mode = SORT_MODE__MEMORY;
857
		symbol_conf.cumulate_callchain = false;
858
	}
859

860
	if (setup_sorting() < 0) {
861 862 863 864 865
		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);
866 867
		goto error;
	}
868

869 870
	/* Force tty output for header output and per-thread stat. */
	if (report.header || report.header_only || report.show_threads)
871 872
		use_browser = 0;

873 874
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
875
	else
876 877
		use_browser = 0;

878 879 880
	if (report.header || report.header_only) {
		perf_session__fprintf_info(session, stdout,
					   report.show_full_info);
881 882 883 884
		if (report.header_only) {
			ret = 0;
			goto error;
		}
885 886 887 888 889
	} else if (use_browser == 0) {
		fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
		      stdout);
	}

890
	/*
891
	 * Only in the TUI browser we are doing integrated annotation,
892 893 894
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
895
	if (ui__has_annotation()) {
896
		symbol_conf.priv_size = sizeof(struct annotation);
897 898
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
		/*
 		 * 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;
		}
	}
915

916
	if (symbol__init(&session->header.env) < 0)
917
		goto error;
918

919 920 921 922 923 924 925 926 927 928
	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];
	}
929

930
	sort__setup_elide(stdout);
931

932
	ret = __cmd_report(&report);
933 934 935 936 937 938
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

939 940 941
error:
	perf_session__delete(session);
	return ret;
942
}