builtin-report.c 27.1 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
static int report__resolve_callchain(struct report *rep, struct symbol **parent,
79
				     struct perf_evsel *evsel, struct addr_location *al,
80
				     struct perf_sample *sample)
81 82
{
	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
83
		return machine__resolve_callchain(al->machine, evsel, al->thread, sample,
84 85 86 87 88 89 90 91 92 93 94 95
						  parent, al, rep->max_stack);
	}
	return 0;
}

static int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
{
	if (!symbol_conf.use_callchain)
		return 0;
	return callchain_append(he->callchain, &callchain_cursor, sample->period);
}

96 97
static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
				      struct perf_sample *sample, struct perf_evsel *evsel,
98
				      union perf_event *event)
99
{
100
	struct report *rep = container_of(tool, struct report, tool);
101 102 103 104 105
	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;
106
	int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
107

108 109
	if (err)
		return err;
110

111
	mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	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.
	 */
129 130
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
				cost, cost, 0);
131 132 133
	if (!he)
		return -ENOMEM;

134 135 136
	err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
	if (err)
		goto out;
137

138
	mx = he->mem_info;
139
	err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
140 141
	if (err)
		goto out;
142 143 144

	evsel->hists.stats.total_period += cost;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
145
	err = hist_entry__append_callchain(he, sample);
146 147 148 149
out:
	return err;
}

150
static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
151
					 struct perf_sample *sample, struct perf_evsel *evsel)
152
{
153
	struct report *rep = container_of(tool, struct report, tool);
154 155 156
	struct symbol *parent = NULL;
	unsigned i;
	struct hist_entry *he;
157
	struct branch_info *bi, *bx;
158
	int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
159

160 161
	if (err)
		return err;
162

163
	bi = machine__resolve_bstack(al->machine, al->thread,
164 165 166 167 168 169 170
				     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;
171 172 173

		err = -ENOMEM;

174 175 176 177
		/* 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;
178 179 180 181
		/*
		 * The report shows the percentage of total branches captured
		 * and not events sampled. Thus we use a pseudo period of 1.
		 */
182 183
		he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
					1, 1, 0);
184
		if (he) {
185
			bx = he->branch_info;
186
			err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
187 188 189
			if (err)
				goto out;

190
			err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
191 192 193
			if (err)
				goto out;

194 195 196
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
		} else
197
			goto out;
198
	}
199
	err = 0;
200
out:
201
	free(bi);
202 203 204
	return err;
}

205
static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
206
				  struct addr_location *al, struct perf_sample *sample)
207
{
208
	struct report *rep = container_of(tool, struct report, tool);
209
	struct symbol *parent = NULL;
210
	struct hist_entry *he;
211
	int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
212

213 214
	if (err)
		return err;
215

216 217 218
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
				sample->period, sample->weight,
				sample->transaction);
219
	if (he == NULL)
220 221
		return -ENOMEM;

222 223 224
	err = hist_entry__append_callchain(he, sample);
	if (err)
		goto out;
225

226
	err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
227 228
	evsel->hists.stats.total_period += sample->period;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
229
out:
230
	return err;
231 232
}

233

234
static int process_sample_event(struct perf_tool *tool,
235
				union perf_event *event,
236
				struct perf_sample *sample,
237
				struct perf_evsel *evsel,
238
				struct machine *machine)
239
{
240
	struct report *rep = container_of(tool, struct report, tool);
241
	struct addr_location al;
242
	int ret;
243

244
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
245 246
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
247 248
		return -1;
	}
249

250
	if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
251
		return 0;
252

253
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
254 255
		return 0;

256
	if (sort__mode == SORT_MODE__BRANCH) {
257
		ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
258
		if (ret < 0)
259
			pr_debug("problem adding lbr entry, skipping event\n");
260
	} else if (rep->mem_mode == 1) {
261
		ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
262
		if (ret < 0)
263
			pr_debug("problem adding mem entry, skipping event\n");
264 265 266
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
267

268
		ret = report__add_hist_entry(tool, evsel, &al, sample);
269
		if (ret < 0)
270
			pr_debug("problem incrementing symbol period, skipping event\n");
271
	}
272
	return ret;
273
}
I
Ingo Molnar 已提交
274

275
static int process_read_event(struct perf_tool *tool,
276
			      union perf_event *event,
277
			      struct perf_sample *sample __maybe_unused,
278
			      struct perf_evsel *evsel,
279
			      struct machine *machine __maybe_unused)
