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

12
#include "util/list.h"
13
#include "util/cache.h"
14
#include "util/rbtree.h"
15
#include "util/symbol.h"
16
#include "util/string.h"
17

18 19 20 21 22
#include "perf.h"

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

23 24 25 26
#define SHOW_KERNEL	1
#define SHOW_USER	2
#define SHOW_HV		4

27
static char		const *input_name = "perf.data";
28
static char		*vmlinux = NULL;
29
static char		*sort_order = "comm,dso";
30 31 32
static int		input;
static int		show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;

33
static int		dump_trace = 0;
I
Ingo Molnar 已提交
34 35
#define dprintf(x...)	do { if (dump_trace) printf(x); } while (0)

36
static int		verbose;
37
static int		full_paths;
38

39 40 41
static unsigned long	page_size;
static unsigned long	mmap_window = 32;

42
const char *perf_event_names[] = {
43 44 45 46 47 48 49 50 51 52
	[PERF_EVENT_MMAP]   = " PERF_EVENT_MMAP",
	[PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
	[PERF_EVENT_COMM]   = " PERF_EVENT_COMM",
};

struct ip_event {
	struct perf_event_header header;
	__u64 ip;
	__u32 pid, tid;
};
53

54 55 56 57 58 59 60 61
struct mmap_event {
	struct perf_event_header header;
	__u32 pid, tid;
	__u64 start;
	__u64 len;
	__u64 pgoff;
	char filename[PATH_MAX];
};
62

63 64
struct comm_event {
	struct perf_event_header header;
65
	__u32 pid, tid;
66 67 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
	char comm[16];
};

typedef union event_union {
	struct perf_event_header header;
	struct ip_event ip;
	struct mmap_event mmap;
	struct comm_event comm;
} event_t;

static LIST_HEAD(dsos);
static struct dso *kernel_dso;

static void dsos__add(struct dso *dso)
{
	list_add_tail(&dso->node, &dsos);
}

static struct dso *dsos__find(const char *name)
{
	struct dso *pos;

	list_for_each_entry(pos, &dsos, node)
		if (strcmp(pos->name, name) == 0)
			return pos;
	return NULL;
}

static struct dso *dsos__findnew(const char *name)
{
	struct dso *dso = dsos__find(name);
97
	int nr;
98

99 100 101 102 103 104
	if (dso)
		return dso;

	dso = dso__new(name, 0);
	if (!dso)
		goto out_delete_dso;
105

106 107 108 109
	nr = dso__load(dso, NULL);
	if (nr < 0) {
		fprintf(stderr, "Failed to open: %s\n", name);
		goto out_delete_dso;
110
	}
111 112 113 114 115 116 117
	if (!nr && verbose) {
		fprintf(stderr,
		"No symbols found in: %s, maybe install a debug package?\n",
				name);
	}

	dsos__add(dso);
118 119 120 121 122 123 124 125

	return dso;

out_delete_dso:
	dso__delete(dso);
	return NULL;
}

126
static void dsos__fprintf(FILE *fp)
127 128 129 130 131 132 133
{
	struct dso *pos;

	list_for_each_entry(pos, &dsos, node)
		dso__fprintf(pos, fp);
}

134 135
static int load_kernel(void)
{
136
	int err;
137

138
	kernel_dso = dso__new("[kernel]", 0);
139
	if (!kernel_dso)
140
		return -1;
141

142
	err = dso__load_kernel(kernel_dso, vmlinux, NULL);
143 144 145 146 147
	if (err) {
		dso__delete(kernel_dso);
		kernel_dso = NULL;
	} else
		dsos__add(kernel_dso);
148

149
	return err;
150 151
}

152 153 154 155 156
static char __cwd[PATH_MAX];
static char *cwd = __cwd;
static int cwdlen;

static int strcommon(const char *pathname)
157 158 159 160 161 162 163 164 165
{
	int n = 0;

	while (pathname[n] == cwd[n] && n < cwdlen)
		++n;

	return n;
}

166 167 168 169 170 171 172 173
struct map {
	struct list_head node;
	uint64_t	 start;
	uint64_t	 end;
	uint64_t	 pgoff;
	struct dso	 *dso;
};

174
static struct map *map__new(struct mmap_event *event)
175 176 177 178
{
	struct map *self = malloc(sizeof(*self));

	if (self != NULL) {
179 180 181 182
		const char *filename = event->filename;
		char newfilename[PATH_MAX];

		if (cwd) {
183 184
			int n = strcommon(filename);

185 186 187 188 189 190 191
			if (n == cwdlen) {
				snprintf(newfilename, sizeof(newfilename),
					 ".%s", filename + n);
				filename = newfilename;
			}
		}

192 193 194 195
		self->start = event->start;
		self->end   = event->start + event->len;
		self->pgoff = event->pgoff;

196
		self->dso = dsos__findnew(filename);
197 198 199 200 201 202 203 204 205
		if (self->dso == NULL)
			goto out_delete;
	}
	return self;
out_delete:
	free(self);
	return NULL;
}

206 207
struct thread;

208
struct thread {
209
	struct rb_node	 rb_node;
210 211 212 213 214 215 216 217 218 219 220
	struct list_head maps;
	pid_t		 pid;
	char		 *comm;
};

static struct thread *thread__new(pid_t pid)
{
	struct thread *self = malloc(sizeof(*self));

	if (self != NULL) {
		self->pid = pid;
P
Peter Zijlstra 已提交
221
		self->comm = malloc(32);
222
		if (self->comm)
P
Peter Zijlstra 已提交
223
			snprintf(self->comm, 32, ":%d", self->pid);
224 225 226 227 228 229 230 231
		INIT_LIST_HEAD(&self->maps);
	}

	return self;
}

static int thread__set_comm(struct thread *self, const char *comm)
{
P
Peter Zijlstra 已提交
232 233
	if (self->comm)
		free(self->comm);
234 235 236 237
	self->comm = strdup(comm);
	return self->comm ? 0 : -ENOMEM;
}

238
static struct rb_root threads;
239
static struct thread *last_match;
240

241
static struct thread *threads__findnew(pid_t pid)
242
{
243 244 245
	struct rb_node **p = &threads.rb_node;
	struct rb_node *parent = NULL;
	struct thread *th;
246

247 248 249 250 251 252 253 254
	/*
	 * Font-end cache - PID lookups come in blocks,
	 * so most of the time we dont have to look up
	 * the full rbtree:
	 */
	if (last_match && last_match->pid == pid)
		return last_match;

255 256 257
	while (*p != NULL) {
		parent = *p;
		th = rb_entry(parent, struct thread, rb_node);
258

259 260
		if (th->pid == pid) {
			last_match = th;
261
			return th;
262
		}
263

264 265 266 267
		if (pid < th->pid)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
268 269
	}

270 271 272 273
	th = thread__new(pid);
	if (th != NULL) {
		rb_link_node(&th->rb_node, parent, p);
		rb_insert_color(&th->rb_node, &threads);
274
		last_match = th;
275
	}
276

277
	return th;
278 279 280 281 282 283 284 285 286
}

static void thread__insert_map(struct thread *self, struct map *map)
{
	list_add_tail(&map->node, &self->maps);
}

static struct map *thread__find_map(struct thread *self, uint64_t ip)
{
287 288
	struct map *pos;

289 290 291 292 293 294 295 296 297 298
	if (self == NULL)
		return NULL;

	list_for_each_entry(pos, &self->maps, node)
		if (ip >= pos->start && ip <= pos->end)
			return pos;

	return NULL;
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
/*
 * histogram, sorted on item, collects counts
 */

static struct rb_root hist;

struct hist_entry {
	struct rb_node	 rb_node;

	struct thread	 *thread;
	struct map	 *map;
	struct dso	 *dso;
	struct symbol	 *sym;
	uint64_t	 ip;
	char		 level;

	uint32_t	 count;
};

318 319 320 321 322 323 324
/*
 * configurable sorting bits
 */

struct sort_entry {
	struct list_head list;

325 326
	char *header;

327
	int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
P
Peter Zijlstra 已提交
328
	int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
329 330 331
	size_t	(*print)(FILE *fp, struct hist_entry *);
};

P
Peter Zijlstra 已提交
332 333
/* --sort pid */

334
static int64_t
335
sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
336
{
337 338 339 340 341 342
	return right->thread->pid - left->thread->pid;
}

static size_t
sort__thread_print(FILE *fp, struct hist_entry *self)
{
343
	return fprintf(fp, " %16s:%5d", self->thread->comm ?: "", self->thread->pid);
344
}
345

346
static struct sort_entry sort_thread = {
347
	.header = "         Command: Pid ",
348 349 350 351
	.cmp	= sort__thread_cmp,
	.print	= sort__thread_print,
};

P
Peter Zijlstra 已提交
352 353
/* --sort comm */

354 355
static int64_t
sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
P
Peter Zijlstra 已提交
356 357 358 359 360 361
{
	return right->thread->pid - left->thread->pid;
}

static int64_t
sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
{
	char *comm_l = left->thread->comm;
	char *comm_r = right->thread->comm;

	if (!comm_l || !comm_r) {
		if (!comm_l && !comm_r)
			return 0;
		else if (!comm_l)
			return -1;
		else
			return 1;
	}

	return strcmp(comm_l, comm_r);
}

static size_t
sort__comm_print(FILE *fp, struct hist_entry *self)
{
381
	return fprintf(fp, "  %16s", self->thread->comm);
382 383 384
}

static struct sort_entry sort_comm = {
P
Peter Zijlstra 已提交
385 386 387 388
	.header 	= "          Command",
	.cmp		= sort__comm_cmp,
	.collapse	= sort__comm_collapse,
	.print		= sort__comm_print,
389 390
};

P
Peter Zijlstra 已提交
391 392
/* --sort dso */

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
static int64_t
sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
{
	struct dso *dso_l = left->dso;
	struct dso *dso_r = right->dso;

	if (!dso_l || !dso_r) {
		if (!dso_l && !dso_r)
			return 0;
		else if (!dso_l)
			return -1;
		else
			return 1;
	}

	return strcmp(dso_l->name, dso_r->name);
}

static size_t
sort__dso_print(FILE *fp, struct hist_entry *self)
{
414 415 416 417
	if (self->dso)
		return fprintf(fp, "  %-25s", self->dso->name);

	return fprintf(fp, "  %016llx", (__u64)self->ip);
418 419 420
}

static struct sort_entry sort_dso = {
421
	.header = " Shared Object          ",
422 423 424 425
	.cmp	= sort__dso_cmp,
	.print	= sort__dso_print,
};

P
Peter Zijlstra 已提交
426 427
/* --sort symbol */

428 429 430 431
static int64_t
sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
{
	uint64_t ip_l, ip_r;
432 433 434 435 436 437 438 439 440 441

	if (left->sym == right->sym)
		return 0;

	ip_l = left->sym ? left->sym->start : left->ip;
	ip_r = right->sym ? right->sym->start : right->ip;

	return (int64_t)(ip_r - ip_l);
}

442 443 444 445 446 447
static size_t
sort__sym_print(FILE *fp, struct hist_entry *self)
{
	size_t ret = 0;

	if (verbose)
448 449 450 451 452 453
		ret += fprintf(fp, "  %#018llx", (__u64)self->ip);

	if (self->dso)
		ret += fprintf(fp, "  %s: ", self->dso->name);
	else
		ret += fprintf(fp, "  %#016llx: ", (__u64)self->ip);
454

455 456 457 458
	if (self->sym)
		ret += fprintf(fp, "%s", self->sym->name);
	else
		ret += fprintf(fp, "%#016llx", (__u64)self->ip);
459 460 461 462 463

	return ret;
}

static struct sort_entry sort_sym = {
464
	.header = " Shared Object: Symbol",
465 466
	.cmp	= sort__sym_cmp,
	.print	= sort__sym_print,
467 468
};

P
Peter Zijlstra 已提交
469 470
static int sort__need_collapse = 0;

471 472 473 474 475 476 477 478
struct sort_dimension {
	char *name;
	struct sort_entry *entry;
	int taken;
};

static struct sort_dimension sort_dimensions[] = {
	{ .name = "pid",	.entry = &sort_thread,	},
479
	{ .name = "comm",	.entry = &sort_comm,	},
480
	{ .name = "dso",	.entry = &sort_dso,	},
481 482 483
	{ .name = "symbol",	.entry = &sort_sym,	},
};

484 485
static LIST_HEAD(hist_entry__sort_list);

486 487 488 489 490 491 492 493 494 495
static int sort_dimension__add(char *tok)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
		struct sort_dimension *sd = &sort_dimensions[i];

		if (sd->taken)
			continue;

496
		if (strncasecmp(tok, sd->name, strlen(tok)))
497 498
			continue;

P
Peter Zijlstra 已提交
499 500 501
		if (sd->entry->collapse)
			sort__need_collapse = 1;

502 503
		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
		sd->taken = 1;
504

505 506 507 508 509 510
		return 0;
	}

	return -ESRCH;
}

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
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 已提交
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
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;
}

