builtin-report.c 31.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 11
#include "util/util.h"

12
#include "util/color.h"
13
#include <linux/list.h>
14
#include "util/cache.h"
15
#include <linux/rbtree.h>
16
#include "util/symbol.h"
17
#include "util/string.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
#include "util/header.h"
25 26 27 28

#include "util/parse-options.h"
#include "util/parse-events.h"

29
#include "util/thread.h"
30
#include "util/sort.h"
31

32
static char		const *input_name = "perf.data";
33

34 35
static char		*dso_list_str, *comm_list_str, *sym_list_str,
			*col_width_list_str;
36
static struct strlist	*dso_list, *comm_list, *sym_list;
37

38
static int		force;
39 40 41
static int		input;
static int		show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;

42
static int		full_paths;
43
static int		show_nr_samples;
44

45 46 47
static int		show_threads;
static struct perf_read_values	show_threads_values;

48 49 50
static char		default_pretty_printing_style[] = "normal";
static char		*pretty_printing_style = default_pretty_printing_style;

51 52 53
static unsigned long	page_size;
static unsigned long	mmap_window = 32;

54
static int		exclude_other = 1;
55

56 57
static char		callchain_default_opt[] = "fractal,0.5";

58
static int		callchain;
59

60 61 62 63
static char		__cwd[PATH_MAX];
static char		*cwd = __cwd;
static int		cwdlen;

64 65 66
static struct rb_root	threads;
static struct thread	*last_match;

67 68
static struct perf_header *header;

69 70
static
struct callchain_param	callchain_param = {
71
	.mode	= CHAIN_GRAPH_REL,
72 73
	.min_percent = 0.5
};
74

75 76
static u64		sample_type;

77 78
static struct rb_root hist;

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
static int64_t
hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
{
	struct sort_entry *se;
	int64_t cmp = 0;

	list_for_each_entry(se, &hist_entry__sort_list, list) {
		cmp = se->cmp(left, right);
		if (cmp)
			break;
	}

	return cmp;
}

P
Peter Zijlstra 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
static int64_t
hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
{
	struct sort_entry *se;
	int64_t cmp = 0;

	list_for_each_entry(se, &hist_entry__sort_list, list) {
		int64_t (*f)(struct hist_entry *, struct hist_entry *);

		f = se->collapse ?: se->cmp;

		cmp = f(left, right);
		if (cmp)
			break;
	}

	return cmp;
}

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
{
	int i;
	size_t ret = 0;

	ret += fprintf(fp, "%s", "                ");

	for (i = 0; i < depth; i++)
		if (depth_mask & (1 << i))
			ret += fprintf(fp, "|          ");
		else
			ret += fprintf(fp, "           ");

	ret += fprintf(fp, "\n");

	return ret;
}
130
static size_t
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
		       int depth_mask, int count, u64 total_samples,
		       int hits)
{
	int i;
	size_t ret = 0;

	ret += fprintf(fp, "%s", "                ");
	for (i = 0; i < depth; i++) {
		if (depth_mask & (1 << i))
			ret += fprintf(fp, "|");
		else
			ret += fprintf(fp, " ");
		if (!count && i == depth - 1) {
			double percent;

			percent = hits * 100.0 / total_samples;
148
			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
149 150 151 152 153 154 155 156 157 158 159
		} else
			ret += fprintf(fp, "%s", "          ");
	}
	if (chain->sym)
		ret += fprintf(fp, "%s\n", chain->sym->name);
	else
		ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);

	return ret;
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
static struct symbol *rem_sq_bracket;
static struct callchain_list rem_hits;

static void init_rem_hits(void)
{
	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
	if (!rem_sq_bracket) {
		fprintf(stderr, "Not enough memory to display remaining hits\n");
		return;
	}

	strcpy(rem_sq_bracket->name, "[...]");
	rem_hits.sym = rem_sq_bracket;
}

