]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - tools/perf/builtin-annotate.c
perf tools: Librarize sample type and attr finding from headers
[mirror_ubuntu-zesty-kernel.git] / tools / perf / builtin-annotate.c
CommitLineData
8035e428
IM
1/*
2 * builtin-annotate.c
3 *
4 * Builtin annotate command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
8#include "builtin.h"
9
10#include "util/util.h"
11
12#include "util/color.h"
5da50258 13#include <linux/list.h>
8035e428 14#include "util/cache.h"
43cbcd8a 15#include <linux/rbtree.h>
8035e428
IM
16#include "util/symbol.h"
17#include "util/string.h"
18
19#include "perf.h"
20
21#include "util/parse-options.h"
22#include "util/parse-events.h"
6baa0a5a 23#include "util/thread.h"
8035e428 24
8035e428 25static char const *input_name = "perf.data";
8035e428 26
0b73da3f 27static char default_sort_order[] = "comm,symbol";
8035e428
IM
28static char *sort_order = default_sort_order;
29
30static int input;
31static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
32
42976487
MG
33static int full_paths;
34
301406b9
FW
35static int print_line;
36
8035e428
IM
37static unsigned long page_size;
38static unsigned long mmap_window = 32;
39
6baa0a5a
FW
40static struct rb_root threads;
41static struct thread *last_match;
42
301406b9
FW
43
44struct sym_ext {
971738f3 45 struct rb_node node;
301406b9
FW
46 double percent;
47 char *path;
48};
49
8035e428
IM
50/*
51 * histogram, sorted on item, collects counts
52 */
53
54static struct rb_root hist;
55
56struct hist_entry {
57 struct rb_node rb_node;
58
59 struct thread *thread;
60 struct map *map;
61 struct dso *dso;
62 struct symbol *sym;
9cffa8d5 63 u64 ip;
8035e428
IM
64 char level;
65
66 uint32_t count;
67};
68
69/*
70 * configurable sorting bits
71 */
72
73struct sort_entry {
74 struct list_head list;
75
83a0944f 76 const char *header;
8035e428
IM
77
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *);
81};
82
83/* --sort pid */
84
85static int64_t
86sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
87{
88 return right->thread->pid - left->thread->pid;
89}
90
91static size_t
92sort__thread_print(FILE *fp, struct hist_entry *self)
93{
94 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
95}
96
97static struct sort_entry sort_thread = {
98 .header = " Command: Pid",
99 .cmp = sort__thread_cmp,
100 .print = sort__thread_print,
101};
102
103/* --sort comm */
104
105static int64_t
106sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
107{
108 return right->thread->pid - left->thread->pid;
109}
110
111static int64_t
112sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
113{
114 char *comm_l = left->thread->comm;
115 char *comm_r = right->thread->comm;
116
117 if (!comm_l || !comm_r) {
118 if (!comm_l && !comm_r)
119 return 0;
120 else if (!comm_l)
121 return -1;
122 else
123 return 1;
124 }
125
126 return strcmp(comm_l, comm_r);
127}
128
129static size_t
130sort__comm_print(FILE *fp, struct hist_entry *self)
131{
132 return fprintf(fp, "%16s", self->thread->comm);
133}
134
135static struct sort_entry sort_comm = {
136 .header = " Command",
137 .cmp = sort__comm_cmp,
138 .collapse = sort__comm_collapse,
139 .print = sort__comm_print,
140};
141
142/* --sort dso */
143
144static int64_t
145sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
146{
147 struct dso *dso_l = left->dso;
148 struct dso *dso_r = right->dso;
149
150 if (!dso_l || !dso_r) {
151 if (!dso_l && !dso_r)
152 return 0;
153 else if (!dso_l)
154 return -1;
155 else
156 return 1;
157 }
158
159 return strcmp(dso_l->name, dso_r->name);
160}
161
162static size_t
163sort__dso_print(FILE *fp, struct hist_entry *self)
164{
165 if (self->dso)
166 return fprintf(fp, "%-25s", self->dso->name);
167
9cffa8d5 168 return fprintf(fp, "%016llx ", (u64)self->ip);
8035e428
IM
169}
170
171static struct sort_entry sort_dso = {
172 .header = "Shared Object ",
173 .cmp = sort__dso_cmp,
174 .print = sort__dso_print,
175};
176
177/* --sort symbol */
178
179static int64_t
180sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
181{
9cffa8d5 182 u64 ip_l, ip_r;
8035e428
IM
183
184 if (left->sym == right->sym)
185 return 0;
186
187 ip_l = left->sym ? left->sym->start : left->ip;
188 ip_r = right->sym ? right->sym->start : right->ip;
189
190 return (int64_t)(ip_r - ip_l);
191}
192
193static size_t
194sort__sym_print(FILE *fp, struct hist_entry *self)
195{
196 size_t ret = 0;
197
198 if (verbose)
9cffa8d5 199 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
8035e428
IM
200
201 if (self->sym) {
202 ret += fprintf(fp, "[%c] %s",
203 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
204 } else {
9cffa8d5 205 ret += fprintf(fp, "%#016llx", (u64)self->ip);
8035e428
IM
206 }
207
208 return ret;
209}
210
211static struct sort_entry sort_sym = {
212 .header = "Symbol",
213 .cmp = sort__sym_cmp,
214 .print = sort__sym_print,
215};
216
217static int sort__need_collapse = 0;
218
219struct sort_dimension {
83a0944f 220 const char *name;
8035e428
IM
221 struct sort_entry *entry;
222 int taken;
223};
224
225static struct sort_dimension sort_dimensions[] = {
226 { .name = "pid", .entry = &sort_thread, },
227 { .name = "comm", .entry = &sort_comm, },
228 { .name = "dso", .entry = &sort_dso, },
229 { .name = "symbol", .entry = &sort_sym, },
230};
231
232static LIST_HEAD(hist_entry__sort_list);
233
234static int sort_dimension__add(char *tok)
235{
f37a291c 236 unsigned int i;
8035e428
IM
237
238 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
239 struct sort_dimension *sd = &sort_dimensions[i];
240
241 if (sd->taken)
242 continue;
243
244 if (strncasecmp(tok, sd->name, strlen(tok)))
245 continue;
246
247 if (sd->entry->collapse)
248 sort__need_collapse = 1;
249
250 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
251 sd->taken = 1;
252
253 return 0;
254 }
255
256 return -ESRCH;
257}
258
259static int64_t
260hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
261{
262 struct sort_entry *se;
263 int64_t cmp = 0;
264
265 list_for_each_entry(se, &hist_entry__sort_list, list) {
266 cmp = se->cmp(left, right);
267 if (cmp)
268 break;
269 }
270
271 return cmp;
272}
273
274static int64_t
275hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
276{
277 struct sort_entry *se;
278 int64_t cmp = 0;
279
280 list_for_each_entry(se, &hist_entry__sort_list, list) {
281 int64_t (*f)(struct hist_entry *, struct hist_entry *);
282
283 f = se->collapse ?: se->cmp;
284
285 cmp = f(left, right);
286 if (cmp)
287 break;
288 }
289
290 return cmp;
291}
292
0b73da3f
IM
293/*
294 * collect histogram counts
295 */
9cffa8d5 296static void hist_hit(struct hist_entry *he, u64 ip)
8035e428 297{
0b73da3f
IM
298 unsigned int sym_size, offset;
299 struct symbol *sym = he->sym;
8035e428 300
0b73da3f 301 he->count++;
8035e428 302
0b73da3f
IM
303 if (!sym || !sym->hist)
304 return;
8035e428 305
0b73da3f
IM
306 sym_size = sym->end - sym->start;
307 offset = ip - sym->start;
8035e428 308
0b73da3f
IM
309 if (offset >= sym_size)
310 return;
8035e428 311
0b73da3f
IM
312 sym->hist_sum++;
313 sym->hist[offset]++;
8035e428 314
0b73da3f
IM
315 if (verbose >= 3)
316 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
7d37a0cb 317 (void *)(unsigned long)he->sym->start,
0b73da3f 318 he->sym->name,
7d37a0cb 319 (void *)(unsigned long)ip, ip - he->sym->start,
0b73da3f 320 sym->hist[offset]);
8035e428
IM
321}
322
8035e428
IM
323static int
324hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
9cffa8d5 325 struct symbol *sym, u64 ip, char level)
8035e428
IM
326{
327 struct rb_node **p = &hist.rb_node;
328 struct rb_node *parent = NULL;
329 struct hist_entry *he;
330 struct hist_entry entry = {
331 .thread = thread,
332 .map = map,
333 .dso = dso,
334 .sym = sym,
335 .ip = ip,
336 .level = level,
337 .count = 1,
338 };
339 int cmp;
340
341 while (*p != NULL) {
342 parent = *p;
343 he = rb_entry(parent, struct hist_entry, rb_node);
344
345 cmp = hist_entry__cmp(&entry, he);
346
347 if (!cmp) {
0b73da3f
IM
348 hist_hit(he, ip);
349
8035e428
IM
350 return 0;
351 }
352
353 if (cmp < 0)
354 p = &(*p)->rb_left;
355 else
356 p = &(*p)->rb_right;
357 }
358
359 he = malloc(sizeof(*he));
360 if (!he)
361 return -ENOMEM;
362 *he = entry;
363 rb_link_node(&he->rb_node, parent, p);
364 rb_insert_color(&he->rb_node, &hist);
365
366 return 0;
367}
368
369static void hist_entry__free(struct hist_entry *he)
370{
371 free(he);
372}
373
374/*
375 * collapse the histogram
376 */
377
378static struct rb_root collapse_hists;
379
380static void collapse__insert_entry(struct hist_entry *he)
381{
382 struct rb_node **p = &collapse_hists.rb_node;
383 struct rb_node *parent = NULL;
384 struct hist_entry *iter;
385 int64_t cmp;
386
387 while (*p != NULL) {
388 parent = *p;
389 iter = rb_entry(parent, struct hist_entry, rb_node);
390
391 cmp = hist_entry__collapse(iter, he);
392
393 if (!cmp) {
394 iter->count += he->count;
395 hist_entry__free(he);
396 return;
397 }
398
399 if (cmp < 0)
400 p = &(*p)->rb_left;
401 else
402 p = &(*p)->rb_right;
403 }
404
405 rb_link_node(&he->rb_node, parent, p);
406 rb_insert_color(&he->rb_node, &collapse_hists);
407}
408
409static void collapse__resort(void)
410{
411 struct rb_node *next;
412 struct hist_entry *n;
413
414 if (!sort__need_collapse)
415 return;
416
417 next = rb_first(&hist);
418 while (next) {
419 n = rb_entry(next, struct hist_entry, rb_node);
420 next = rb_next(&n->rb_node);
421
422 rb_erase(&n->rb_node, &hist);
423 collapse__insert_entry(n);
424 }
425}
426
427/*
428 * reverse the map, sort on count.
429 */
430
431static struct rb_root output_hists;
432
433static void output__insert_entry(struct hist_entry *he)
434{
435 struct rb_node **p = &output_hists.rb_node;
436 struct rb_node *parent = NULL;
437 struct hist_entry *iter;
438
439 while (*p != NULL) {
440 parent = *p;
441 iter = rb_entry(parent, struct hist_entry, rb_node);
442
443 if (he->count > iter->count)
444 p = &(*p)->rb_left;
445 else
446 p = &(*p)->rb_right;
447 }
448
449 rb_link_node(&he->rb_node, parent, p);
450 rb_insert_color(&he->rb_node, &output_hists);
451}
452
453static void output__resort(void)
454{
455 struct rb_node *next;
456 struct hist_entry *n;
457 struct rb_root *tree = &hist;
458
459 if (sort__need_collapse)
460 tree = &collapse_hists;
461
462 next = rb_first(tree);
463
464 while (next) {
465 n = rb_entry(next, struct hist_entry, rb_node);
466 next = rb_next(&n->rb_node);
467
468 rb_erase(&n->rb_node, tree);
469 output__insert_entry(n);
470 }
471}
472
8035e428
IM
473static void register_idle_thread(void)
474{
6baa0a5a 475 struct thread *thread = threads__findnew(0, &threads, &last_match);
8035e428
IM
476
477 if (thread == NULL ||
478 thread__set_comm(thread, "[idle]")) {
479 fprintf(stderr, "problem inserting idle task.\n");
480 exit(-1);
481 }
482}
483
484static unsigned long total = 0,
485 total_mmap = 0,
486 total_comm = 0,
487 total_fork = 0,
488 total_unknown = 0;
489
490static int
e6e18ec7 491process_sample_event(event_t *event, unsigned long offset, unsigned long head)
8035e428
IM
492{
493 char level;
494 int show = 0;
495 struct dso *dso = NULL;
6baa0a5a 496 struct thread *thread;
9cffa8d5 497 u64 ip = event->ip.ip;
8035e428
IM
498 struct map *map = NULL;
499
6baa0a5a
FW
500 thread = threads__findnew(event->ip.pid, &threads, &last_match);
501
2cec19d9 502 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
8035e428
IM
503 (void *)(offset + head),
504 (void *)(long)(event->header.size),
505 event->header.misc,
506 event->ip.pid,
507 (void *)(long)ip);
508
2cec19d9 509 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
8035e428
IM
510
511 if (thread == NULL) {
512 fprintf(stderr, "problem processing %d event, skipping it.\n",
513 event->header.type);
514 return -1;
515 }
516
517 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
518 show = SHOW_KERNEL;
519 level = 'k';
520
521 dso = kernel_dso;
522
2cec19d9 523 dump_printf(" ...... dso: %s\n", dso->name);
8035e428
IM
524
525 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
526
527 show = SHOW_USER;
528 level = '.';
529
530 map = thread__find_map(thread, ip);
531 if (map != NULL) {
532 ip = map->map_ip(map, ip);
533 dso = map->dso;
534 } else {
535 /*
536 * If this is outside of all known maps,
537 * and is a negative address, try to look it
538 * up in the kernel dso, as it might be a
539 * vsyscall (which executes in user-mode):
540 */
541 if ((long long)ip < 0)
542 dso = kernel_dso;
543 }
2cec19d9 544 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
8035e428
IM
545
546 } else {
547 show = SHOW_HV;
548 level = 'H';
2cec19d9 549 dump_printf(" ...... dso: [hypervisor]\n");
8035e428
IM
550 }
551
552 if (show & show_mask) {
553 struct symbol *sym = NULL;
554
555 if (dso)
556 sym = dso->find_symbol(dso, ip);
557
558 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
559 fprintf(stderr,
560 "problem incrementing symbol count, skipping event\n");
561 return -1;
562 }
563 }
564 total++;
565
566 return 0;
567}
568
569static int
570process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
571{
6baa0a5a 572 struct thread *thread;
66e274f3 573 struct map *map = map__new(&event->mmap, NULL, 0);
8035e428 574
6baa0a5a
FW
575 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
576
2cec19d9 577 dump_printf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
8035e428
IM
578 (void *)(offset + head),
579 (void *)(long)(event->header.size),
580 event->mmap.pid,
581 (void *)(long)event->mmap.start,
582 (void *)(long)event->mmap.len,
583 (void *)(long)event->mmap.pgoff,
584 event->mmap.filename);
585
586 if (thread == NULL || map == NULL) {
2cec19d9 587 dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n");
8035e428
IM
588 return 0;
589 }
590
591 thread__insert_map(thread, map);
592 total_mmap++;
593
594 return 0;
595}
596
597static int
598process_comm_event(event_t *event, unsigned long offset, unsigned long head)
599{
6baa0a5a 600 struct thread *thread;
8035e428 601
6baa0a5a 602 thread = threads__findnew(event->comm.pid, &threads, &last_match);
2cec19d9 603 dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
8035e428
IM
604 (void *)(offset + head),
605 (void *)(long)(event->header.size),
606 event->comm.comm, event->comm.pid);
607
608 if (thread == NULL ||
609 thread__set_comm(thread, event->comm.comm)) {
2cec19d9 610 dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n");
8035e428
IM
611 return -1;
612 }
613 total_comm++;
614
615 return 0;
616}
617
618static int
619process_fork_event(event_t *event, unsigned long offset, unsigned long head)
620{
6baa0a5a
FW
621 struct thread *thread;
622 struct thread *parent;
8035e428 623
6baa0a5a
FW
624 thread = threads__findnew(event->fork.pid, &threads, &last_match);
625 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
2cec19d9 626 dump_printf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
8035e428
IM
627 (void *)(offset + head),
628 (void *)(long)(event->header.size),
629 event->fork.pid, event->fork.ppid);
630
631 if (!thread || !parent || thread__fork(thread, parent)) {
2cec19d9 632 dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n");
8035e428
IM
633 return -1;
634 }
635 total_fork++;
636
637 return 0;
638}
639
8035e428
IM
640static int
641process_event(event_t *event, unsigned long offset, unsigned long head)
642{
8035e428 643 switch (event->header.type) {
e6e18ec7
PZ
644 case PERF_EVENT_SAMPLE:
645 return process_sample_event(event, offset, head);
646
8035e428
IM
647 case PERF_EVENT_MMAP:
648 return process_mmap_event(event, offset, head);
649
650 case PERF_EVENT_COMM:
651 return process_comm_event(event, offset, head);
652
653 case PERF_EVENT_FORK:
654 return process_fork_event(event, offset, head);
8035e428
IM
655 /*
656 * We dont process them right now but they are fine:
657 */
658
659 case PERF_EVENT_THROTTLE:
660 case PERF_EVENT_UNTHROTTLE:
661 return 0;
662
663 default:
664 return -1;
665 }
666
667 return 0;
668}
669
0b73da3f 670static int
9cffa8d5 671parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
0b73da3f
IM
672{
673 char *line = NULL, *tmp, *tmp2;
301406b9
FW
674 static const char *prev_line;
675 static const char *prev_color;
0b73da3f
IM
676 unsigned int offset;
677 size_t line_len;
f37a291c 678 s64 line_ip;
0b73da3f
IM
679 int ret;
680 char *c;
681
682 if (getline(&line, &line_len, file) < 0)
683 return -1;
684 if (!line)
685 return -1;
686
687 c = strchr(line, '\n');
688 if (c)
689 *c = 0;
690
691 line_ip = -1;
692 offset = 0;
693 ret = -2;
694
695 /*
696 * Strip leading spaces:
697 */
698 tmp = line;
699 while (*tmp) {
700 if (*tmp != ' ')
701 break;
702 tmp++;
703 }
704
705 if (*tmp) {
706 /*
707 * Parse hexa addresses followed by ':'
708 */
709 line_ip = strtoull(tmp, &tmp2, 16);
710 if (*tmp2 != ':')
711 line_ip = -1;
712 }
713
714 if (line_ip != -1) {
301406b9 715 const char *path = NULL;
0b73da3f
IM
716 unsigned int hits = 0;
717 double percent = 0.0;
83a0944f 718 const char *color;
301406b9 719 struct sym_ext *sym_ext = sym->priv;
0b73da3f
IM
720
721 offset = line_ip - start;
722 if (offset < len)
723 hits = sym->hist[offset];
724
c17c2db1 725 if (offset < len && sym_ext) {
301406b9
FW
726 path = sym_ext[offset].path;
727 percent = sym_ext[offset].percent;
728 } else if (sym->hist_sum)
0b73da3f
IM
729 percent = 100.0 * hits / sym->hist_sum;
730
1e11fd82 731 color = get_percent_color(percent);
0b73da3f 732
301406b9
FW
733 /*
734 * Also color the filename and line if needed, with
735 * the same color than the percentage. Don't print it
736 * twice for close colored ip with the same filename:line
737 */
738 if (path) {
739 if (!prev_line || strcmp(prev_line, path)
740 || color != prev_color) {
741 color_fprintf(stdout, color, " %s", path);
742 prev_line = path;
743 prev_color = color;
744 }
745 }
746
0b73da3f
IM
747 color_fprintf(stdout, color, " %7.2f", percent);
748 printf(" : ");
749 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
750 } else {
751 if (!*line)
752 printf(" :\n");
753 else
754 printf(" : %s\n", line);
755 }
756
757 return 0;
758}
759
971738f3
FW
760static struct rb_root root_sym_ext;
761
762static void insert_source_line(struct sym_ext *sym_ext)
763{
764 struct sym_ext *iter;
765 struct rb_node **p = &root_sym_ext.rb_node;
766 struct rb_node *parent = NULL;
767
768 while (*p != NULL) {
769 parent = *p;
770 iter = rb_entry(parent, struct sym_ext, node);
771
772 if (sym_ext->percent > iter->percent)
773 p = &(*p)->rb_left;
774 else
775 p = &(*p)->rb_right;
776 }
777
778 rb_link_node(&sym_ext->node, parent, p);
779 rb_insert_color(&sym_ext->node, &root_sym_ext);
780}
781
301406b9
FW
782static void free_source_line(struct symbol *sym, int len)
783{
784 struct sym_ext *sym_ext = sym->priv;
785 int i;
786
787 if (!sym_ext)
788 return;
789
790 for (i = 0; i < len; i++)
791 free(sym_ext[i].path);
792 free(sym_ext);
793
794 sym->priv = NULL;
971738f3 795 root_sym_ext = RB_ROOT;
301406b9
FW
796}
797
798/* Get the filename:line for the colored entries */
c17c2db1 799static void
83a0944f 800get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
301406b9
FW
801{
802 int i;
803 char cmd[PATH_MAX * 2];
804 struct sym_ext *sym_ext;
805
806 if (!sym->hist_sum)
807 return;
808
809 sym->priv = calloc(len, sizeof(struct sym_ext));
810 if (!sym->priv)
811 return;
812
813 sym_ext = sym->priv;
814
815 for (i = 0; i < len; i++) {
816 char *path = NULL;
817 size_t line_len;
9cffa8d5 818 u64 offset;
301406b9
FW
819 FILE *fp;
820
821 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
822 if (sym_ext[i].percent <= 0.5)
823 continue;
824
825 offset = start + i;
c17c2db1 826 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
301406b9
FW
827 fp = popen(cmd, "r");
828 if (!fp)
829 continue;
830
831 if (getline(&path, &line_len, fp) < 0 || !line_len)
832 goto next;
833
c17c2db1 834 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
301406b9
FW
835 if (!sym_ext[i].path)
836 goto next;
837
838 strcpy(sym_ext[i].path, path);
971738f3 839 insert_source_line(&sym_ext[i]);
301406b9
FW
840
841 next:
842 pclose(fp);
843 }
844}
845
83a0944f 846static void print_summary(const char *filename)
971738f3
FW
847{
848 struct sym_ext *sym_ext;
849 struct rb_node *node;
850
851 printf("\nSorted summary for file %s\n", filename);
852 printf("----------------------------------------------\n\n");
853
854 if (RB_EMPTY_ROOT(&root_sym_ext)) {
855 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
856 return;
857 }
858
859 node = rb_first(&root_sym_ext);
860 while (node) {
861 double percent;
83a0944f 862 const char *color;
971738f3
FW
863 char *path;
864
865 sym_ext = rb_entry(node, struct sym_ext, node);
866 percent = sym_ext->percent;
1e11fd82 867 color = get_percent_color(percent);
971738f3
FW
868 path = sym_ext->path;
869
870 color_fprintf(stdout, color, " %7.2f %s", percent, path);
871 node = rb_next(node);
872 }
873}
874
0b73da3f
IM
875static void annotate_sym(struct dso *dso, struct symbol *sym)
876{
83a0944f 877 const char *filename = dso->name, *d_filename;
9cffa8d5 878 u64 start, end, len;
0b73da3f
IM
879 char command[PATH_MAX*2];
880 FILE *file;
881
882 if (!filename)
883 return;
42976487
MG
884 if (sym->module)
885 filename = sym->module->path;
886 else if (dso == kernel_dso)
83a0944f 887 filename = vmlinux_name;
0b73da3f 888
0b73da3f
IM
889 start = sym->obj_start;
890 if (!start)
891 start = sym->start;
42976487
MG
892 if (full_paths)
893 d_filename = filename;
894 else
895 d_filename = basename(filename);
0b73da3f
IM
896
897 end = start + sym->end - sym->start + 1;
898 len = sym->end - sym->start;
899
971738f3 900 if (print_line) {
c17c2db1 901 get_source_line(sym, start, len, filename);
971738f3
FW
902 print_summary(filename);
903 }
904
905 printf("\n\n------------------------------------------------\n");
42976487 906 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
971738f3
FW
907 printf("------------------------------------------------\n");
908
909 if (verbose >= 2)
910 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
301406b9 911
42976487
MG
912 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
913 (u64)start, (u64)end, filename, filename);
0b73da3f
IM
914
915 if (verbose >= 3)
916 printf("doing: %s\n", command);
917
918 file = popen(command, "r");
919 if (!file)
920 return;
921
922 while (!feof(file)) {
923 if (parse_line(file, sym, start, len) < 0)
924 break;
925 }
926
927 pclose(file);
971738f3
FW
928 if (print_line)
929 free_source_line(sym, len);
0b73da3f
IM
930}
931
932static void find_annotations(void)
933{
934 struct rb_node *nd;
935 struct dso *dso;
936 int count = 0;
937
938 list_for_each_entry(dso, &dsos, node) {
939
940 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
941 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
942
943 if (sym->hist) {
944 annotate_sym(dso, sym);
945 count++;
946 }
947 }
948 }
949
950 if (!count)
951 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
952}
953
8035e428
IM
954static int __cmd_annotate(void)
955{
956 int ret, rc = EXIT_FAILURE;
957 unsigned long offset = 0;
958 unsigned long head = 0;
83a0944f 959 struct stat input_stat;
8035e428
IM
960 event_t *event;
961 uint32_t size;
962 char *buf;
963
964 register_idle_thread();
965
966 input = open(input_name, O_RDONLY);
967 if (input < 0) {
968 perror("failed to open file");
969 exit(-1);
970 }
971
83a0944f 972 ret = fstat(input, &input_stat);
8035e428
IM
973 if (ret < 0) {
974 perror("failed to stat file");
975 exit(-1);
976 }
977
83a0944f 978 if (!input_stat.st_size) {
8035e428
IM
979 fprintf(stderr, "zero-sized file, nothing to do!\n");
980 exit(0);
981 }
982
983 if (load_kernel() < 0) {
984 perror("failed to load kernel symbols");
985 return EXIT_FAILURE;
986 }
987
8035e428
IM
988remap:
989 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
990 MAP_SHARED, input, offset);
991 if (buf == MAP_FAILED) {
992 perror("failed to mmap file");
993 exit(-1);
994 }
995
996more:
997 event = (event_t *)(buf + head);
998
999 size = event->header.size;
1000 if (!size)
1001 size = 8;
1002
1003 if (head + event->header.size >= page_size * mmap_window) {
1004 unsigned long shift = page_size * (head / page_size);
83a0944f 1005 int munmap_ret;
8035e428 1006
83a0944f
IM
1007 munmap_ret = munmap(buf, page_size * mmap_window);
1008 assert(munmap_ret == 0);
8035e428
IM
1009
1010 offset += shift;
1011 head -= shift;
1012 goto remap;
1013 }
1014
1015 size = event->header.size;
1016
2cec19d9 1017 dump_printf("%p [%p]: event: %d\n",
8035e428
IM
1018 (void *)(offset + head),
1019 (void *)(long)event->header.size,
1020 event->header.type);
1021
1022 if (!size || process_event(event, offset, head) < 0) {
1023
2cec19d9 1024 dump_printf("%p [%p]: skipping unknown header type: %d\n",
8035e428
IM
1025 (void *)(offset + head),
1026 (void *)(long)(event->header.size),
1027 event->header.type);
1028
1029 total_unknown++;
1030
1031 /*
1032 * assume we lost track of the stream, check alignment, and
1033 * increment a single u64 in the hope to catch on again 'soon'.
1034 */
1035
1036 if (unlikely(head & 7))
1037 head &= ~7ULL;
1038
1039 size = 8;
1040 }
1041
1042 head += size;
1043
83a0944f 1044 if (offset + head < (unsigned long)input_stat.st_size)
8035e428
IM
1045 goto more;
1046
1047 rc = EXIT_SUCCESS;
1048 close(input);
1049
2cec19d9
FW
1050 dump_printf(" IP events: %10ld\n", total);
1051 dump_printf(" mmap events: %10ld\n", total_mmap);
1052 dump_printf(" comm events: %10ld\n", total_comm);
1053 dump_printf(" fork events: %10ld\n", total_fork);
1054 dump_printf(" unknown events: %10ld\n", total_unknown);
8035e428
IM
1055
1056 if (dump_trace)
1057 return 0;
1058
1059 if (verbose >= 3)
6baa0a5a 1060 threads__fprintf(stdout, &threads);
8035e428
IM
1061
1062 if (verbose >= 2)
1063 dsos__fprintf(stdout);
1064
1065 collapse__resort();
1066 output__resort();
0b73da3f
IM
1067
1068 find_annotations();
8035e428
IM
1069
1070 return rc;
1071}
1072
1073static const char * const annotate_usage[] = {
1074 "perf annotate [<options>] <command>",
1075 NULL
1076};
1077
1078static const struct option options[] = {
1079 OPT_STRING('i', "input", &input_name, "file",
1080 "input file name"),
23b87116 1081 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
0b73da3f 1082 "symbol to annotate"),
8035e428
IM
1083 OPT_BOOLEAN('v', "verbose", &verbose,
1084 "be more verbose (show symbol address, etc)"),
1085 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1086 "dump raw trace in ASCII"),
83a0944f 1087 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
42976487
MG
1088 OPT_BOOLEAN('m', "modules", &modules,
1089 "load module symbols - WARNING: use only with -k and LIVE kernel"),
301406b9
FW
1090 OPT_BOOLEAN('l', "print-line", &print_line,
1091 "print matching source lines (may be slow)"),
42976487
MG
1092 OPT_BOOLEAN('P', "full-paths", &full_paths,
1093 "Don't shorten the displayed pathnames"),
8035e428
IM
1094 OPT_END()
1095};
1096
1097static void setup_sorting(void)
1098{
1099 char *tmp, *tok, *str = strdup(sort_order);
1100
1101 for (tok = strtok_r(str, ", ", &tmp);
1102 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1103 if (sort_dimension__add(tok) < 0) {
1104 error("Unknown --sort key: `%s'", tok);
1105 usage_with_options(annotate_usage, options);
1106 }
1107 }
1108
1109 free(str);
1110}
1111
f37a291c 1112int cmd_annotate(int argc, const char **argv, const char *prefix __used)
8035e428
IM
1113{
1114 symbol__init();
1115
1116 page_size = getpagesize();
1117
1118 argc = parse_options(argc, argv, options, annotate_usage, 0);
1119
1120 setup_sorting();
1121
0b73da3f
IM
1122 if (argc) {
1123 /*
1124 * Special case: if there's an argument left then assume tha
1125 * it's a symbol filter:
1126 */
1127 if (argc > 1)
1128 usage_with_options(annotate_usage, options);
1129
1130 sym_hist_filter = argv[0];
1131 }
1132
1133 if (!sym_hist_filter)
8035e428
IM
1134 usage_with_options(annotate_usage, options);
1135
1136 setup_pager();
1137
1138 return __cmd_annotate();
1139}