545 546 547 548 549 550 551
static size_t
hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
{
	struct sort_entry *se;
	size_t ret;

	if (total_samples) {
552
		ret = fprintf(fp, "   %6.2f%%",
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
				(self->count * 100.0) / total_samples);
	} else
		ret = fprintf(fp, "%12d ", self->count);

	list_for_each_entry(se, &hist_entry__sort_list, list)
		ret += se->print(fp, self);

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

	return ret;
}

/*
 * collect histogram counts
 */

569 570 571
static int
hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
		struct symbol *sym, uint64_t ip, char level)
572
{
573 574 575 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
	struct rb_node **p = &hist.rb_node;
	struct rb_node *parent = NULL;
	struct hist_entry *he;
	struct hist_entry entry = {
		.thread	= thread,
		.map	= map,
		.dso	= dso,
		.sym	= sym,
		.ip	= ip,
		.level	= level,
		.count	= 1,
	};
	int cmp;

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

		cmp = hist_entry__cmp(&entry, he);

		if (!cmp) {
			he->count++;
			return 0;
		}

		if (cmp < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
602
	}
603 604 605 606 607 608 609 610 611

	he = malloc(sizeof(*he));
	if (!he)
		return -ENOMEM;
	*he = entry;
	rb_link_node(&he->rb_node, parent, p);
	rb_insert_color(&he->rb_node, &hist);

	return 0;
612 613
}