280
{
281
	struct report *rep = container_of(tool, struct report, tool);
282

283
	if (rep->show_threads) {
284
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
285
		perf_read_values_add_value(&rep->show_threads_values,
286 287 288 289 290 291
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

292
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
293
		    evsel ? perf_evsel__name(evsel) : "FAIL",
294
		    event->read.value);
295 296 297 298

	return 0;
}

299
/* For pipe mode, sample_type is not currently set */
300
static int report__setup_sample_type(struct report *rep)
301
{
302 303 304
	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);
305

306
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
307
		if (sort__has_parent) {
308
			ui__error("Selected --sort parent, but no "
309 310
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
311
			return -EINVAL;
312
		}
313
		if (symbol_conf.use_callchain) {
314
			ui__error("Selected -g but no callchain data. Did "
315
				    "you call 'perf record' without -g?\n");
316
			return -1;
317
		}
318 319
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
320
		   !symbol_conf.use_callchain) {
321
			symbol_conf.use_callchain = true;
322
			if (callchain_register_param(&callchain_param) < 0) {
323
				ui__error("Can't register callchain params.\n");
324
				return -EINVAL;
325
			}
326 327
	}

328
	if (sort__mode == SORT_MODE__BRANCH) {
329
		if (!is_pipe &&
330
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
331 332
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
333 334 335 336
			return -1;
		}
	}

337 338
	return 0;
}
339

340
static void sig_handler(int sig __maybe_unused)
341 342 343 344
{
	session_done = 1;
}

345
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
346 347 348 349
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
350 351 352
	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);
353 354 355
	char buf[512];
	size_t size = sizeof(buf);

356
	if (perf_evsel__is_group_event(evsel)) {
357 358 359 360 361 362 363 364 365 366
		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;
		}
	}
367

368 369
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
370
	if (evname != NULL)
371 372
		ret += fprintf(fp, " of event '%s'", evname);

373 374 375 376 377
	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);
378 379 380
	return ret + fprintf(fp, "\n#\n");
}

381
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
382
					 struct report *rep,
383
					 const char *help)
384
{
385
	struct perf_evsel *pos;
386

387 388
	list_for_each_entry(pos, &evlist->entries, node) {
		struct hists *hists = &pos->hists;
389
		const char *evname = perf_evsel__name(pos);
390

391 392 393 394
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

395
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
396
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
397 398 399 400 401 402 403
		fprintf(stdout, "\n\n");
	}

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

404 405 406
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
407
						 style);
408
			perf_read_values_destroy(&rep->show_threads_values);
409 410 411 412 413 414
		}
	}

	return 0;
}

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

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

489
static int __cmd_report(struct report *rep)
490
{
491
	int ret = -EINVAL;
492
	u64 nr_samples;
493
	struct perf_session *session = rep->session;
494
	struct perf_evsel *pos;
495
	struct ui_progress prog;
496
	struct perf_data_file *file = session->file;
497

498 499
	signal(SIGINT, sig_handler);

500 501 502
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
503
		if (ret)
504
			return ret;
505 506
	}

507 508
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
509

510
	ret = report__setup_sample_type(rep);
511
	if (ret)
512
		return ret;
513

514
	ret = perf_session__process_events(session, &rep->tool);
515
	if (ret)
516
		return ret;
517

518
	report__warn_kptr_restrict(rep);
519

520 521 522
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
523

524 525
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
526

527 528 529 530
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
			return 0;
		}
531 532
	}

533 534 535 536 537 538
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node)
		nr_samples += pos->hists.nr_entries;

	ui_progress__init(&prog, nr_samples, "Merging related events...");

539 540 541
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node) {
		struct hists *hists = &pos->hists;
542

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

546
		hists__collapse_resort(hists, &prog);
547
		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
548 549 550 551 552 553 554 555 556

		/* 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);
		}
557
	}
558
	ui_progress__finish();
559

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

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

568 569 570
	list_for_each_entry(pos, &session->evlist->entries, node)
		hists__output_resort(&pos->hists);

571
	return report__browse_hists(rep);
572 573
}

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

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

589
	symbol_conf.use_callchain = true;
590 591 592 593

	if (!arg)
		return 0;

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

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

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

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

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

		return 0;
	}

615 616 617
	else
		return -1;

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

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

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

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

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

	/* 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;
657
setup:
658
	if (callchain_register_param(&callchain_param) < 0) {
659
		pr_err("Can't register callchain params\n");
660 661
		return -1;
	}
662 663 664
	return 0;
}

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

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

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

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

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

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

831
	perf_config(report__config, &report);
832

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

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

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

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

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

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

	report.session = session;

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

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

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

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

886 887 888 889 890 891 892
		/*
		 * 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";
	}
893

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

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

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

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

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

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

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

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

965
	sort__setup_elide(stdout);
966

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

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