builtin-report.c 26.4 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
	float			min_percent;
56
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
57
};
58

59 60 61 62 63 64 65 66 67 68
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);
}

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 114
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;

	/*
115
	 * In the TUI browser, we are doing integrated annotation,
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 161
	 * 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;
}

162 163 164 165 166 167 168 169 170 171 172
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;
173
	struct branch_info *bi, *bx;
174 175 176

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

		err = -ENOMEM;

194 195 196 197 198
		/*
		 * 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,
199
				&bi[i], 1, 1);
200
		if (he) {
201 202
			struct annotation *notes;
			bx = he->branch_info;
203
			if (bx->from.sym && use_browser == 1 && sort__has_sym) {
204 205 206 207 208 209 210 211 212 213 214 215 216
				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;
			}

217
			if (bx->to.sym && use_browser == 1 && sort__has_sym) {
218 219 220 221 222 223 224 225 226 227 228 229
				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;
			}
230 231 232
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
		} else
233
			goto out;
234
	}
235
	err = 0;
236
out:
237
	free(bi);
238 239 240
	return err;
}

241 242 243 244
static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
				      struct addr_location *al,
				      struct perf_sample *sample,
				      struct machine *machine)
245
{
246
	struct symbol *parent = NULL;
247
	int err = 0;
248 249
	struct hist_entry *he;

250
	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
251 252
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample, &parent);
253 254
		if (err)
			return err;
255
	}
256

257 258
	he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
					sample->weight);
259
	if (he == NULL)
260 261
		return -ENOMEM;

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

		assert(evsel != NULL);

		err = -ENOMEM;
280
		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
281 282 283
			goto out;

		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
284
	}
285

286 287 288
	evsel->hists.stats.total_period += sample->period;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
out:
289
	return err;
290 291
}

292

293
static int process_sample_event(struct perf_tool *tool,
294
				union perf_event *event,
295
				struct perf_sample *sample,
296
				struct perf_evsel *evsel,
297
				struct machine *machine)
298
{
299
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
300
	struct addr_location al;
301
	int ret;
302

303
	if (perf_event__preprocess_sample(event, machine, &al, sample,
304
					  rep->annotate_init) < 0) {
305
		fprintf(stderr, "problem processing %d event, skipping it.\n",
306 307 308
			event->header.type);
		return -1;
	}
309

310
	if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
311
		return 0;
312

313
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
314 315
		return 0;

316
	if (sort__mode == SORT_MODE__BRANCH) {
317 318 319
		ret = perf_report__add_branch_hist_entry(tool, &al, sample,
							 evsel, machine);
		if (ret < 0)
320
			pr_debug("problem adding lbr entry, skipping event\n");
321
	} else if (rep->mem_mode == 1) {
322 323 324
		ret = perf_report__add_mem_hist_entry(tool, &al, sample,
						      evsel, machine, event);
		if (ret < 0)
325
			pr_debug("problem adding mem entry, skipping event\n");
326 327 328
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
329

330 331
		ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
		if (ret < 0)
332
			pr_debug("problem incrementing symbol period, skipping event\n");
333
	}
334
	return ret;
335
}
I
Ingo Molnar 已提交
336

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

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

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

	return 0;
}

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

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

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

398 399
	return 0;
}
400

401 402
extern volatile int session_done;

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

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

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

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

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

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

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

455 456 457 458
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

459
		hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
460
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
461 462 463 464 465 466 467
		fprintf(stdout, "\n\n");
	}

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

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

	return 0;
}

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

489 490
	signal(SIGINT, sig_handler);

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

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

501 502
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
503

504
	ret = perf_report__setup_sample_type(rep);
505 506 507
	if (ret)
		goto out_delete;

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

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

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

537
	if (verbose > 3)
538
		perf_session__fprintf(session, stdout);
539

540
	if (verbose > 2)
541
		perf_session__fprintf_dsos(session, stdout);
542

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

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

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

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

		/* 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);
		}
566 567 568
	}

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

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

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

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

596
out_delete:
597 598 599 600 601 602 603 604 605 606 607 608
	/*
	 * 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);
 	 */
609
	return ret;
610 611
}

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

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

627
	symbol_conf.use_callchain = true;
628 629 630 631

	if (!arg)
		return 0;

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

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

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

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

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

		return 0;
	}

653 654 655
	else
		return -1;

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

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

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

	if (tok2[0] != 'c') {
671
		callchain_param.print_limit = strtoul(tok2, &endptr, 0);
672 673 674 675 676 677 678 679 680 681 682 683
		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;
684
setup:
685
	if (callchain_register_param(&callchain_param) < 0) {
686 687 688
		fprintf(stderr, "Can't register callchain params\n");
		return -1;
	}
689 690 691
	return 0;
}

692
static int
693 694
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
695
{
696 697 698
	int *branch_mode = opt->value;

	*branch_mode = !unset;
699 700 701
	return 0;
}

702 703 704 705 706 707 708 709 710 711
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
	struct perf_report *rep = opt->value;

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

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

826 827
	perf_config(perf_report_config, NULL);

828 829
	argc = parse_options(argc, argv, options, report_usage, 0);

830
	if (report.use_stdio)
831
		use_browser = 0;
832
	else if (report.use_tui)
833
		use_browser = 1;
834 835
	else if (report.use_gtk)
		use_browser = 2;
836

837
	if (report.inverted_callchain)
838 839
		callchain_param.order = ORDER_CALLER;

840
	if (!input_name || !strlen(input_name)) {
841
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
842
			input_name = "-";
843
		else
844
			input_name = "perf.data";
845
	}
846 847 848 849 850 851 852 853 854 855

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

repeat:
856
	session = perf_session__new(input_name, O_RDONLY,
857 858 859 860 861 862 863 864
				    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);
865

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

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

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

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

895 896
	if (setup_sorting() < 0)
		usage_with_options(report_usage, options);
897

898
	/*
899
	 * Only in the TUI browser we are doing integrated annotation,
900 901 902
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
903
	if (use_browser == 1 && sort__has_sym) {
904
		symbol_conf.priv_size = sizeof(struct annotation);
905
		report.annotate_init  = symbol__annotate_init;
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
		/*
 		 * 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;
		}
	}
922

923
	if (symbol__init() < 0)
924
		goto error;
925

926
	if (parent_pattern != default_parent_pattern) {
927
		if (sort_dimension__add("parent") < 0)
928
			goto error;
929 930 931 932 933 934 935 936

		/*
		 * 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;
937
	} else
938
		symbol_conf.exclude_other = false;
939

940 941 942 943 944 945 946 947 948 949
	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];
	}
950

951
	sort__setup_elide(stdout);
952

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

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