builtin-annotate.c 16.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
#include "util/hist.h"
27
#include "util/process_events.h"
28 29 30

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

31
static int		force;
32 33
static int		input;

34 35
static int		full_paths;

36
static int		print_line;
37
static bool		use_modules;
38

39 40
static unsigned long	page_size;
static unsigned long	mmap_window = 32;
41
const char		*vmlinux_name;
42

43 44 45 46 47
struct sym_hist {
	u64		sum;
	u64		ip[0];
};

48
struct sym_ext {
49
	struct rb_node	node;
50 51 52 53
	double		percent;
	char		*path;
};

54 55 56 57 58 59 60
struct sym_priv {
	struct sym_hist	*hist;
	struct sym_ext	*ext;
};

static const char *sym_hist_filter;

61
static int symbol_filter(struct map *map __used, struct symbol *sym)
62
{
63 64
	if (sym_hist_filter == NULL ||
	    strcmp(sym->name, sym_hist_filter) == 0) {
65
		struct sym_priv *priv = symbol__priv(sym);
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		const int size = (sizeof(*priv->hist) +
				  (sym->end - sym->start) * sizeof(u64));

		priv->hist = malloc(size);
		if (priv->hist)
			memset(priv->hist, 0, size);
		return 0;
	}
	/*
	 * FIXME: We should really filter it out, as we don't want to go thru symbols
	 * we're not interested, and if a DSO ends up with no symbols, delete it too,
	 * but right now the kernel loading routines in symbol.c bail out if no symbols
	 * are found, fix it later.
	 */
	return 0;
}
82

83 84 85
/*
 * collect histogram counts
 */
86
static void hist_hit(struct hist_entry *he, u64 ip)
87
{
88 89
	unsigned int sym_size, offset;
	struct symbol *sym = he->sym;
90 91
	struct sym_priv *priv;
	struct sym_hist *h;
92

93
	he->count++;
94

95 96 97
	if (!sym || !he->map)
		return;

98
	priv = symbol__priv(sym);
99
	if (!priv->hist)
100
		return;
101

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

105 106 107 108
	if (verbose)
		fprintf(stderr, "%s: ip=%Lx\n", __func__,
			he->map->unmap_ip(he->map, ip));

109 110
	if (offset >= sym_size)
		return;
111

112 113 114
	h = priv->hist;
	h->sum++;
	h->ip[offset]++;
115

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

124 125
static int hist_entry__add(struct thread *thread, struct map *map,
			   struct symbol *sym, u64 ip, u64 count, char level)
126
{
127 128 129 130
	bool hit;
	struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
						  count, level, &hit);
	if (he == NULL)
131
		return -ENOMEM;
132
	hist_hit(he, ip);
133 134 135 136
	return 0;
}

static int
137
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
138 139
{
	char level;
140
	u64 ip = event->ip.ip;
141
	struct map *map = NULL;
142
	struct symbol *sym = NULL;
143
	struct thread *thread = threads__findnew(event->ip.pid);
144

145
	dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
146 147 148 149 150 151 152 153 154 155 156 157
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->header.misc,
		event->ip.pid,
		(void *)(long)ip);

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

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

160
	if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
161
		level = 'k';
162
		sym = kernel_maps__find_symbol(ip, &map, symbol_filter);
163 164
		dump_printf(" ...... dso: %s\n",
			    map ? map->dso->long_name : "<not found>");
165
	} else if (event->header.misc & PERF_RECORD_MISC_USER) {
166 167 168
		level = '.';
		map = thread__find_map(thread, ip);
		if (map != NULL) {
169
got_map:
170
			ip = map->map_ip(map, ip);
171
			sym = map__find_symbol(map, ip, symbol_filter);
172 173 174 175 176
		} 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
177 178 179 180 181
			 * vsyscall or vdso (which executes in user-mode).
			 *
			 * XXX This is nasty, we should have a symbol list in
			 * the "[vdso]" dso, but for now lets use the old
			 * trick of looking in the whole kernel symbol list.
182
			 */
183 184 185 186
			if ((long long)ip < 0) {
				map = kernel_map;
				goto got_map;
			}
187
		}
188 189
		dump_printf(" ...... dso: %s\n",
			    map ? map->dso->long_name : "<not found>");
190 191
	} else {
		level = 'H';
192
		dump_printf(" ...... dso: [hypervisor]\n");
193 194
	}

195 196 197 198
	if (hist_entry__add(thread, map, sym, ip, 1, level)) {
		fprintf(stderr, "problem incrementing symbol count, "
				"skipping event\n");
		return -1;
199 200 201 202 203 204 205 206 207
	}
	total++;

	return 0;
}

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

