builtin-report.c 26.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
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
61
};
62

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

	return perf_default_config(var, value, cb);
}

78 79
static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
				      struct perf_sample *sample, struct perf_evsel *evsel,
80
				      union perf_event *event)
81
{
82
	struct report *rep = container_of(tool, struct report, tool);
83 84 85 86 87
	struct symbol *parent = NULL;
	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
	struct hist_entry *he;
	struct mem_info *mi, *mx;
	uint64_t cost;
88
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
89

90 91
	if (err)
		return err;
92

93
	mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	if (!mi)
		return -ENOMEM;

	if (rep->hide_unresolved && !al->sym)
		return 0;

	cost = sample->weight;
	if (!cost)
		cost = 1;

	/*
	 * must pass period=weight in order to get the correct
	 * sorting from hists__collapse_resort() which is solely
	 * based on periods. We want sorting be done on nr_events * weight
	 * and this is indirectly achieved by passing period=weight here
	 * and the he_stat__add_period() function.
	 */
111 112
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
				cost, cost, 0);
113 114 115
	if (!he)
		return -ENOMEM;

116 117 118
	err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
	if (err)
		goto out;
119

120
	mx = he->mem_info;
121
	err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
122 123
	if (err)
		goto out;
124 125 126

	evsel->hists.stats.total_period += cost;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
127
	err = hist_entry__append_callchain(he, sample);
128 129 130 131
out:
	return err;
}

132
static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
133
					 struct perf_sample *sample, struct perf_evsel *evsel)
134
{
135
	struct report *rep = container_of(tool, struct report, tool);
136 137 138
	struct symbol *parent = NULL;
	unsigned i;
	struct hist_entry *he;
139
	struct branch_info *bi, *bx;
140
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
141

142 143
	if (err)
		return err;
144

145
	bi = machine__resolve_bstack(al->machine, al->thread,
146 147 148 149 150 151 152
				     sample->branch_stack);
	if (!bi)
		return -ENOMEM;

	for (i = 0; i < sample->branch_stack->nr; i++) {
		if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
			continue;
153 154 155

		err = -ENOMEM;

156 157 158 159
		/* overwrite the 'al' to branch-to info */
		al->map = bi[i].to.map;
		al->sym = bi[i].to.sym;
		al->addr = bi[i].to.addr;
160 161 162 163
		/*
		 * The report shows the percentage of total branches captured
		 * and not events sampled. Thus we use a pseudo period of 1.
		 */
164 165
		he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
					1, 1, 0);
166
		if (he) {
167
			bx = he->branch_info;
168
			err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
169 170 171
			if (err)
				goto out;

172
			err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
173 174 175
			if (err)
				goto out;

176 177 178
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
		} else
179
			goto out;
180
	}
181
	err = 0;
182
out:
183
	free(bi);
184 185 186
	return err;
}

187
static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
188
				  struct addr_location *al, struct perf_sample *sample)
189
{
190
	struct report *rep = container_of(tool, struct report, tool);
191
	struct symbol *parent = NULL;
192
	struct hist_entry *he;
193
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
194

195 196
	if (err)
		return err;
197

198 199 200
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
				sample->period, sample->weight,
				sample->transaction);
201
	if (he == NULL)
202 203
		return -ENOMEM;

204 205 206
	err = hist_entry__append_callchain(he, sample);
	if (err)
		goto out;
207

208
	err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
209 210
	evsel->hists.stats.total_period += sample->period;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
211
out:
212
	return err;
213 214
}

215

216
static int process_sample_event(struct perf_tool *tool,
217
				union perf_event *event,
218
				struct perf_sample *sample,
219
				struct perf_evsel *evsel,
220
				struct machine *machine)
221
{
222
	struct report *rep = container_of(tool, struct report, tool);
223
	struct addr_location al;
224
	int ret;
225

226
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
227 228
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
229 230
		return -1;
	}
231

232
	if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
233
		return 0;
234

235
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
236 237
		return 0;

238
	if (sort__mode == SORT_MODE__BRANCH) {
239
		ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
240
		if (ret < 0)
241
			pr_debug("problem adding lbr entry, skipping event\n");
242
	} else if (rep->mem_mode == 1) {
243
		ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
244
		if (ret < 0)
245
			pr_debug("problem adding mem entry, skipping event\n");
246 247 248
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
249

250
		ret = report__add_hist_entry(tool, evsel, &al, sample);
251
		if (ret < 0)
252
			pr_debug("problem incrementing symbol period, skipping event\n");
253
	}
