builtin-report.c 27.0 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 "arch/common.h"
37

38 39
#include <linux/bitmap.h>

40
struct perf_report {
41
	struct perf_tool	tool;
42
	struct perf_session	*session;
43
	bool			force, use_tui, use_gtk, use_stdio;
44 45 46 47 48
	bool			hide_unresolved;
	bool			dont_use_callchains;
	bool			show_full_info;
	bool			show_threads;
	bool			inverted_callchain;
49
	bool			mem_mode;
50 51 52 53
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	symbol_filter_t		annotate_init;
	const char		*cpu_list;
54
	const char		*symbol_filter_str;
55
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
56
};
57

58 59 60 61 62 63 64 65 66 67
static int perf_report_config(const char *var, const char *value, void *cb)
{
	if (!strcmp(var, "report.group")) {
		symbol_conf.event_group = perf_config_bool(var, value);
		return 0;
	}

	return perf_default_config(var, value, cb);
}

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
					   struct addr_location *al,
					   struct perf_sample *sample,
					   struct perf_evsel *evsel,
					   struct machine *machine,
					   union perf_event *event)
{
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
	struct symbol *parent = NULL;
	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
	int err = 0;
	struct hist_entry *he;
	struct mem_info *mi, *mx;
	uint64_t cost;

	if ((sort__has_parent || symbol_conf.use_callchain) &&
	    sample->callchain) {
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample, &parent);
		if (err)
			return err;
	}

	mi = machine__resolve_mem(machine, al->thread, sample, cpumode);
	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.
	 */
	he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost);
	if (!he)
		return -ENOMEM;

	/*
114
	 * In the TUI browser, we are doing integrated annotation,
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	 * so we don't allocate the extra space needed because the stdio
	 * code will not use it.
	 */
	if (sort__has_sym && he->ms.sym && use_browser > 0) {
		struct annotation *notes = symbol__annotation(he->ms.sym);

		assert(evsel != NULL);

		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
			goto out;

		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
		if (err)
			goto out;
	}

	if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
		struct annotation *notes;

		mx = he->mem_info;

		notes = symbol__annotation(mx->daddr.sym);
		if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
			goto out;

		err = symbol__inc_addr_samples(mx->daddr.sym,
					       mx->daddr.map,
					       evsel->idx,
					       mx->daddr.al_addr);
		if (err)
			goto out;
	}

	evsel->hists.stats.total_period += cost;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
	err = 0;

	if (symbol_conf.use_callchain) {
		err = callchain_append(he->callchain,
				       &callchain_cursor,
				       sample->period);
	}
out:
	return err;
}

161 162 163 164 165 166 167 168 169 170 171
static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
					struct addr_location *al,
					struct perf_sample *sample,
					struct perf_evsel *evsel,
				      struct machine *machine)
{
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
	struct symbol *parent = NULL;
	int err = 0;
	unsigned i;
	struct hist_entry *he;
172
	struct branch_info *bi, *bx;
173 174 175

	if ((sort__has_parent || symbol_conf.use_callchain)
	    && sample->callchain) {
176 177
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample, &parent);
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
		if (err)
			return err;
	}

	bi = machine__resolve_bstack(machine, al->thread,
				     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;
		/*
		 * The report shows the percentage of total branches captured
		 * and not events sampled. Thus we use a pseudo period of 1.
		 */
		he = __hists__add_branch_entry(&evsel->hists, al, parent,
195
				&bi[i], 1, 1);
196
		if (he) {
197 198 199
			struct annotation *notes;
			err = -ENOMEM;
			bx = he->branch_info;
200
			if (bx->from.sym && use_browser == 1 && sort__has_sym) {
201 202 203 204 205 206 207 208 209 210 211 212 213
				notes = symbol__annotation(bx->from.sym);
				if (!notes->src
				    && symbol__alloc_hist(bx->from.sym) < 0)
					goto out;

				err = symbol__inc_addr_samples(bx->from.sym,
							       bx->from.map,
							       evsel->idx,
							       bx->from.al_addr);
				if (err)
					goto out;
			}

214
			if (bx->to.sym && use_browser == 1 && sort__has_sym) {
215 216 217 218 219 220 221 222 223 224 225 226
				notes = symbol__annotation(bx->to.sym);
				if (!notes->src
				    && symbol__alloc_hist(bx->to.sym) < 0)
					goto out;

				err = symbol__inc_addr_samples(bx->to.sym,
							       bx->to.map,
							       evsel->idx,
							       bx->to.al_addr);
				if (err)
					goto out;
			}
227 228
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
229
			err = 0;
230 231 232
		} else
			return -ENOMEM;
	}