210
	dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
211 212 213 214 215 216
		(void *)(offset + head),
		(void *)(long)(event->header.size),
		event->comm.comm, event->comm.pid);

	if (thread == NULL ||
	    thread__set_comm(thread, event->comm.comm)) {
217
		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
218 219 220 221 222 223 224 225 226 227 228
		return -1;
	}
	total_comm++;

	return 0;
}

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

232
	case PERF_RECORD_MMAP:
233 234
		return process_mmap_event(event, offset, head);

235
	case PERF_RECORD_COMM:
236 237
		return process_comm_event(event, offset, head);

238
	case PERF_RECORD_FORK:
239
		return process_task_event(event, offset, head);
240 241 242 243
	/*
	 * We dont process them right now but they are fine:
	 */

244 245
	case PERF_RECORD_THROTTLE:
	case PERF_RECORD_UNTHROTTLE:
246 247 248 249 250 251 252 253 254
		return 0;

	default:
		return -1;
	}

	return 0;
}

255
static int parse_line(FILE *file, struct hist_entry *he, u64 len)
256
{
257
	struct symbol *sym = he->sym;
258
	char *line = NULL, *tmp, *tmp2;
259 260
	static const char *prev_line;
	static const char *prev_color;
261 262
	unsigned int offset;
	size_t line_len;
263
	u64 start;
264
	s64 line_ip;
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	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;
	}

300 301
	start = he->map->unmap_ip(he->map, sym->start);

302
	if (line_ip != -1) {
303
		const char *path = NULL;
304 305
		unsigned int hits = 0;
		double percent = 0.0;
306
		const char *color;
307
		struct sym_priv *priv = symbol__priv(sym);
308 309
		struct sym_ext *sym_ext = priv->ext;
		struct sym_hist *h = priv->hist;
310

311
		offset = line_ip - start;
312
		if (offset < len)
313
			hits = h->ip[offset];
314

315
		if (offset < len && sym_ext) {
316 317
			path = sym_ext[offset].path;
			percent = sym_ext[offset].percent;
318 319
		} else if (h->sum)
			percent = 100.0 * hits / h->sum;
320

321
		color = get_percent_color(percent);
322

323 324 325 326 327 328 329 330 331 332 333 334 335 336
		/*
		 * 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;
			}
		}

337 338 339 340 341 342 343 344 345 346 347 348 349
		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;
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
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);
}

372
static void free_source_line(struct hist_entry *he, int len)
373
{
374
	struct sym_priv *priv = symbol__priv(he->sym);
375
	struct sym_ext *sym_ext = priv->ext;
376 377 378 379 380 381 382 383 384
	int i;

	if (!sym_ext)
		return;

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

385
	priv->ext = NULL;
386
	root_sym_ext = RB_ROOT;
387 388 389
}

/* Get the filename:line for the colored entries */
390
static void
391
get_source_line(struct hist_entry *he, int len, const char *filename)
392
{
393 394
	struct symbol *sym = he->sym;
	u64 start;
395 396 397
	int i;
	char cmd[PATH_MAX * 2];
	struct sym_ext *sym_ext;
398
	struct sym_priv *priv = symbol__priv(sym);
399
	struct sym_hist *h = priv->hist;
400

401
	if (!h->sum)
402 403
		return;

404 405
	sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
	if (!priv->ext)
406 407
		return;

408
	start = he->map->unmap_ip(he->map, sym->start);
409 410 411 412

	for (i = 0; i < len; i++) {
		char *path = NULL;
		size_t line_len;
413
		u64 offset;
414 415
		FILE *fp;

416
		sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
417 418 419
		if (sym_ext[i].percent <= 0.5)
			continue;

420
		offset = start + i;
421
		sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
422 423 424 425 426 427 428
		fp = popen(cmd, "r");
		if (!fp)
			continue;

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

429
		sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
430 431 432 433
		if (!sym_ext[i].path)
			goto next;

		strcpy(sym_ext[i].path, path);
434
		insert_source_line(&sym_ext[i]);
435 436 437 438 439 440

	next:
		pclose(fp);
	}
}

441
static void print_summary(const char *filename)
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
{
	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;
457
		const char *color;
458 459 460 461
		char *path;

		sym_ext = rb_entry(node, struct sym_ext, node);
		percent = sym_ext->percent;
462
		color = get_percent_color(percent);
463 464 465 466 467 468 469
		path = sym_ext->path;

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

470
static void annotate_sym(struct hist_entry *he)
471
{
472 473 474
	struct map *map = he->map;
	struct dso *dso = map->dso;
	struct symbol *sym = he->sym;
475 476
	const char *filename = dso->long_name, *d_filename;
	u64 len;
477 478 479 480 481
	char command[PATH_MAX*2];
	FILE *file;

	if (!filename)
		return;
482

483 484 485 486 487 488
	if (verbose)
		fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
			__func__, filename, sym->name,
			map->unmap_ip(map, sym->start),
			map->unmap_ip(map, sym->end));

489 490 491 492
	if (full_paths)
		d_filename = filename;
	else
		d_filename = basename(filename);
493 494 495

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

496
	if (print_line) {
497
		get_source_line(he, len, filename);
498 499 500 501
		print_summary(filename);
	}

	printf("\n\n------------------------------------------------\n");
502
	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
503 504 505
	printf("------------------------------------------------\n");

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

509
	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
510 511
		map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
		filename, filename);
512 513 514 515 516 517 518 519 520

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

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

	while (!feof(file)) {
521
		if (parse_line(file, he, len) < 0)
522 523 524 525
			break;
	}

	pclose(file);
526
	if (print_line)
527
		free_source_line(he, len);
528 529 530 531 532 533
}

