builtin-annotate.c 19.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * builtin-annotate.c
 *
 * Builtin annotate 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.
 */
#include "builtin.h"

#include "util/util.h"

#include "util/color.h"
13
#include <linux/list.h>
14
#include "util/cache.h"
15
#include <linux/rbtree.h>
16 17 18 19
#include "util/symbol.h"
#include "util/string.h"

#include "perf.h"
20
#include "util/debug.h"
21 22 23

#include "util/parse-options.h"
#include "util/parse-events.h"
24
#include "util/thread.h"
25
#include "util/sort.h"
26 27 28

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

29
static int		force;
30 31 32
static int		input;
static int		show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;

33 34
static int		full_paths;

35 36
static int		print_line;

37 38 39
static unsigned long	page_size;
static unsigned long	mmap_window = 32;

40 41 42
static struct rb_root	threads;
static struct thread	*last_match;

43 44

struct sym_ext {
45
	struct rb_node	node;
46 47 48 49
	double		percent;
	char		*path;
};

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
/*
 * histogram, sorted on item, collects counts
 */

static struct rb_root hist;

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

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

90 91 92
/*
 * collect histogram counts
 */
93
static void hist_hit(struct hist_entry *he, u64 ip)
94
{
95 96
	unsigned int sym_size, offset;
	struct symbol *sym = he->sym;
97

98
	he->count++;
99

100 101
	if (!sym || !sym->hist)
		return;
102

103 104
	sym_size = sym->end - sym->start;
	offset = ip - sym->start;
105

106 107
	if (offset >= sym_size)
		return;
108

109 110
	sym->hist_sum++;
	sym->hist[offset]++;
111

112 113
	if (verbose >= 3)
		printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
114
			(void *)(unsigned long)he->sym->start,
115
			he->sym->name,
116
			(void *)(unsigned long)ip, ip - he->sym->start,
117
			sym->hist[offset]);
118 119 120 121
}

static int
hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
122
		struct symbol *sym, u64 ip, char level)
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
{
	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) {
145 146
			hist_hit(he, ip);

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
			return 0;
		}

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

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

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

/*
 * reverse the map, sort on count.
 */

static struct rb_root output_hists;

static void output__insert_entry(struct hist_entry *he)
{
	struct rb_node **p = &output_hists.rb_node;
	struct rb_node *parent = NULL;
	struct hist_entry *iter;

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

		if (he->count > iter->count)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

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

static void output__resort(void)
{
	struct rb_node *next;
	struct hist_entry *n;
	struct rb_root *tree = &hist;

	if (sort__need_collapse)
		tree = &collapse_hists;

	next = rb_first(tree);

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

		rb_erase(&n->rb_node, tree);
		output__insert_entry(n);
	}
}

static unsigned long total = 0,
		     total_mmap = 0,
		     total_comm = 0,
		     total_fork = 0,
		     total_unknown = 0;

static int
277
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
278 279 280 281
{
	char level;
	int show = 0;
	struct dso *dso = NULL;
282
	struct thread *thread;
283
	u64 ip = event->ip.ip;
284 285
	struct map *map = NULL;

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

288
	dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
289 290 291 292 293 294
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->header.misc,
		event->ip.pid,
		(void *)(long)ip);

295
	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
296 297 298 299 300 301 302

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

303
	if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
304 305 306 307 308
		show = SHOW_KERNEL;
		level = 'k';

		dso = kernel_dso;

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

311
	} else if (event->header.misc & PERF_RECORD_MISC_USER) {
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

		show = SHOW_USER;
		level = '.';

		map = thread__find_map(thread, ip);
		if (map != NULL) {
			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;
		}
330
		dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
331 332 333 334

	} else {
		show = SHOW_HV;
		level = 'H';
335
		dump_printf(" ...... dso: [hypervisor]\n");
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
	}

	if (show & show_mask) {
		struct symbol *sym = NULL;

		if (dso)
			sym = dso->find_symbol(dso, ip);

		if (hist_entry__add(thread, map, dso, sym, ip, level)) {
			fprintf(stderr,
		"problem incrementing symbol count, skipping event\n");
			return -1;
		}
	}
	total++;

	return 0;
}

static int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
358
	struct thread *thread;
359
	struct map *map = map__new(&event->mmap, NULL, 0);
360

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

363
	dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