254
	return ret;
255
}
I
Ingo Molnar 已提交
256

257
static int process_read_event(struct perf_tool *tool,
258
			      union perf_event *event,
259
			      struct perf_sample *sample __maybe_unused,
260
			      struct perf_evsel *evsel,
261
			      struct machine *machine __maybe_unused)
262
{
263
	struct report *rep = container_of(tool, struct report, tool);
264

265
	if (rep->show_threads) {
266
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
267
		perf_read_values_add_value(&rep->show_threads_values,
268 269 270 271 272 273
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

274
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
275
		    evsel ? perf_evsel__name(evsel) : "FAIL",
276
		    event->read.value);
277 278 279 280

	return 0;
}

281
/* For pipe mode, sample_type is not currently set */
282
static int report__setup_sample_type(struct report *rep)
283
{
284 285 286
	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);
287

288
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
289
		if (sort__has_parent) {
290
			ui__error("Selected --sort parent, but no "
291 292
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
293
			return -EINVAL;
294
		}
295
		if (symbol_conf.use_callchain) {
296
			ui__error("Selected -g but no callchain data. Did "
297
				    "you call 'perf record' without -g?\n");
298
			return -1;
299
		}
300 301
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
302
		   !symbol_conf.use_callchain) {
303
			symbol_conf.use_callchain = true;
304
			if (callchain_register_param(&callchain_param) < 0) {
305
				ui__error("Can't register callchain params.\n");
306
				return -EINVAL;
307
			}
308 309
	}

310
	if (sort__mode == SORT_MODE__BRANCH) {
311
		if (!is_pipe &&
312
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
313 314
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
315 316 317 318
			return -1;
		}
	}

319 320
	return 0;
}
321

322
static void sig_handler(int sig __maybe_unused)
323 324 325 326
{
	session_done = 1;
}

327
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
328 329 330 331
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
332 333 334
	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);
335 336 337
	char buf[512];
	size_t size = sizeof(buf);

338
	if (perf_evsel__is_group_event(evsel)) {
339 340 341 342 343 344 345 346 347 348
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
			nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
			nr_events += pos->hists.stats.total_period;
		}
	}
349

350 351
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
352
	if (evname != NULL)
353 354
		ret += fprintf(fp, " of event '%s'", evname);

355 356 357 358 359
	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);
360 361 362
	return ret + fprintf(fp, "\n#\n");
}

363
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
364
					 struct report *rep,
365
					 const char *help)
366
{
367
	struct perf_evsel *pos;
368

369
	evlist__for_each(evlist, pos) {
370
		struct hists *hists = &pos->hists;
371
		const char *evname = perf_evsel__name(pos);
372

373 374 375 376
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

377
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
378
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
379 380 381 382 383 384 385
		fprintf(stdout, "\n\n");
	}

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

386 387 388
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
389
						 style);
390
			perf_read_values_destroy(&rep->show_threads_values);
391 392 393 394 395 396
		}
	}

	return 0;
}

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

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 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
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;
}