175 176 177 178 179 180 181 182
static size_t
callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
			u64 total_samples, int depth, int depth_mask)
{
	struct rb_node *node, *next;
	struct callchain_node *child;
	struct callchain_list *chain;
	int new_depth_mask = depth_mask;
183
	u64 new_total;
184
	u64 remaining;
185 186 187
	size_t ret = 0;
	int i;

188
	if (callchain_param.mode == CHAIN_GRAPH_REL)
189
		new_total = self->children_hit;
190 191 192
	else
		new_total = total_samples;

193 194
	remaining = new_total;

195 196
	node = rb_first(&self->rb_root);
	while (node) {
197 198
		u64 cumul;

199
		child = rb_entry(node, struct callchain_node, rb_node);
200 201
		cumul = cumul_hits(child);
		remaining -= cumul;
202 203 204 205

		/*
		 * The depth mask manages the output of pipes that show
		 * the depth. We don't want to keep the pipes of the current
206 207 208
		 * level for the last child of this depth.
		 * Except if we have remaining filtered hits. They will
		 * supersede the last child
209 210
		 */
		next = rb_next(node);
211
		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
212 213 214 215 216 217 218 219 220 221 222 223 224
			new_depth_mask &= ~(1 << (depth - 1));

		/*
		 * But we keep the older depth mask for the line seperator
		 * to keep the level link until we reach the last child
		 */
		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
		i = 0;
		list_for_each_entry(chain, &child->val, list) {
			if (chain->ip >= PERF_CONTEXT_MAX)
				continue;
			ret += ipchain__fprintf_graph(fp, chain, depth,
						      new_depth_mask, i++,
225
						      new_total,
226
						      cumul);
227
		}
228
		ret += callchain__fprintf_graph(fp, child, new_total,
229 230 231 232 233
						depth + 1,
						new_depth_mask | (1 << depth));
		node = next;
	}

234 235 236 237 238 239 240 241 242 243 244 245 246
	if (callchain_param.mode == CHAIN_GRAPH_REL &&
		remaining && remaining != new_total) {

		if (!rem_sq_bracket)
			return ret;

		new_depth_mask &= ~(1 << (depth - 1));

		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
					      new_depth_mask, 0, new_total,
					      remaining);
	}

247 248 249 250 251 252
	return ret;
}

static size_t
callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
			u64 total_samples)
253 254 255 256 257 258 259
{
	struct callchain_list *chain;
	size_t ret = 0;

	if (!self)
		return 0;

260
	ret += callchain__fprintf_flat(fp, self->parent, total_samples);
261 262


263 264 265 266 267 268 269
	list_for_each_entry(chain, &self->val, list) {
		if (chain->ip >= PERF_CONTEXT_MAX)
			continue;
		if (chain->sym)
			ret += fprintf(fp, "                %s\n", chain->sym->name);
		else
			ret += fprintf(fp, "                %p\n",
270
					(void *)(long)chain->ip);
271
	}
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289

	return ret;
}

static size_t
hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
			      u64 total_samples)
{
	struct rb_node *rb_node;
	struct callchain_node *chain;
	size_t ret = 0;

	rb_node = rb_first(&self->sorted_chain);
	while (rb_node) {
		double percent;

		chain = rb_entry(rb_node, struct callchain_node, rb_node);
		percent = chain->hit * 100.0 / total_samples;
290 291
		switch (callchain_param.mode) {
		case CHAIN_FLAT:
292 293
			ret += percent_color_fprintf(fp, "           %6.2f%%\n",
						     percent);
294
			ret += callchain__fprintf_flat(fp, chain, total_samples);
295 296 297
			break;
		case CHAIN_GRAPH_ABS: /* Falldown */
		case CHAIN_GRAPH_REL:
298 299
			ret += callchain__fprintf_graph(fp, chain,
							total_samples, 1, 1);
300
		case CHAIN_NONE:
301 302
		default:
			break;
303
		}
304 305 306 307 308 309 310 311
		ret += fprintf(fp, "\n");
		rb_node = rb_next(rb_node);
	}

	return ret;
}


312
static size_t
313
hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
314 315 316 317
{
	struct sort_entry *se;
	size_t ret;

318 319 320
	if (exclude_other && !self->parent)
		return 0;

321
	if (total_samples)
322 323 324
		ret = percent_color_fprintf(fp,
					    field_sep ? "%.2f" : "   %6.2f%%",
					(self->count * 100.0) / total_samples);
325
	else
326
		ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
327

328 329 330 331 332 333
	if (show_nr_samples) {
		if (field_sep)
			fprintf(fp, "%c%lld", *field_sep, self->count);
		else
			fprintf(fp, "%11lld", self->count);
	}
334

335
	list_for_each_entry(se, &hist_entry__sort_list, list) {
336
		if (se->elide)
337 338
			continue;

339 340
		fprintf(fp, "%s", field_sep ?: "  ");
		ret += se->print(fp, self, se->width ? *se->width : 0);
341
	}
342 343 344

	ret += fprintf(fp, "\n");

345 346 347
	if (callchain)
		hist_entry_callchain__fprintf(fp, self, total_samples);

348 349 350
	return ret;
}

351 352 353 354
/*
 *
 */

355 356 357 358 359 360 361 362 363 364 365 366
static void dso__calc_col_width(struct dso *self)
{
	if (!col_width_list_str && !field_sep &&
	    (!dso_list || strlist__has_entry(dso_list, self->name))) {
		unsigned int slen = strlen(self->name);
		if (slen > dsos__col_width)
			dsos__col_width = slen;
	}

	self->slen_calculated = 1;
}