233
out:
234 235 236
	return err;
}

237 238 239 240
static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
				      struct addr_location *al,
				      struct perf_sample *sample,
				      struct machine *machine)
241
{
242
	struct symbol *parent = NULL;
243
	int err = 0;
244 245
	struct hist_entry *he;

246
	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
247 248
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample, &parent);
249 250
		if (err)
			return err;
251
	}
252

253 254
	he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
					sample->weight);
255
	if (he == NULL)
256 257
		return -ENOMEM;

258
	if (symbol_conf.use_callchain) {
259
		err = callchain_append(he->callchain,
260
				       &callchain_cursor,
261
				       sample->period);
262
		if (err)
263
			return err;
264 265
	}
	/*
266
	 * Only in the TUI browser we are doing integrated annotation,
267 268 269
	 * so we don't allocated the extra space needed because the stdio
	 * code will not use it.
	 */
270
	if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
271
		struct annotation *notes = symbol__annotation(he->ms.sym);
272 273 274 275

		assert(evsel != NULL);

		err = -ENOMEM;
276
		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
277 278 279
			goto out;

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

282 283 284
	evsel->hists.stats.total_period += sample->period;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
out:
285
	return err;
286 287
}

288

289
static int process_sample_event(struct perf_tool *tool,
290
				union perf_event *event,
291
				struct perf_sample *sample,
292
				struct perf_evsel *evsel,
293
				struct machine *machine)
294
{
295
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
296
	struct addr_location al;
297

298
	if (perf_event__preprocess_sample(event, machine, &al, sample,
299
					  rep->annotate_init) < 0) {
300
		fprintf(stderr, "problem processing %d event, skipping it.\n",
301 302 303
			event->header.type);
		return -1;
	}
304

305
	if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
306
		return 0;
307

308
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
309 310
		return 0;

311
	if (sort__branch_mode == 1) {
312 313 314 315 316
		if (perf_report__add_branch_hist_entry(tool, &al, sample,
						       evsel, machine)) {
			pr_debug("problem adding lbr entry, skipping event\n");
			return -1;
		}
317 318 319 320 321 322
	} else if (rep->mem_mode == 1) {
		if (perf_report__add_mem_hist_entry(tool, &al, sample,
						    evsel, machine, event)) {
			pr_debug("problem adding mem entry, skipping event\n");
			return -1;
		}
323 324 325
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
326

327 328 329 330
		if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
			pr_debug("problem incrementing symbol period, skipping event\n");
			return -1;
		}
331
	}
332 333
	return 0;
}
I
Ingo Molnar 已提交
334

335
static int process_read_event(struct perf_tool *tool,
336
			      union perf_event *event,
337
			      struct perf_sample *sample __maybe_unused,
338
			      struct perf_evsel *evsel,
339
			      struct machine *machine __maybe_unused)
340
{
341
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
342

343
	if (rep->show_threads) {
344
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
345
		perf_read_values_add_value(&rep->show_threads_values,
346 347 348 349 350 351
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

352
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
353
		    evsel ? perf_evsel__name(evsel) : "FAIL",
354
		    event->read.value);
355 356 357 358

	return 0;
}

359
/* For pipe mode, sample_type is not currently set */
360
static int perf_report__setup_sample_type(struct perf_report *rep)
361
{
362
	struct perf_session *self = rep->session;
363
	u64 sample_type = perf_evlist__sample_type(self->evlist);
364

365
	if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
366
		if (sort__has_parent) {
367
			ui__error("Selected --sort parent, but no "
368 369
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
370
			return -EINVAL;
371
		}
372
		if (symbol_conf.use_callchain) {
373
			ui__error("Selected -g but no callchain data. Did "
374
				    "you call 'perf record' without -g?\n");
375
			return -1;
376
		}
377 378
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
379
		   !symbol_conf.use_callchain) {
380
			symbol_conf.use_callchain = true;
381
			if (callchain_register_param(&callchain_param) < 0) {
382
				ui__error("Can't register callchain params.\n");
383
				return -EINVAL;
384
			}
385 386
	}

387
	if (sort__branch_mode == 1) {
388
		if (!self->fd_pipe &&
389
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
390 391
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
392 393 394 395
			return -1;
		}
	}

396 397
	return 0;
}
398

399 400
extern volatile int session_done;

401
static void sig_handler(int sig __maybe_unused)
402 403 404 405
{
	session_done = 1;
}

406 407
static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
					      struct hists *self,
408 409 410 411
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
412 413
	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
	u64 nr_events = self->stats.total_period;
414 415 416 417
	struct perf_evsel *evsel = hists_to_evsel(self);
	char buf[512];
	size_t size = sizeof(buf);

418
	if (perf_evsel__is_group_event(evsel)) {
419 420 421 422 423 424 425 426 427 428
		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;
		}
	}