471 472 473 474 475 476 477 478 479
static u64 report__collapse_hists(struct report *rep)
{
	struct ui_progress prog;
	struct perf_evsel *pos;
	u64 nr_samples = 0;
	/*
 	 * Count number of histogram entries to use when showing progress,
 	 * reusing nr_samples variable.
 	 */
480
	evlist__for_each(rep->session->evlist, pos)
481 482 483 484 485 486 487 488 489
		nr_samples += pos->hists.nr_entries;

	ui_progress__init(&prog, nr_samples, "Merging related events...");
	/*
	 * Count total number of samples, will be used to check if this
 	 * session had any.
 	 */
	nr_samples = 0;

490
	evlist__for_each(rep->session->evlist, pos) {
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
		struct hists *hists = &pos->hists;

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

		hists__collapse_resort(hists, &prog);
		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];

		/* 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();

	return nr_samples;
}

514
static int __cmd_report(struct report *rep)
515
{
516
	int ret;
517
	u64 nr_samples;
518
	struct perf_session *session = rep->session;
519
	struct perf_evsel *pos;
520
	struct perf_data_file *file = session->file;
521

522 523
	signal(SIGINT, sig_handler);

524 525 526
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
527
		if (ret)
528
			return ret;
529 530
	}

531 532
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
533

534
	ret = report__setup_sample_type(rep);
535
	if (ret)
536
		return ret;
537

538
	ret = perf_session__process_events(session, &rep->tool);
539
	if (ret)
540
		return ret;
541

542
	report__warn_kptr_restrict(rep);
543

544 545 546
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
547

548 549
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
550

551 552 553 554
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
			return 0;
		}
555 556
	}

557
	nr_samples = report__collapse_hists(rep);
558

559 560 561
	if (session_done())
		return 0;

562
	if (nr_samples == 0) {
563
		ui__error("The %s file has no samples!\n", file->path);
564
		return 0;
565 566
	}

567
	evlist__for_each(session->evlist, pos)
568 569
		hists__output_resort(&pos->hists);

570
	return report__browse_hists(rep);
571 572
}

573
static int
574
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
575
{
576
	struct report *rep = (struct report *)opt->value;
577
	char *tok, *tok2;
578 579
	char *endptr;

580 581 582 583
	/*
	 * --no-call-graph
	 */
	if (unset) {
584
		rep->dont_use_callchains = true;
585 586 587
		return 0;
	}

588
	symbol_conf.use_callchain = true;
589 590 591 592

	if (!arg)
		return 0;

593 594 595 596 597 598
	tok = strtok((char *)arg, ",");
	if (!tok)
		return -1;

	/* get the output mode */
	if (!strncmp(tok, "graph", strlen(arg)))
599
		callchain_param.mode = CHAIN_GRAPH_ABS;
600

601
	else if (!strncmp(tok, "flat", strlen(arg)))
602 603 604 605 606
		callchain_param.mode = CHAIN_FLAT;

	else if (!strncmp(tok, "fractal", strlen(arg)))
		callchain_param.mode = CHAIN_GRAPH_REL;

607 608
	else if (!strncmp(tok, "none", strlen(arg))) {
		callchain_param.mode = CHAIN_NONE;
609
		symbol_conf.use_callchain = false;
610 611 612 613

		return 0;
	}

614 615 616
	else
		return -1;

617 618 619
	/* get the min percentage */
	tok = strtok(NULL, ",");
	if (!tok)
620
		goto setup;
621

622
	callchain_param.min_percent = strtod(tok, &endptr);
623 624 625
	if (tok == endptr)
		return -1;

626 627 628 629 630 631
	/* get the print limit */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;

	if (tok2[0] != 'c') {
632
		callchain_param.print_limit = strtoul(tok2, &endptr, 0);
633 634 635 636 637 638
		tok2 = strtok(NULL, ",");
		if (!tok2)
			goto setup;
	}

	/* get the call chain order */
639
	if (!strncmp(tok2, "caller", strlen("caller")))
640
		callchain_param.order = ORDER_CALLER;
641
	else if (!strncmp(tok2, "callee", strlen("callee")))
642 643 644
		callchain_param.order = ORDER_CALLEE;
	else
		return -1;
645 646 647 648 649 650 651 652 653 654 655

	/* Get the sort key */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;
	if (!strncmp(tok2, "function", strlen("function")))
		callchain_param.key = CCKEY_FUNCTION;
	else if (!strncmp(tok2, "address", strlen("address")))
		callchain_param.key = CCKEY_ADDRESS;
	else
		return -1;
656
setup:
657
	if (callchain_register_param(&callchain_param) < 0) {
658
		pr_err("Can't register callchain params\n");
659 660
		return -1;
	}
661 662 663
	return 0;
}

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
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;
}

682
static int
683 684
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
685
{
686 687 688
	int *branch_mode = opt->value;

	*branch_mode = !unset;
689 690 691
	return 0;
}

692 693 694 695
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
696
	struct report *rep = opt->value;
697 698 699 700 701

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

702
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
703
{
704
	struct perf_session *session;
705
	struct stat st;
706
	bool has_br_stack = false;
707
	int branch_mode = -1;
708
	int ret = -1;
709 710
	char callchain_default_opt[] = "fractal,0.5,callee";
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
711
		"perf report [<options>]",
712 713
		NULL
	};
714
	struct report report = {
715
		.tool = {
716 717
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
718
			.mmap2		 = perf_event__process_mmap2,
719
			.comm		 = perf_event__process_comm,
720 721
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
722 723 724 725 726 727 728 729
			.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,
		},
730
		.max_stack		 = PERF_MAX_STACK_DEPTH,
731 732 733
		.pretty_printing_style	 = "normal",
	};
	const struct option options[] = {
734
	OPT_STRING('i', "input", &input_name, "file",
735
		    "input file name"),
736
	OPT_INCR('v', "verbose", &verbose,
737
		    "be more verbose (show symbol address, etc)"),
738 739
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
740 741
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
742 743
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
744
	OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
745
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
746
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
747
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
748
		    "Show a column with the number of samples"),