364 365 366 367 368 369 370 371 372
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->mmap.pid,
		(void *)(long)event->mmap.start,
		(void *)(long)event->mmap.len,
		(void *)(long)event->mmap.pgoff,
		event->mmap.filename);

	if (thread == NULL || map == NULL) {
373
		dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
374 375 376 377 378 379 380 381 382 383 384 385
		return 0;
	}

	thread__insert_map(thread, map);
	total_mmap++;

	return 0;
}

static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
386
	struct thread *thread;
387

388
	thread = threads__findnew(event->comm.pid, &threads, &last_match);
389
	dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
390 391 392 393 394 395
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->comm.comm, event->comm.pid);

	if (thread == NULL ||
	    thread__set_comm(thread, event->comm.comm)) {
396
		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
397 398 399 400 401 402 403 404 405 406
		return -1;
	}
	total_comm++;

	return 0;
}

static int
process_fork_event(event_t *event, unsigned long offset, unsigned long head)
{
407 408
	struct thread *thread;
	struct thread *parent;
409

410 411
	thread = threads__findnew(event->fork.pid, &threads, &last_match);
	parent = threads__findnew(event->fork.ppid, &threads, &last_match);
412
	dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
413 414 415 416
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->fork.pid, event->fork.ppid);

417 418 419 420 421 422 423
	/*
	 * A thread clone will have the same PID for both
	 * parent and child.
	 */
	if (thread == parent)
		return 0;

424
	if (!thread || !parent || thread__fork(thread, parent)) {
425
		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
426 427 428 429 430 431 432 433 434 435 436
		return -1;
	}
	total_fork++;

	return 0;
}

static int
process_event(event_t *event, unsigned long offset, unsigned long head)
{
	switch (event->header.type) {
437
	case PERF_RECORD_SAMPLE:
438 439
		return process_sample_event(event, offset, head);

440
	case PERF_RECORD_MMAP:
441 442
		return process_mmap_event(event, offset, head);

443
	case PERF_RECORD_COMM:
444 445
		return process_comm_event(event, offset, head);

446
	case PERF_RECORD_FORK:
447 448 449 450 451
		return process_fork_event(event, offset, head);
	/*
	 * We dont process them right now but they are fine:
	 */

452 453
	case PERF_RECORD_THROTTLE:
	case PERF_RECORD_UNTHROTTLE:
454 455 456 457 458 459 460 461 462
		return 0;

	default:
		return -1;
	}

	return 0;
}

463
static int
464
parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
465 466
{
	char *line = NULL, *tmp, *tmp2;
467 468
	static const char *prev_line;
	static const char *prev_color;
469 470
	unsigned int offset;
	size_t line_len;
471
	s64 line_ip;
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
	int ret;
	char *c;

	if (getline(&line, &line_len, file) < 0)
		return -1;
	if (!line)
		return -1;

	c = strchr(line, '\n');
	if (c)
		*c = 0;

	line_ip = -1;
	offset = 0;
	ret = -2;

	/*
	 * Strip leading spaces:
	 */
	tmp = line;
	while (*tmp) {
		if (*tmp != ' ')
			break;
		tmp++;
	}

	if (*tmp) {
		/*
		 * Parse hexa addresses followed by ':'
		 */
		line_ip = strtoull(tmp, &tmp2, 16);
		if (*tmp2 != ':')
			line_ip = -1;
	}

	if (line_ip != -1) {
508
		const char *path = NULL;
509 510
		unsigned int hits = 0;
		double percent = 0.0;
511
		const char *color;
512
		struct sym_ext *sym_ext = sym->priv;
513 514 515 516 517

		offset = line_ip - start;
		if (offset < len)
			hits = sym->hist[offset];

518
		if (offset < len && sym_ext) {
519 520 521
			path = sym_ext[offset].path;
			percent = sym_ext[offset].percent;
		} else if (sym->hist_sum)
522 523
			percent = 100.0 * hits / sym->hist_sum;

524
		color = get_percent_color(percent);
525

526 527 528 529 530 531 532 533 534 535 536 537 538 539
		/*
		 * Also color the filename and line if needed, with
		 * the same color than the percentage. Don't print it
		 * twice for close colored ip with the same filename:line
		 */
		if (path) {
			if (!prev_line || strcmp(prev_line, path)
				       || color != prev_color) {
				color_fprintf(stdout, color, " %s", path);
				prev_line = path;
				prev_color = color;
			}
		}

540 541 542 543 544 545 546 547 548 549 550 551 552
		color_fprintf(stdout, color, " %7.2f", percent);
		printf(" :	");
		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
	} else {
		if (!*line)
			printf("         :\n");
		else
			printf("         :	%s\n", line);
	}

	return 0;
}

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
static struct rb_root root_sym_ext;