429

430 431
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
432
	if (evname != NULL)
433 434
		ret += fprintf(fp, " of event '%s'", evname);

435 436 437 438 439
	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);
440 441 442
	return ret + fprintf(fp, "\n#\n");
}

443
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
444
					 struct perf_report *rep,
445
					 const char *help)
446
{
447
	struct perf_evsel *pos;
448

449 450
	list_for_each_entry(pos, &evlist->entries, node) {
		struct hists *hists = &pos->hists;
451
		const char *evname = perf_evsel__name(pos);
452

453 454 455 456
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

457
		hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
458
		hists__fprintf(hists, true, 0, 0, stdout);
459 460 461 462 463 464 465
		fprintf(stdout, "\n\n");
	}

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

466 467 468
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
469
						 style);
470
			perf_read_values_destroy(&rep->show_threads_values);
471 472 473 474 475 476
		}
	}

	return 0;
}

477
static int __cmd_report(struct perf_report *rep)
478
{
479
	int ret = -EINVAL;
480
	u64 nr_samples;
481
	struct perf_session *session = rep->session;
482
	struct perf_evsel *pos;
483 484
	struct map *kernel_map;
	struct kmap *kernel_kmap;
485
	const char *help = "For a higher level overview, try: perf report --sort comm,dso";
486

487 488
	signal(SIGINT, sig_handler);

489 490 491
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
492 493 494 495
		if (ret)
			goto out_delete;
	}

496
	if (use_browser <= 0)
497
		perf_session__fprintf_info(session, stdout, rep->show_full_info);
498

499 500
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
501

502
	ret = perf_report__setup_sample_type(rep);
503 504 505
	if (ret)
		goto out_delete;

506
	ret = perf_session__process_events(session, &rep->tool);
507
	if (ret)
508
		goto out_delete;
509

510
	kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
511 512 513 514 515
	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))) {
516 517 518 519 520 521 522 523 524 525 526
		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.";
			}
		}
527

528 529 530 531
		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",
532
		desc);
533 534
	}

535
	if (verbose > 3)
536
		perf_session__fprintf(session, stdout);
537

538
	if (verbose > 2)
539
		perf_session__fprintf_dsos(session, stdout);
540

541 542 543 544 545
	if (dump_trace) {
		perf_session__fprintf_nr_events(session, stdout);
		goto out_delete;
	}

546 547 548
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node) {
		struct hists *hists = &pos->hists;
549

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

553
		hists__collapse_resort(hists);
554
		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
555 556 557 558 559 560 561 562 563

		/* 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);
		}
564 565 566
	}

	if (nr_samples == 0) {
567
		ui__error("The %s file has no samples!\n", session->filename);
568
		goto out_delete;
569 570
	}

571 572 573
	list_for_each_entry(pos, &session->evlist->entries, node)
		hists__output_resort(&pos->hists);

574
	if (use_browser > 0) {
575
		if (use_browser == 1) {
576 577 578 579 580 581 582 583 584 585 586
			ret = perf_evlist__tui_browse_hists(session->evlist,
							help,
							NULL,
							&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;

587 588
		} else if (use_browser == 2) {
			perf_evlist__gtk_browse_hists(session->evlist, help,
589
						      NULL);
590
		}
591
	} else
592
		perf_evlist__tty_browse_hists(session->evlist, rep, help);
593

594
out_delete:
595 596 597 598 599 600 601 602 603 604 605 606
	/*
	 * Speed up the exit process, for large files this can
	 * take quite a while.
	 *
	 * XXX Enable this when using valgrind or if we ever
	 * librarize this command.
	 *
	 * Also experiment with obstacks to see how much speed
	 * up we'll get here.
	 *
 	 * perf_session__delete(session);
 	 */
607
	return ret;
608 609
}