static void find_annotations(void)
{
	struct rb_node *nd;

534 535
	for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
536
		struct sym_priv *priv;
537

538 539
		if (he->sym == NULL)
			continue;
540

541
		priv = symbol__priv(he->sym);
542 543 544 545 546 547 548 549 550 551
		if (priv->hist == NULL)
			continue;

		annotate_sym(he);
		/*
		 * Since we have a hist_entry per IP for the same symbol, free
		 * he->sym->hist to signal we already processed this symbol.
		 */
		free(priv->hist);
		priv->hist = NULL;
552 553 554
	}
}

555 556 557 558 559
static int __cmd_annotate(void)
{
	int ret, rc = EXIT_FAILURE;
	unsigned long offset = 0;
	unsigned long head = 0;
560
	struct stat input_stat;
561 562 563 564
	event_t *event;
	uint32_t size;
	char *buf;

565
	register_idle_thread();
566 567 568 569 570 571 572

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

573
	ret = fstat(input, &input_stat);
574 575 576 577 578
	if (ret < 0) {
		perror("failed to stat file");
		exit(-1);
	}

579 580
	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);
581 582 583
		exit(-1);
	}

584
	if (!input_stat.st_size) {
585 586 587 588
		fprintf(stderr, "zero-sized file, nothing to do!\n");
		exit(0);
	}

589
	if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) {
590 591
		pr_err("failed to create kernel maps for symbol resolution\b");
		return -1;
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	}

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);
611
		int munmap_ret;
612

613 614
		munmap_ret = munmap(buf, page_size * mmap_window);
		assert(munmap_ret == 0);
615 616 617 618 619 620 621 622

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

	size = event->header.size;

623
	dump_printf("%p [%p]: event: %d\n",
624 625 626 627 628 629
			(void *)(offset + head),
			(void *)(long)event->header.size,
			event->header.type);

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

630
		dump_printf("%p [%p]: skipping unknown header type: %d\n",
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
			(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;

650
	if (offset + head < (unsigned long)input_stat.st_size)
651 652 653 654 655
		goto more;

	rc = EXIT_SUCCESS;
	close(input);

656 657 658 659 660
	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);
661 662 663 664

	if (dump_trace)
		return 0;

665
	if (verbose > 3)
666
		threads__fprintf(stdout);
667

668
	if (verbose > 2)
669 670 671
		dsos__fprintf(stdout);

	collapse__resort();
672
	output__resort(total);
673 674

	find_annotations();
675 676 677 678 679 680 681 682 683 684 685 686

	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"),
687
	OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
688
		    "symbol to annotate"),
689
	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
690 691 692 693
	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"),
694
	OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
695
	OPT_BOOLEAN('m', "modules", &use_modules,
696
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
697 698
	OPT_BOOLEAN('l', "print-line", &print_line,
		    "print matching source lines (may be slow)"),
699 700
	OPT_BOOLEAN('P', "full-paths", &full_paths,
		    "Don't shorten the displayed pathnames"),
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
	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);
}

719
int cmd_annotate(int argc, const char **argv, const char *prefix __used)
720
{
721
	symbol__init(sizeof(struct sym_priv));
722 723 724 725 726 727 728

	page_size = getpagesize();

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

	setup_sorting();

729 730 731 732 733 734 735 736 737 738 739
	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];
	}

740 741
	setup_pager();

742 743 744 745 746 747
	if (field_sep && *field_sep == '.') {
		fputs("'.' is the only non valid --field-separator argument\n",
				stderr);
		exit(129);
	}

748 749
	return __cmd_annotate();
}