367
static void thread__comm_adjust(struct thread *self)
368
{
369
	char *comm = self->comm;
370 371 372 373 374 375 376 377 378 379

	if (!col_width_list_str && !field_sep &&
	    (!comm_list || strlist__has_entry(comm_list, comm))) {
		unsigned int slen = strlen(comm);

		if (slen > comms__col_width) {
			comms__col_width = slen;
			threads__col_width = slen + 6;
		}
	}
380 381 382 383 384 385 386 387 388 389
}

static int thread__set_comm_adjust(struct thread *self, const char *comm)
{
	int ret = thread__set_comm(self, comm);

	if (ret)
		return ret;

	thread__comm_adjust(self);
390 391 392 393 394

	return 0;
}


395 396
static struct symbol *
resolve_symbol(struct thread *thread, struct map **mapp,
397
	       struct dso **dsop, u64 *ipp)
398 399 400
{
	struct dso *dso = dsop ? *dsop : NULL;
	struct map *map = mapp ? *mapp : NULL;
401
	u64 ip = *ipp;
402 403 404 405 406 407 408 409 410 411 412 413

	if (!thread)
		return NULL;

	if (dso)
		goto got_dso;

	if (map)
		goto got_map;

	map = thread__find_map(thread, ip);
	if (map != NULL) {
414 415 416 417 418
		/*
		 * We have to do this here as we may have a dso
		 * with no symbol hit that has a name longer than
		 * the ones with symbols sampled.
		 */
419
		if (!sort_dso.elide && !map->dso->slen_calculated)
420 421
			dso__calc_col_width(map->dso);

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
		if (mapp)
			*mapp = map;
got_map:
		ip = map->map_ip(map, ip);

		dso = map->dso;
	} else {
		/*
		 * If this is outside of all known maps,
		 * and is a negative address, try to look it
		 * up in the kernel dso, as it might be a
		 * vsyscall (which executes in user-mode):
		 */
		if ((long long)ip < 0)
		dso = kernel_dso;
	}
438 439
	dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
	dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
440
	*ipp  = ip;
441 442 443 444 445 446 447 448 449 450

	if (dsop)
		*dsop = dso;

	if (!dso)
		return NULL;
got_dso:
	return dso->find_symbol(dso, ip);
}

451
static int call__match(struct symbol *sym)
452
{
453
	if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
454
		return 1;
455

456
	return 0;
457 458
}

459
static struct symbol **
460
resolve_callchain(struct thread *thread, struct map *map __used,
461 462 463
		    struct ip_callchain *chain, struct hist_entry *entry)
{
	u64 context = PERF_CONTEXT_MAX;
464
	struct symbol **syms = NULL;
465
	unsigned int i;
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485

	if (callchain) {
		syms = calloc(chain->nr, sizeof(*syms));
		if (!syms) {
			fprintf(stderr, "Can't allocate memory for symbols\n");
			exit(-1);
		}
	}

	for (i = 0; i < chain->nr; i++) {
		u64 ip = chain->ips[i];
		struct dso *dso = NULL;
		struct symbol *sym;

		if (ip >= PERF_CONTEXT_MAX) {
			context = ip;
			continue;
		}

		switch (context) {
I
Ingo Molnar 已提交
486 487 488
		case PERF_CONTEXT_HV:
			dso = hypervisor_dso;
			break;
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
		case PERF_CONTEXT_KERNEL:
			dso = kernel_dso;
			break;
		default:
			break;
		}

		sym = resolve_symbol(thread, NULL, &dso, &ip);

		if (sym) {
			if (sort__has_parent && call__match(sym) &&
			    !entry->parent)
				entry->parent = sym;
			if (!callchain)
				break;
			syms[i] = sym;
		}
	}

	return syms;
}

511 512 513 514
/*
 * collect histogram counts
 */

515 516
static int
hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
517 518
		struct symbol *sym, u64 ip, struct ip_callchain *chain,
		char level, u64 count)
519
{
520 521 522
	struct rb_node **p = &hist.rb_node;
	struct rb_node *parent = NULL;
	struct hist_entry *he;
523
	struct symbol **syms = NULL;
524 525 526 527 528 529 530
	struct hist_entry entry = {
		.thread	= thread,
		.map	= map,
		.dso	= dso,
		.sym	= sym,
		.ip	= ip,
		.level	= level,
531
		.count	= count,
532
		.parent = NULL,
533
		.sorted_chain = RB_ROOT
534 535 536
	};
	int cmp;

537 538
	if ((sort__has_parent || callchain) && chain)
		syms = resolve_callchain(thread, map, chain, &entry);
539

540 541 542 543 544 545 546
	while (*p != NULL) {
		parent = *p;
		he = rb_entry(parent, struct hist_entry, rb_node);

		cmp = hist_entry__cmp(&entry, he);

		if (!cmp) {
547
			he->count += count;
548 549 550 551
			if (callchain) {
				append_chain(&he->callchain, chain, syms);
				free(syms);
			}
552 553 554 555 556 557 558
			return 0;
		}

		if (cmp < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
559
	}
560 561 562 563 564

	he = malloc(sizeof(*he));
	if (!he)
		return -ENOMEM;
	*he = entry;
565 566
	if (callchain) {
		callchain_init(&he->callchain);
567 568
		append_chain(&he->callchain, chain, syms);
		free(syms);
569
	}
570 571 572 573
	rb_link_node(&he->rb_node, parent, p);
	rb_insert_color(&he->rb_node, &hist);

	return 0;
574 575
}

P
Peter Zijlstra 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
static void hist_entry__free(struct hist_entry *he)
{
	free(he);
}

/*
 * collapse the histogram
 */

static struct rb_root collapse_hists;

static void collapse__insert_entry(struct hist_entry *he)
{
	struct rb_node **p = &collapse_hists.rb_node;
	struct rb_node *parent = NULL;
	struct hist_entry *iter;
	int64_t cmp;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct hist_entry, rb_node);

		cmp = hist_entry__collapse(iter, he);

		if (!cmp) {
			iter->count += he->count;
			hist_entry__free(he);
			return;
		}

		if (cmp < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&he->rb_node, parent, p);
	rb_insert_color(&he->rb_node, &collapse_hists);
}