P
Peter Zijlstra 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
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);
	}
}

672 673 674 675 676 677 678
/*
 * reverse the map, sort on count.
 */

static struct rb_root output_hists;

static void output__insert_entry(struct hist_entry *he)
679
{
680
	struct rb_node **p = &output_hists.rb_node;
681
	struct rb_node *parent = NULL;
682
	struct hist_entry *iter;
683 684 685

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

688
		if (he->count > iter->count)
689 690 691 692 693
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

694 695
	rb_link_node(&he->rb_node, parent, p);
	rb_insert_color(&he->rb_node, &output_hists);
696 697
}

698
static void output__resort(void)
699
{
P
Peter Zijlstra 已提交
700
	struct rb_node *next;
701
	struct hist_entry *n;
702

P
Peter Zijlstra 已提交
703 704 705 706 707
	if (sort__need_collapse)
		next = rb_first(&collapse_hists);
	else
		next = rb_first(&hist);

708 709 710
	while (next) {
		n = rb_entry(next, struct hist_entry, rb_node);
		next = rb_next(&n->rb_node);
711

712 713
		rb_erase(&n->rb_node, &hist);
		output__insert_entry(n);
714 715 716
	}
}

717
static size_t output__fprintf(FILE *fp, uint64_t total_samples)
718
{
719
	struct hist_entry *pos;
720
	struct sort_entry *se;
721 722 723
	struct rb_node *nd;
	size_t ret = 0;

724 725 726 727 728 729 730 731
	fprintf(fp, "#\n");

	fprintf(fp, "# Overhead");
	list_for_each_entry(se, &hist_entry__sort_list, list)
		fprintf(fp, " %s", se->header);
	fprintf(fp, "\n");

	fprintf(fp, "# ........");
732
	list_for_each_entry(se, &hist_entry__sort_list, list) {
733 734
		int i;

735 736
		fprintf(fp, "  ");
		for (i = 0; i < strlen(se->header)-1; i++)
737
			fprintf(fp, ".");
738
	}
739 740 741
	fprintf(fp, "\n");

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

743 744 745
	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);