static void insert_source_line(struct sym_ext *sym_ext)
{
	struct sym_ext *iter;
	struct rb_node **p = &root_sym_ext.rb_node;
	struct rb_node *parent = NULL;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct sym_ext, node);

		if (sym_ext->percent > iter->percent)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&sym_ext->node, parent, p);
	rb_insert_color(&sym_ext->node, &root_sym_ext);
}

575 576 577 578 579 580 581 582 583 584 585 586 587
static void free_source_line(struct symbol *sym, int len)
{
	struct sym_ext *sym_ext = sym->priv;
	int i;

	if (!sym_ext)
		return;

	for (i = 0; i < len; i++)
		free(sym_ext[i].path);
	free(sym_ext);

	sym->priv = NULL;
588
	root_sym_ext = RB_ROOT;
589 590 591
}

/* Get the filename:line for the colored entries */
592
static void
593
get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
{
	int i;
	char cmd[PATH_MAX * 2];
	struct sym_ext *sym_ext;

	if (!sym->hist_sum)
		return;

	sym->priv = calloc(len, sizeof(struct sym_ext));
	if (!sym->priv)
		return;

	sym_ext = sym->priv;

	for (i = 0; i < len; i++) {
		char *path = NULL;
		size_t line_len;
611
		u64 offset;
612 613 614 615 616 617 618
		FILE *fp;

		sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
		if (sym_ext[i].percent <= 0.5)
			continue;

		offset = start + i;
619
		sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
620 621 622 623 624 625 626
		fp = popen(cmd, "r");
		if (!fp)
			continue;

		if (getline(&path, &line_len, fp) < 0 || !line_len)
			goto next;

627
		sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
628 629 630 631
		if (!sym_ext[i].path)
			goto next;

		strcpy(sym_ext[i].path, path);
632
		insert_source_line(&sym_ext[i]);
633 634 635 636 637 638

	next:
		pclose(fp);
	}
}

639
static void print_summary(const char *filename)
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
{
	struct sym_ext *sym_ext;
	struct rb_node *node;

	printf("\nSorted summary for file %s\n", filename);
	printf("----------------------------------------------\n\n");

	if (RB_EMPTY_ROOT(&root_sym_ext)) {
		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
		return;
	}

	node = rb_first(&root_sym_ext);
	while (node) {
		double percent;
655
		const char *color;
656 657 658 659
		char *path;

		sym_ext = rb_entry(node, struct sym_ext, node);
		percent = sym_ext->percent;
660
		color = get_percent_color(percent);
661 662 663 664 665 666 667
		path = sym_ext->path;

		color_fprintf(stdout, color, " %7.2f %s", percent, path);
		node = rb_next(node);
	}
}

668 669
static void annotate_sym(struct dso *dso, struct symbol *sym)
{
670
	const char *filename = dso->name, *d_filename;
671
	u64 start, end, len;
672 673 674 675 676
	char command[PATH_MAX*2];
	FILE *file;

	if (!filename)
		return;
677 678 679
	if (sym->module)
		filename = sym->module->path;
	else if (dso == kernel_dso)
680
		filename = vmlinux_name;
681 682 683 684

	start = sym->obj_start;
	if (!start)
		start = sym->start;
685 686 687 688
	if (full_paths)
		d_filename = filename;
	else
		d_filename = basename(filename);
689 690 691 692

	end = start + sym->end - sym->start + 1;
	len = sym->end - sym->start;

693
	if (print_line) {
694
		get_source_line(sym, start, len, filename);
695 696 697 698
		print_summary(filename);
	}

	printf("\n\n------------------------------------------------\n");
699
	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
700 701 702 703
	printf("------------------------------------------------\n");

	if (verbose >= 2)
		printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
704

705 706
	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
			(u64)start, (u64)end, filename, filename);
707 708 709 710 711 712 713 714 715 716 717 718 719 720

	if (verbose >= 3)
		printf("doing: %s\n", command);

	file = popen(command, "r");
	if (!file)
		return;

	while (!feof(file)) {
		if (parse_line(file, sym, start, len) < 0)
			break;
	}

	pclose(file);