static void collapse__resort(void)
{
	struct rb_node *next;
	struct hist_entry *n;

	if (!sort__need_collapse)
		return;

	next = rb_first(&hist);
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);

		rb_erase(&n->rb_node, &hist);
		collapse__insert_entry(n);
	}
}

634 635 636 637 638 639
/*
 * reverse the map, sort on count.
 */

static struct rb_root output_hists;

640
static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
641
{
642
	struct rb_node **p = &output_hists.rb_node;
643
	struct rb_node *parent = NULL;
644
	struct hist_entry *iter;
645

646 647 648
	if (callchain)
		callchain_param.sort(&he->sorted_chain, &he->callchain,
				      min_callchain_hits, &callchain_param);
649

650 651
	while (*p != NULL) {
		parent = *p;
652
		iter = rb_entry(parent, struct hist_entry, rb_node);
653

654
		if (he->count > iter->count)
655 656 657 658 659
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

660 661
	rb_link_node(&he->rb_node, parent, p);
	rb_insert_color(&he->rb_node, &output_hists);
662 663
}

664
static void output__resort(u64 total_samples)
665
{
P
Peter Zijlstra 已提交
666
	struct rb_node *next;
667
	struct hist_entry *n;
668
	struct rb_root *tree = &hist;
669 670
	u64 min_callchain_hits;

671
	min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
672

P
Peter Zijlstra 已提交
673
	if (sort__need_collapse)
674 675 676
		tree = &collapse_hists;

	next = rb_first(tree);
P
Peter Zijlstra 已提交
677

678 679 680
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);
681

682
		rb_erase(&n->rb_node, tree);
683
		output__insert_entry(n, min_callchain_hits);
684 685 686
	}
}

687
static size_t output__fprintf(FILE *fp, u64 total_samples)
688
{
689
	struct hist_entry *pos;
690
	struct sort_entry *se;
691 692
	struct rb_node *nd;
	size_t ret = 0;
693 694
	unsigned int width;
	char *col_width = col_width_list_str;
695 696 697
	int raw_printing_style;

	raw_printing_style = !strcmp(pretty_printing_style, "raw");
698

699 700
	init_rem_hits();

701
	fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
702 703 704
	fprintf(fp, "#\n");

	fprintf(fp, "# Overhead");
705 706 707 708 709 710
	if (show_nr_samples) {
		if (field_sep)
			fprintf(fp, "%cSamples", *field_sep);
		else
			fputs("  Samples  ", fp);
	}
711
	list_for_each_entry(se, &hist_entry__sort_list, list) {
712
		if (se->elide)
713
			continue;
714 715
		if (field_sep) {
			fprintf(fp, "%c%s", *field_sep, se->header);
716
			continue;
717 718 719 720 721 722 723 724 725 726 727 728 729 730
		}
		width = strlen(se->header);
		if (se->width) {
			if (col_width_list_str) {
				if (col_width) {
					*se->width = atoi(col_width);
					col_width = strchr(col_width, ',');
					if (col_width)
						++col_width;
				}
			}
			width = *se->width = max(*se->width, width);
		}
		fprintf(fp, "  %*s", width, se->header);
731
	}
732 733
	fprintf(fp, "\n");

734 735 736
	if (field_sep)
		goto print_entries;

737
	fprintf(fp, "# ........");
738 739
	if (show_nr_samples)
		fprintf(fp, " ..........");
740
	list_for_each_entry(se, &hist_entry__sort_list, list) {
741
		unsigned int i;
742

743
		if (se->elide)
744 745
			continue;

746
		fprintf(fp, "  ");
747 748 749 750 751
		if (se->width)
			width = *se->width;
		else
			width = strlen(se->header);
		for (i = 0; i < width; i++)
752
			fprintf(fp, ".");
753
	}
754 755 756
	fprintf(fp, "\n");

	fprintf(fp, "#\n");
757

758
print_entries:
759 760 761
	for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
		pos = rb_entry(nd, struct hist_entry, rb_node);
		ret += hist_entry__fprintf(fp, pos, total_samples);
762 763
	}