610
static int
611
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
612
{
613
	struct perf_report *rep = (struct perf_report *)opt->value;
614
	char *tok, *tok2;
615 616
	char *endptr;

617 618 619 620
	/*
	 * --no-call-graph
	 */
	if (unset) {
621
		rep->dont_use_callchains = true;
622 623 624
		return 0;
	}

625
	symbol_conf.use_callchain = true;
626 627 628 629

	if (!arg)
		return 0;

630 631 632 633 634 635
	tok = strtok((char *)arg, ",");
	if (!tok)
		return -1;

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

638
	else if (!strncmp(tok, "flat", strlen(arg)))
639 640 641 642 643
		callchain_param.mode = CHAIN_FLAT;

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

644 645
	else if (!strncmp(tok, "none", strlen(arg))) {
		callchain_param.mode = CHAIN_NONE;
646
		symbol_conf.use_callchain = false;
647 648 649 650

		return 0;
	}

651 652 653
	else
		return -1;

654 655 656
	/* get the min percentage */
	tok = strtok(NULL, ",");
	if (!tok)
657
		goto setup;
658

659
	callchain_param.min_percent = strtod(tok, &endptr);
660 661 662
	if (tok == endptr)
		return -1;

663 664 665 666 667 668
	/* get the print limit */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;

	if (tok2[0] != 'c') {
669
		callchain_param.print_limit = strtoul(tok2, &endptr, 0);
670 671 672 673 674 675 676 677 678 679 680 681
		tok2 = strtok(NULL, ",");
		if (!tok2)
			goto setup;
	}

	/* get the call chain order */
	if (!strcmp(tok2, "caller"))
		callchain_param.order = ORDER_CALLER;
	else if (!strcmp(tok2, "callee"))
		callchain_param.order = ORDER_CALLEE;
	else
		return -1;
682
setup:
683
	if (callchain_register_param(&callchain_param) < 0) {
684 685 686
		fprintf(stderr, "Can't register callchain params\n");
		return -1;
	}
687 688 689
	return 0;
}

690
static int
691 692
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
693 694 695 696 697
{
	sort__branch_mode = !unset;
	return 0;
}

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

809 810
	perf_config(perf_report_config, NULL);

811 812
	argc = parse_options(argc, argv, options, report_usage, 0);

813
	if (report.use_stdio)
814
		use_browser = 0;
815
	else if (report.use_tui)
816
		use_browser = 1;
817 818
	else if (report.use_gtk)
		use_browser = 2;
819

820
	if (report.inverted_callchain)
821 822
		callchain_param.order = ORDER_CALLER;

823
	if (!input_name || !strlen(input_name)) {
824
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
825
			input_name = "-";
826
		else
827
			input_name = "perf.data";
828
	}
829 830 831 832 833 834 835 836 837 838

	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
	else {
		use_browser = 0;
		perf_hpp__column_enable(PERF_HPP__OVERHEAD);
		perf_hpp__init();
	}

repeat:
839
	session = perf_session__new(input_name, O_RDONLY,
840 841 842 843 844 845 846 847
				    report.force, false, &report.tool);
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

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

849 850 851
	if (sort__branch_mode == -1 && has_br_stack)
		sort__branch_mode = 1;

852
	/* sort__branch_mode could be 0 if --no-branch-stack */
853
	if (sort__branch_mode == 1) {
854
		/*
855 856
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
857 858 859 860 861
		 */
		if (sort_order == default_sort_order)
			sort_order = "comm,dso_from,symbol_from,"
				     "dso_to,symbol_to";

862
	}
863 864 865 866 867 868 869 870 871 872 873 874
	if (report.mem_mode) {
		if (sort__branch_mode == 1) {
			fprintf(stderr, "branch and mem mode incompatible\n");
			goto error;
		}
		/*
		 * 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";
	}
875

876 877
	if (setup_sorting() < 0)
		usage_with_options(report_usage, options);
878

879
	/*
880
	 * Only in the TUI browser we are doing integrated annotation,
881 882 883
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
884
	if (use_browser == 1 && sort__has_sym) {
885
		symbol_conf.priv_size = sizeof(struct annotation);
886
		report.annotate_init  = symbol__annotate_init;
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
		/*
 		 * 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;
		}
	}
903

904
	if (symbol__init() < 0)
905
		goto error;
906

907
	if (parent_pattern != default_parent_pattern) {
908
		if (sort_dimension__add("parent") < 0)
909
			goto error;
910 911 912 913 914 915 916 917

		/*
		 * Only show the parent fields if we explicitly
		 * sort that way. If we only use parent machinery
		 * for filtering, we don't want it.
		 */
		if (!strstr(sort_order, "parent"))
			sort_parent.elide = 1;
918
	} else
919
		symbol_conf.exclude_other = false;
920

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

932
	sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
933 934 935 936 937 938 939

	if (sort__branch_mode == 1) {
		sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
		sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
		sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
		sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
	} else {
940 941 942 943 944 945 946 947
		if (report.mem_mode) {
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
			sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
		}
948 949 950
		sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
		sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
	}
951

952
	ret = __cmd_report(&report);
953 954 955 956 957 958
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

959 960 961
error:
	perf_session__delete(session);
	return ret;
962
}