749
	OPT_BOOLEAN('T', "threads", &report.show_threads,
750
		    "Show per-thread event counters"),
751
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
752
		   "pretty printing style key: normal raw"),
753
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
754
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
755 756
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
757 758 759
	OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
	OPT_BOOLEAN(0, "header-only", &report.header_only,
		    "Show only data header."),
760
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
761
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
762
		   " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
763
		   " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
764
		   "snoop, locked, abort, in_tx, transaction"),
765 766
	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes"),
767 768
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
769
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
770
		    "Only display entries with parent-match"),
771
	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
772 773
		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
		     "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
774 775 776 777
	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)),
778 779
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
780 781 782
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
783
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
784
		   "only consider symbols in these dsos"),
785
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
786
		   "only consider symbols in these comms"),
787
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
788
		   "only consider these symbols"),
789 790
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
791
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
792 793
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
794
	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
795 796
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
797
	OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
798
		    "Only display entries resolved to a symbol"),
799 800
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
801
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
802 803
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
804
		    "Display extended information about perf.data file"),
805 806 807 808
	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)"),
809 810
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
811 812
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
N
Namhyung Kim 已提交
813 814
	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
		    "Show event group information together"),
815
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
816
		    "use branch records for histogram filling", parse_branch_mode),
817 818
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
819 820
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
821
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
822 823
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
824
	OPT_END()
825
	};
826 827 828
	struct perf_data_file file = {
		.mode  = PERF_DATA_MODE_READ,
	};
829

830
	perf_config(report__config, &report);
831

832 833
	argc = parse_options(argc, argv, options, report_usage, 0);

834
	if (report.use_stdio)
835
		use_browser = 0;
836
	else if (report.use_tui)
837
		use_browser = 1;
838 839
	else if (report.use_gtk)
		use_browser = 2;
840

841
	if (report.inverted_callchain)
842 843
		callchain_param.order = ORDER_CALLER;

844
	if (!input_name || !strlen(input_name)) {
845
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
846
			input_name = "-";
847
		else
848
			input_name = "perf.data";
849
	}
850

851 852 853
	file.path  = input_name;
	file.force = report.force;

854
repeat:
855
	session = perf_session__new(&file, false, &report.tool);
856 857 858 859 860 861 862
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

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

864 865
	if (branch_mode == -1 && has_br_stack)
		sort__mode = SORT_MODE__BRANCH;
866

867 868
	/* sort__mode could be NORMAL if --no-branch-stack */
	if (sort__mode == SORT_MODE__BRANCH) {
869
		/*
870 871
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
872 873 874 875 876
		 */
		if (sort_order == default_sort_order)
			sort_order = "comm,dso_from,symbol_from,"
				     "dso_to,symbol_to";

877
	}
878
	if (report.mem_mode) {
879
		if (sort__mode == SORT_MODE__BRANCH) {
880
			pr_err("branch and mem mode incompatible\n");
881 882
			goto error;
		}
883 884
		sort__mode = SORT_MODE__MEMORY;

885 886 887 888 889 890 891
		/*
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
		 */
		if (sort_order == default_sort_order)
			sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
	}
892

893 894 895 896
	if (setup_sorting() < 0) {
		parse_options_usage(report_usage, options, "s", 1);
		goto error;
	}
897

898 899 900 901 902
	if (parent_pattern != default_parent_pattern) {
		if (sort_dimension__add("parent") < 0)
			goto error;
	}

903 904 905 906
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

907 908 909 910 911 912 913
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
	else {
		use_browser = 0;
		perf_hpp__init();
	}

914 915 916 917 918 919 920 921 922 923
	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);
	}

924
	/*
925
	 * Only in the TUI browser we are doing integrated annotation,
926 927 928
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
929
	if (use_browser == 1 && sort__has_sym) {
930
		symbol_conf.priv_size = sizeof(struct annotation);
931 932
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
		/*
 		 * 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;
		}
	}
949

950
	if (symbol__init() < 0)
951
		goto error;
952

953 954 955 956 957 958 959 960 961 962
	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];
	}
963

964
	sort__setup_elide(stdout);
965

966
	ret = __cmd_report(&report);
967 968 969 970 971 972
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

973 974 975
error:
	perf_session__delete(session);
	return ret;
976
}