764 765
	if (sort_order == default_sort_order &&
			parent_pattern == default_parent_pattern) {
766
		fprintf(fp, "#\n");
767
		fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
768 769
		fprintf(fp, "#\n");
	}
770
	fprintf(fp, "\n");
771

772 773
	free(rem_sq_bracket);

774
	if (show_threads)
775 776
		perf_read_values_display(fp, &show_threads_values,
					 raw_printing_style);
777

778 779 780
	return ret;
}

781 782 783 784
static unsigned long total = 0,
		     total_mmap = 0,
		     total_comm = 0,
		     total_fork = 0,
785 786
		     total_unknown = 0,
		     total_lost = 0;
787

788
static int validate_chain(struct ip_callchain *chain, event_t *event)
789 790 791 792 793 794
{
	unsigned int chain_size;

	chain_size = event->header.size;
	chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;

795
	if (chain->nr*sizeof(u64) > chain_size)
796 797 798 799 800
		return -1;

	return 0;
}

801
static int
802
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
803 804 805 806
{
	char level;
	int show = 0;
	struct dso *dso = NULL;
807
	struct thread *thread;
808 809
	u64 ip = event->ip.ip;
	u64 period = 1;
810
	struct map *map = NULL;
811
	void *more_data = event->ip.__more_data;
812
	struct ip_callchain *chain = NULL;
813
	int cpumode;
814

815 816
	thread = threads__findnew(event->ip.pid, &threads, &last_match);

817
	if (sample_type & PERF_SAMPLE_PERIOD) {
818 819
		period = *(u64 *)more_data;
		more_data += sizeof(u64);
820
	}
821

822
	dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
823 824 825
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->header.misc,
826
		event->ip.pid, event->ip.tid,
827
		(void *)(long)ip,
828
		(long long)period);
829

830
	if (sample_type & PERF_SAMPLE_CALLCHAIN) {
831
		unsigned int i;
832 833 834

		chain = (void *)more_data;

835
		dump_printf("... chain: nr:%Lu\n", chain->nr);
836

837 838 839 840 841 842
		if (validate_chain(chain, event) < 0) {
			eprintf("call-chain problem with event, skipping it.\n");
			return 0;
		}

		if (dump_trace) {
843
			for (i = 0; i < chain->nr; i++)
844
				dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
845 846 847
		}
	}

848
	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
849 850

	if (thread == NULL) {
851
		eprintf("problem processing %d event, skipping it.\n",
852 853 854
			event->header.type);
		return -1;
	}
855

856 857 858
	if (comm_list && !strlist__has_entry(comm_list, thread->comm))
		return 0;

859
	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
860

861
	if (cpumode == PERF_RECORD_MISC_KERNEL) {
862 863
		show = SHOW_KERNEL;
		level = 'k';
864

865
		dso = kernel_dso;
866

867
		dump_printf(" ...... dso: %s\n", dso->name);
868

869
	} else if (cpumode == PERF_RECORD_MISC_USER) {
870

871 872
		show = SHOW_USER;
		level = '.';
873

874 875 876
	} else {
		show = SHOW_HV;
		level = 'H';
877 878 879

		dso = hypervisor_dso;

880
		dump_printf(" ...... dso: [hypervisor]\n");
881
	}
882

883
	if (show & show_mask) {
884
		struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
885

886 887
		if (dso_list && (!dso || !dso->name ||
				 !strlist__has_entry(dso_list, dso->name)))
888 889
			return 0;

890
		if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
891 892
			return 0;

893
		if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
894
			eprintf("problem incrementing symbol count, skipping event\n");
895
			return -1;
896
		}
897
	}
898
	total += period;
899

900 901
	return 0;
}
I
Ingo Molnar 已提交
902

903 904 905
static int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
906
	struct thread *thread;
907
	struct map *map = map__new(&event->mmap, cwd, cwdlen);
908

909 910
	thread = threads__findnew(event->mmap.pid, &threads, &last_match);

911
	dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
912 913
		(void *)(offset + head),
		(void *)(long)(event->header.size),
914
		event->mmap.pid,
915
		event->mmap.tid,
916 917 918 919 920 921
		(void *)(long)event->mmap.start,
		(void *)(long)event->mmap.len,
		(void *)(long)event->mmap.pgoff,
		event->mmap.filename);

	if (thread == NULL || map == NULL) {
922
		dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
923
		return 0;
924 925 926 927 928 929 930 931 932 933 934
	}

	thread__insert_map(thread, map);
	total_mmap++;

	return 0;
}