746 747 748 749 750
	}

	return ret;
}

751 752 753 754 755 756 757 758 759 760 761
static void register_idle_thread(void)
{
	struct thread *thread = threads__findnew(0);

	if (thread == NULL ||
			thread__set_comm(thread, "[idle]")) {
		fprintf(stderr, "problem inserting idle task.\n");
		exit(-1);
	}
}

762
static unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
763

764
static int
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
{
	char level;
	int show = 0;
	struct dso *dso = NULL;
	struct thread *thread = threads__findnew(event->ip.pid);
	uint64_t ip = event->ip.ip;
	struct map *map = NULL;

	dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->header.misc,
		event->ip.pid,
		(void *)(long)ip);

	dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);

	if (thread == NULL) {
		fprintf(stderr, "problem processing %d event, skipping it.\n",
			event->header.type);
		return -1;
	}
788

789 790 791
	if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
		show = SHOW_KERNEL;
		level = 'k';
792

793
		dso = kernel_dso;
794

795
		dprintf(" ...... dso: %s\n", dso->name);
796

797
	} else if (event->header.misc & PERF_EVENT_MISC_USER) {
798

799 800
		show = SHOW_USER;
		level = '.';
801

802 803 804 805
		map = thread__find_map(thread, ip);
		if (map != NULL) {
			dso = map->dso;
			ip -= map->start + map->pgoff;
806
		} else {
807 808 809 810 811 812 813 814
			/*
			 * 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;
815
		}
816 817 818 819 820 821 822
		dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");

	} else {
		show = SHOW_HV;
		level = 'H';
		dprintf(" ...... dso: [hypervisor]\n");
	}
823

824 825
	if (show & show_mask) {
		struct symbol *sym = dso__find_symbol(dso, ip);
826

827 828
		if (hist_entry__add(thread, map, dso, sym, ip, level)) {
			fprintf(stderr,
829
		"problem incrementing symbol count, skipping event\n");
830
			return -1;
831
		}
832
	}
833
	total++;
834

835 836
	return 0;
}
I
Ingo Molnar 已提交
837

838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
static int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
	struct thread *thread = threads__findnew(event->mmap.pid);
	struct map *map = map__new(&event->mmap);

	dprintf("%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		(void *)(long)event->mmap.start,
		(void *)(long)event->mmap.len,
		(void *)(long)event->mmap.pgoff,
		event->mmap.filename);

	if (thread == NULL || map == NULL) {
		dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
		return -1;
	}

	thread__insert_map(thread, map);
	total_mmap++;

	return 0;
}

static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
	struct thread *thread = threads__findnew(event->comm.pid);

	dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->comm.comm, event->comm.pid);

	if (thread == NULL ||
	    thread__set_comm(thread, event->comm.comm)) {
		dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
		return -1;
877
	}
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
	total_comm++;

	return 0;
}

static int
process_event(event_t *event, unsigned long offset, unsigned long head)
{
	if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
		return process_overflow_event(event, offset, head);

	switch (event->header.type) {
	case PERF_EVENT_MMAP:
		return process_mmap_event(event, offset, head);

	case PERF_EVENT_COMM:
		return process_comm_event(event, offset, head);

896 897 898 899 900 901 902 903 904
	default:
		return -1;
	}

	return 0;
}

static int __cmd_report(void)
{
905
	int ret, rc = EXIT_FAILURE;
906 907 908 909 910
	unsigned long offset = 0;
	unsigned long head = 0;
	struct stat stat;
	event_t *event;
	uint32_t size;
911
	char *buf;
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977

	register_idle_thread();

	input = open(input_name, O_RDONLY);
	if (input < 0) {
		perror("failed to open file");
		exit(-1);
	}

	ret = fstat(input, &stat);
	if (ret < 0) {
		perror("failed to stat file");
		exit(-1);
	}

	if (!stat.st_size) {
		fprintf(stderr, "zero-sized file, nothing to do!\n");
		exit(0);
	}

	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;
	}
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) {
		unsigned long shift = page_size * (head / page_size);
		int ret;

		ret = munmap(buf, page_size * mmap_window);
		assert(ret == 0);

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

	size = event->header.size;

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

I
Ingo Molnar 已提交
978 979 980 981
		dprintf("%p [%p]: skipping unknown header type: %d\n",
			(void *)(offset + head),
			(void *)(long)(event->header.size),
			event->header.type);
982

983
		total_unknown++;
984 985 986 987 988 989 990 991 992 993

		/*
		 * 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;
994
	}
995

996
	head += size;
I
Ingo Molnar 已提交
997

998 999 1000 1001 1002
	if (offset + head < stat.st_size)
		goto more;

	rc = EXIT_SUCCESS;
	close(input);
1003

I
Ingo Molnar 已提交
1004 1005 1006 1007
	dprintf("      IP events: %10ld\n", total);
	dprintf("    mmap events: %10ld\n", total_mmap);
	dprintf("    comm events: %10ld\n", total_comm);
	dprintf(" unknown events: %10ld\n", total_unknown);
1008

I
Ingo Molnar 已提交
1009
	if (dump_trace)
1010 1011
		return 0;

1012
	if (verbose >= 2)
1013 1014
		dsos__fprintf(stdout);

P
Peter Zijlstra 已提交
1015
	collapse__resort();
1016 1017
	output__resort();
	output__fprintf(stdout, total);
1018 1019 1020 1021

	return rc;
}

1022 1023 1024 1025 1026 1027 1028 1029
static const char * const report_usage[] = {
	"perf report [<options>] <command>",
	NULL
};

static const struct option options[] = {
	OPT_STRING('i', "input", &input_name, "file",
		    "input file name"),
1030 1031
	OPT_BOOLEAN('v', "verbose", &verbose,
		    "be more verbose (show symbol address, etc)"),
1032 1033
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
1034
	OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1035 1036
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
		   "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
1037 1038
	OPT_BOOLEAN('P', "full-paths", &full_paths,
		    "Don't shorten the pathnames taking into account the cwd"),
1039 1040 1041
	OPT_END()
};

1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
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);
}

1057 1058
int cmd_report(int argc, const char **argv, const char *prefix)
{
1059
	symbol__init();
1060 1061 1062 1063 1064

	page_size = getpagesize();

	parse_options(argc, argv, options, report_usage, 0);

1065 1066
	setup_sorting();

1067 1068
	setup_pager();

1069 1070
	return __cmd_report();
}