721 722
	if (print_line)
		free_source_line(sym, len);
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
}

static void find_annotations(void)
{
	struct rb_node *nd;
	struct dso *dso;
	int count = 0;

	list_for_each_entry(dso, &dsos, node) {

		for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
			struct symbol *sym = rb_entry(nd, struct symbol, rb_node);

			if (sym->hist) {
				annotate_sym(dso, sym);
				count++;
			}
		}
	}

	if (!count)
		printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
}

747 748 749 750 751
static int __cmd_annotate(void)
{
	int ret, rc = EXIT_FAILURE;
	unsigned long offset = 0;
	unsigned long head = 0;
752
	struct stat input_stat;
753 754 755 756
	event_t *event;
	uint32_t size;
	char *buf;

757
	register_idle_thread(&threads, &last_match);
758 759 760 761 762 763 764

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

765
	ret = fstat(input, &input_stat);
766 767 768 769 770
	if (ret < 0) {
		perror("failed to stat file");
		exit(-1);
	}

771 772
	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);
773 774 775
		exit(-1);
	}

776
	if (!input_stat.st_size) {
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
		fprintf(stderr, "zero-sized file, nothing to do!\n");
		exit(0);
	}

	if (load_kernel() < 0) {
		perror("failed to load kernel symbols");
		return EXIT_FAILURE;
	}

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);
803
		int munmap_ret;
804

805 806
		munmap_ret = munmap(buf, page_size * mmap_window);
		assert(munmap_ret == 0);
807 808 809 810 811 812 813 814

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

	size = event->header.size;

815
	dump_printf("%p [%p]: event: %d\n",
816 817 818 819 820 821
			(void *)(offset + head),
			(void *)(long)event->header.size,
			event->header.type);

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

822
		dump_printf("%p [%p]: skipping unknown header type: %d\n",
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
			(void *)(offset + head),
			(void *)(long)(event->header.size),
			event->header.type);

		total_unknown++;

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

	head += size;

842
	if (offset + head < (unsigned long)input_stat.st_size)
843 844 845 846 847
		goto more;

	rc = EXIT_SUCCESS;
	close(input);

848 849 850 851 852
	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(" unknown events: %10ld\n", total_unknown);
853 854 855 856 857

	if (dump_trace)
		return 0;

	if (verbose >= 3)
858
		threads__fprintf(stdout, &threads);
859 860 861 862 863 864

	if (verbose >= 2)
		dsos__fprintf(stdout);

	collapse__resort();
	output__resort();
865 866

	find_annotations();
867 868 869 870 871 872 873 874 875 876 877 878

	return rc;
}

static const char * const annotate_usage[] = {
	"perf annotate [<options>] <command>",
	NULL
};

static const struct option options[] = {
	OPT_STRING('i', "input", &input_name, "file",
		    "input file name"),
879
	OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
880
		    "symbol to annotate"),
881
	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
882 883 884 885
	OPT_BOOLEAN('v', "verbose", &verbose,
		    "be more verbose (show symbol address, etc)"),
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
886
	OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
887 888
	OPT_BOOLEAN('m', "modules", &modules,
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
889 890
	OPT_BOOLEAN('l', "print-line", &print_line,
		    "print matching source lines (may be slow)"),
891 892
	OPT_BOOLEAN('P', "full-paths", &full_paths,
		    "Don't shorten the displayed pathnames"),
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
	OPT_END()
};

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(annotate_usage, options);
		}
	}

	free(str);
}

911
int cmd_annotate(int argc, const char **argv, const char *prefix __used)
912 913 914 915 916 917 918 919 920
{
	symbol__init();

	page_size = getpagesize();

	argc = parse_options(argc, argv, options, annotate_usage, 0);

	setup_sorting();

921 922 923 924 925 926 927 928 929 930 931 932
	if (argc) {
		/*
		 * Special case: if there's an argument left then assume tha
		 * it's a symbol filter:
		 */
		if (argc > 1)
			usage_with_options(annotate_usage, options);

		sym_hist_filter = argv[0];
	}

	if (!sym_hist_filter)
933 934 935 936
		usage_with_options(annotate_usage, options);

	setup_pager();

937 938 939 940 941 942
	if (field_sep && *field_sep == '.') {
		fputs("'.' is the only non valid --field-separator argument\n",
				stderr);
		exit(129);
	}

943 944
	return __cmd_annotate();
}