static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
935 936 937
	struct thread *thread;

	thread = threads__findnew(event->comm.pid, &threads, &last_match);
938

939
	dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
940 941 942 943 944
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->comm.comm, event->comm.pid);

	if (thread == NULL ||
945
	    thread__set_comm_adjust(thread, event->comm.comm)) {
946
		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
947
		return -1;
948
	}
949 950 951 952 953
	total_comm++;

	return 0;
}

954
static int
955
process_task_event(event_t *event, unsigned long offset, unsigned long head)
956
{
957 958 959 960 961
	struct thread *thread;
	struct thread *parent;

	thread = threads__findnew(event->fork.pid, &threads, &last_match);
	parent = threads__findnew(event->fork.ppid, &threads, &last_match);
962

963
	dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
964 965
		(void *)(offset + head),
		(void *)(long)(event->header.size),
966
		event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
967 968 969 970 971 972 973 974 975 976
		event->fork.pid, event->fork.tid,
		event->fork.ppid, event->fork.ptid);

	/*
	 * A thread clone will have the same PID for both
	 * parent and child.
	 */
	if (thread == parent)
		return 0;

977
	if (event->header.type == PERF_RECORD_EXIT)
978
		return 0;
979 980

	if (!thread || !parent || thread__fork(thread, parent)) {
981
		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
982 983 984 985 986 987 988
		return -1;
	}
	total_fork++;

	return 0;
}

989 990 991
static int
process_lost_event(event_t *event, unsigned long offset, unsigned long head)
{
992
	dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
993 994 995 996 997 998 999 1000 1001 1002
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->lost.id,
		event->lost.lost);

	total_lost += event->lost.lost;

	return 0;
}

1003 1004 1005
static int
process_read_event(event_t *event, unsigned long offset, unsigned long head)
{
1006
	struct perf_event_attr *attr;
1007 1008

	attr = perf_header__find_attr(event->read.id, header);
1009

1010
	if (show_threads) {
1011
		const char *name = attr ? __event_name(attr->type, attr->config)
1012 1013 1014 1015 1016 1017 1018 1019
				   : "unknown";
		perf_read_values_add_value(&show_threads_values,
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

1020
	dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1021 1022 1023 1024
			(void *)(offset + head),
			(void *)(long)(event->header.size),
			event->read.pid,
			event->read.tid,
1025 1026
			attr ? __event_name(attr->type, attr->config)
			     : "FAIL",
1027 1028 1029 1030 1031
			event->read.value);

	return 0;
}

1032 1033 1034
static int
process_event(event_t *event, unsigned long offset, unsigned long head)
{
1035 1036
	trace_event(event);

1037
	switch (event->header.type) {
1038
	case PERF_RECORD_SAMPLE:
1039 1040
		return process_sample_event(event, offset, head);

1041
	case PERF_RECORD_MMAP:
1042 1043
		return process_mmap_event(event, offset, head);

1044
	case PERF_RECORD_COMM:
1045 1046
		return process_comm_event(event, offset, head);

1047 1048
	case PERF_RECORD_FORK:
	case PERF_RECORD_EXIT:
1049
		return process_task_event(event, offset, head);
1050

1051
	case PERF_RECORD_LOST:
1052 1053
		return process_lost_event(event, offset, head);

1054
	case PERF_RECORD_READ:
1055 1056
		return process_read_event(event, offset, head);

1057 1058 1059
	/*
	 * We dont process them right now but they are fine:
	 */
1060

1061 1062
	case PERF_RECORD_THROTTLE:
	case PERF_RECORD_UNTHROTTLE:
1063 1064
		return 0;

1065 1066 1067 1068 1069 1070 1071 1072 1073
	default:
		return -1;
	}

	return 0;
}

static int __cmd_report(void)
{
1074
	int ret, rc = EXIT_FAILURE;
1075
	unsigned long offset = 0;
1076
	unsigned long head, shift;
1077
	struct stat input_stat;
1078
	struct thread *idle;
1079 1080
	event_t *event;
	uint32_t size;
1081
	char *buf;
1082

1083 1084
	idle = register_idle_thread(&threads, &last_match);
	thread__comm_adjust(idle);
1085

1086 1087 1088
	if (show_threads)
		perf_read_values_init(&show_threads_values);

1089 1090
	input = open(input_name, O_RDONLY);
	if (input < 0) {
1091 1092 1093 1094
		fprintf(stderr, " failed to open file: %s", input_name);
		if (!strcmp(input_name, "perf.data"))
			fprintf(stderr, "  (try 'perf record' first)");
		fprintf(stderr, "\n");
1095 1096 1097
		exit(-1);
	}

1098
	ret = fstat(input, &input_stat);
1099 1100 1101 1102 1103
	if (ret < 0) {
		perror("failed to stat file");
		exit(-1);
	}

1104 1105
	if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
		fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1106 1107 1108
		exit(-1);
	}

1109
	if (!input_stat.st_size) {
1110 1111 1112 1113
		fprintf(stderr, "zero-sized file, nothing to do!\n");
		exit(0);
	}

1114 1115
	header = perf_header__read(input);
	head = header->data_offset;
1116

1117
	sample_type = perf_header__sample_type(header);
1118

1119 1120 1121 1122 1123 1124 1125 1126
	if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
		if (sort__has_parent) {
			fprintf(stderr, "selected --sort parent, but no"
					" callchain data. Did you call"
					" perf record without -g?\n");
			exit(-1);
		}
		if (callchain) {
1127
			fprintf(stderr, "selected -g but no callchain data."
1128 1129 1130 1131
					" Did you call perf record without"
					" -g?\n");
			exit(-1);
		}
1132 1133 1134 1135 1136 1137 1138
	} else if (callchain_param.mode != CHAIN_NONE && !callchain) {
			callchain = 1;
			if (register_callchain_param(&callchain_param) < 0) {
				fprintf(stderr, "Can't register callchain"
						" params\n");
				exit(-1);
			}
1139 1140
	}

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	if (load_kernel() < 0) {
		perror("failed to load kernel symbols");
		return EXIT_FAILURE;
	}

	if (!full_paths) {
		if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
			perror("failed to get the current directory");
			return EXIT_FAILURE;
		}
		cwdlen = strlen(cwd);
	} else {
		cwd = NULL;
		cwdlen = 0;
	}
1156 1157 1158 1159 1160

	shift = page_size * (head / page_size);
	offset += shift;
	head -= shift;

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
remap:
	buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
			   MAP_SHARED, input, offset);
	if (buf == MAP_FAILED) {
		perror("failed to mmap file");
		exit(-1);
	}

more:
	event = (event_t *)(buf + head);

	size = event->header.size;
	if (!size)
		size = 8;

	if (head + event->header.size >= page_size * mmap_window) {
1177
		int munmap_ret;
1178

1179 1180
		shift = page_size * (head / page_size);

1181 1182
		munmap_ret = munmap(buf, page_size * mmap_window);
		assert(munmap_ret == 0);
1183 1184 1185 1186 1187 1188 1189 1190

		offset += shift;
		head -= shift;
		goto remap;
	}

	size = event->header.size;

1191
	dump_printf("\n%p [%p]: event: %d\n",
1192 1193 1194 1195
			(void *)(offset + head),
			(void *)(long)event->header.size,
			event->header.type);

1196 1197
	if (!size || process_event(event, offset, head) < 0) {

1198
		dump_printf("%p [%p]: skipping unknown header type: %d\n",
I
Ingo Molnar 已提交
1199 1200 1201
			(void *)(offset + head),
			(void *)(long)(event->header.size),
			event->header.type);
1202

1203
		total_unknown++;
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213

		/*
		 * assume we lost track of the stream, check alignment, and
		 * increment a single u64 in the hope to catch on again 'soon'.
		 */

		if (unlikely(head & 7))
			head &= ~7ULL;

		size = 8;
1214
	}
1215

1216
	head += size;
I
Ingo Molnar 已提交
1217

1218
	if (offset + head >= header->data_offset + header->data_size)
1219 1220
		goto done;

1221
	if (offset + head < (unsigned long)input_stat.st_size)
1222 1223
		goto more;

1224
done:
1225 1226
	rc = EXIT_SUCCESS;
	close(input);
1227

1228 1229 1230 1231 1232 1233
	dump_printf("      IP events: %10ld\n", total);
	dump_printf("    mmap events: %10ld\n", total_mmap);
	dump_printf("    comm events: %10ld\n", total_comm);
	dump_printf("    fork events: %10ld\n", total_fork);
	dump_printf("    lost events: %10ld\n", total_lost);
	dump_printf(" unknown events: %10ld\n", total_unknown);
1234

I
Ingo Molnar 已提交
1235
	if (dump_trace)
1236 1237
		return 0;

1238
	if (verbose >= 3)
1239
		threads__fprintf(stdout, &threads);
1240

1241
	if (verbose >= 2)
1242 1243
		dsos__fprintf(stdout);

P
Peter Zijlstra 已提交
1244
	collapse__resort();
1245
	output__resort(total);
1246
	output__fprintf(stdout, total);
1247

1248 1249 1250
	if (show_threads)
		perf_read_values_destroy(&show_threads_values);

1251 1252 1253
	return rc;
}

1254 1255 1256 1257
static int
parse_callchain_opt(const struct option *opt __used, const char *arg,
		    int unset __used)
{
1258 1259 1260
	char *tok;
	char *endptr;

1261 1262 1263 1264 1265
	callchain = 1;

	if (!arg)
		return 0;

1266 1267 1268 1269 1270 1271
	tok = strtok((char *)arg, ",");
	if (!tok)
		return -1;

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

1274
	else if (!strncmp(tok, "flat", strlen(arg)))
1275 1276 1277 1278 1279
		callchain_param.mode = CHAIN_FLAT;

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

1280 1281 1282 1283 1284 1285 1286
	else if (!strncmp(tok, "none", strlen(arg))) {
		callchain_param.mode = CHAIN_NONE;
		callchain = 0;

		return 0;
	}

1287 1288 1289
	else
		return -1;

1290 1291 1292
	/* get the min percentage */
	tok = strtok(NULL, ",");
	if (!tok)
1293
		goto setup;
1294

1295
	callchain_param.min_percent = strtod(tok, &endptr);
1296 1297 1298
	if (tok == endptr)
		return -1;

1299 1300 1301 1302 1303
setup:
	if (register_callchain_param(&callchain_param) < 0) {
		fprintf(stderr, "Can't register callchain params\n");
		return -1;
	}
1304 1305 1306
	return 0;
}

1307 1308
//static const char * const report_usage[] = {
const char * const report_usage[] = {
1309 1310 1311 1312 1313 1314 1315
	"perf report [<options>] <command>",
	NULL
};

static const struct option options[] = {
	OPT_STRING('i', "input", &input_name, "file",
		    "input file name"),
1316 1317
	OPT_BOOLEAN('v', "verbose", &verbose,
		    "be more verbose (show symbol address, etc)"),
1318 1319
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
1320
	OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1321
	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1322 1323
	OPT_BOOLEAN('m', "modules", &modules,
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
1324 1325
	OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
		    "Show a column with the number of samples"),
1326 1327
	OPT_BOOLEAN('T', "threads", &show_threads,
		    "Show per-thread event counters"),
1328 1329
	OPT_STRING(0, "pretty", &pretty_printing_style, "key",
		   "pretty printing style key: normal raw"),
1330
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1331
		   "sort by key(s): pid, comm, dso, symbol, parent"),
1332 1333
	OPT_BOOLEAN('P', "full-paths", &full_paths,
		    "Don't shorten the pathnames taking into account the cwd"),
1334 1335
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
1336 1337
	OPT_BOOLEAN('x', "exclude-other", &exclude_other,
		    "Only display entries with parent-match"),
1338
	OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1339
		     "Display callchains using output_type and min percent threshold. "
1340
		     "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1341 1342
	OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
		   "only consider symbols in these dsos"),
1343 1344
	OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
		   "only consider symbols in these comms"),
1345 1346
	OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
		   "only consider these symbols"),
1347 1348 1349 1350 1351 1352
	OPT_STRING('w', "column-widths", &col_width_list_str,
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
	OPT_STRING('t', "field-separator", &field_sep, "separator",
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
1353 1354 1355
	OPT_END()
};

1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
static void setup_sorting(void)
{
	char *tmp, *tok, *str = strdup(sort_order);

	for (tok = strtok_r(str, ", ", &tmp);
			tok; tok = strtok_r(NULL, ", ", &tmp)) {
		if (sort_dimension__add(tok) < 0) {
			error("Unknown --sort key: `%s'", tok);
			usage_with_options(report_usage, options);
		}
	}

	free(str);
}

1371
static void setup_list(struct strlist **list, const char *list_str,
1372 1373
		       struct sort_entry *se, const char *list_name,
		       FILE *fp)
1374 1375 1376 1377 1378 1379 1380 1381
{
	if (list_str) {
		*list = strlist__new(true, list_str);
		if (!*list) {
			fprintf(stderr, "problems parsing %s list\n",
				list_name);
			exit(129);
		}
1382 1383 1384 1385 1386
		if (strlist__nr_entries(*list) == 1) {
			fprintf(fp, "# %s: %s\n", list_name,
				strlist__entry(*list, 0)->s);
			se->elide = true;
		}
1387 1388 1389
	}
}

1390
int cmd_report(int argc, const char **argv, const char *prefix __used)
1391
{
1392
	symbol__init();
1393 1394 1395

	page_size = getpagesize();

1396
	argc = parse_options(argc, argv, options, report_usage, 0);
1397

1398 1399
	setup_sorting();

1400
	if (parent_pattern != default_parent_pattern) {
1401
		sort_dimension__add("parent");
1402 1403
		sort_parent.elide = 1;
	} else
1404 1405
		exclude_other = 0;

1406 1407 1408 1409 1410 1411
	/*
	 * Any (unrecognized) arguments left?
	 */
	if (argc)
		usage_with_options(report_usage, options);

1412 1413
	setup_pager();

1414 1415 1416
	setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
	setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
	setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
1417

1418 1419 1420 1421 1422 1423
	if (field_sep && *field_sep == '.') {
		fputs("'.' is the only non valid --field-separator argument\n",
		      stderr);
		exit(129);
	}

1424 1425
	return __cmd_report();
}