perf symbols: Support multiple symtabs in struct thread
[safe/jmp/linux-2.6] / tools / perf / builtin-annotate.c
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"
13 #include <linux/list.h>
14 #include "util/cache.h"
15 #include <linux/rbtree.h>
16 #include "util/symbol.h"
17 #include "util/string.h"
18
19 #include "perf.h"
20 #include "util/debug.h"
21
22 #include "util/parse-options.h"
23 #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 static char             const *input_name = "perf.data";
30
31 static int              force;
32 static int              input;
33
34 static int              full_paths;
35
36 static int              print_line;
37
38 static unsigned long    page_size;
39 static unsigned long    mmap_window = 32;
40
41 struct sym_hist {
42         u64             sum;
43         u64             ip[0];
44 };
45
46 struct sym_ext {
47         struct rb_node  node;
48         double          percent;
49         char            *path;
50 };
51
52 struct sym_priv {
53         struct sym_hist *hist;
54         struct sym_ext  *ext;
55 };
56
57 static struct symbol_conf symbol_conf = {
58         .priv_size        = sizeof(struct sym_priv),
59         .try_vmlinux_path = true,
60 };
61
62 static const char *sym_hist_filter;
63
64 static int symbol_filter(struct map *map __used, struct symbol *sym)
65 {
66         if (sym_hist_filter == NULL ||
67             strcmp(sym->name, sym_hist_filter) == 0) {
68                 struct sym_priv *priv = symbol__priv(sym);
69                 const int size = (sizeof(*priv->hist) +
70                                   (sym->end - sym->start) * sizeof(u64));
71
72                 priv->hist = malloc(size);
73                 if (priv->hist)
74                         memset(priv->hist, 0, size);
75                 return 0;
76         }
77         /*
78          * FIXME: We should really filter it out, as we don't want to go thru symbols
79          * we're not interested, and if a DSO ends up with no symbols, delete it too,
80          * but right now the kernel loading routines in symbol.c bail out if no symbols
81          * are found, fix it later.
82          */
83         return 0;
84 }
85
86 /*
87  * collect histogram counts
88  */
89 static void hist_hit(struct hist_entry *he, u64 ip)
90 {
91         unsigned int sym_size, offset;
92         struct symbol *sym = he->sym;
93         struct sym_priv *priv;
94         struct sym_hist *h;
95
96         he->count++;
97
98         if (!sym || !he->map)
99                 return;
100
101         priv = symbol__priv(sym);
102         if (!priv->hist)
103                 return;
104
105         sym_size = sym->end - sym->start;
106         offset = ip - sym->start;
107
108         if (verbose)
109                 fprintf(stderr, "%s: ip=%Lx\n", __func__,
110                         he->map->unmap_ip(he->map, ip));
111
112         if (offset >= sym_size)
113                 return;
114
115         h = priv->hist;
116         h->sum++;
117         h->ip[offset]++;
118
119         if (verbose >= 3)
120                 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
121                         (void *)(unsigned long)he->sym->start,
122                         he->sym->name,
123                         (void *)(unsigned long)ip, ip - he->sym->start,
124                         h->ip[offset]);
125 }
126
127 static int hist_entry__add(struct thread *thread, struct map *map,
128                            struct symbol *sym, u64 ip, u64 count, char level)
129 {
130         bool hit;
131         struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
132                                                   count, level, &hit);
133         if (he == NULL)
134                 return -ENOMEM;
135         hist_hit(he, ip);
136         return 0;
137 }
138
139 static int
140 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
141 {
142         char level;
143         u64 ip = event->ip.ip;
144         struct map *map = NULL;
145         struct symbol *sym = NULL;
146         struct thread *thread = threads__findnew(event->ip.pid);
147
148         dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
149                 (void *)(offset + head),
150                 (void *)(long)(event->header.size),
151                 event->header.misc,
152                 event->ip.pid,
153                 (void *)(long)ip);
154
155         if (thread == NULL) {
156                 fprintf(stderr, "problem processing %d event, skipping it.\n",
157                         event->header.type);
158                 return -1;
159         }
160
161         dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
162
163         if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
164                 level = 'k';
165                 sym = kernel_maps__find_function(ip, &map, symbol_filter);
166                 dump_printf(" ...... dso: %s\n",
167                             map ? map->dso->long_name : "<not found>");
168         } else if (event->header.misc & PERF_RECORD_MISC_USER) {
169                 level = '.';
170                 map = thread__find_map(thread, MAP__FUNCTION, ip);
171                 if (map != NULL) {
172                         ip = map->map_ip(map, ip);
173                         sym = map__find_symbol(map, ip, symbol_filter);
174                 } else {
175                         /*
176                          * If this is outside of all known maps,
177                          * and is a negative address, try to look it
178                          * up in the kernel dso, as it might be a
179                          * vsyscall or vdso (which executes in user-mode).
180                          *
181                          * XXX This is nasty, we should have a symbol list in
182                          * the "[vdso]" dso, but for now lets use the old
183                          * trick of looking in the whole kernel symbol list.
184                          */
185                         if ((long long)ip < 0)
186                                 sym = kernel_maps__find_function(ip, &map,
187                                                                  symbol_filter);
188                 }
189                 dump_printf(" ...... dso: %s\n",
190                             map ? map->dso->long_name : "<not found>");
191         } else {
192                 level = 'H';
193                 dump_printf(" ...... dso: [hypervisor]\n");
194         }
195
196         if (hist_entry__add(thread, map, sym, ip, 1, level)) {
197                 fprintf(stderr, "problem incrementing symbol count, "
198                                 "skipping event\n");
199                 return -1;
200         }
201         total++;
202
203         return 0;
204 }
205
206 static int
207 process_comm_event(event_t *event, unsigned long offset, unsigned long head)
208 {
209         struct thread *thread = threads__findnew(event->comm.pid);
210
211         dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
212                 (void *)(offset + head),
213                 (void *)(long)(event->header.size),
214                 event->comm.comm, event->comm.pid);
215
216         if (thread == NULL ||
217             thread__set_comm(thread, event->comm.comm)) {
218                 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
219                 return -1;
220         }
221         total_comm++;
222
223         return 0;
224 }
225
226 static int
227 process_event(event_t *event, unsigned long offset, unsigned long head)
228 {
229         switch (event->header.type) {
230         case PERF_RECORD_SAMPLE:
231                 return process_sample_event(event, offset, head);
232
233         case PERF_RECORD_MMAP:
234                 return process_mmap_event(event, offset, head);
235
236         case PERF_RECORD_COMM:
237                 return process_comm_event(event, offset, head);
238
239         case PERF_RECORD_FORK:
240                 return process_task_event(event, offset, head);
241         /*
242          * We dont process them right now but they are fine:
243          */
244
245         case PERF_RECORD_THROTTLE:
246         case PERF_RECORD_UNTHROTTLE:
247                 return 0;
248
249         default:
250                 return -1;
251         }
252
253         return 0;
254 }
255
256 static int parse_line(FILE *file, struct hist_entry *he, u64 len)
257 {
258         struct symbol *sym = he->sym;
259         char *line = NULL, *tmp, *tmp2;
260         static const char *prev_line;
261         static const char *prev_color;
262         unsigned int offset;
263         size_t line_len;
264         u64 start;
265         s64 line_ip;
266         int ret;
267         char *c;
268
269         if (getline(&line, &line_len, file) < 0)
270                 return -1;
271         if (!line)
272                 return -1;
273
274         c = strchr(line, '\n');
275         if (c)
276                 *c = 0;
277
278         line_ip = -1;
279         offset = 0;
280         ret = -2;
281
282         /*
283          * Strip leading spaces:
284          */
285         tmp = line;
286         while (*tmp) {
287                 if (*tmp != ' ')
288                         break;
289                 tmp++;
290         }
291
292         if (*tmp) {
293                 /*
294                  * Parse hexa addresses followed by ':'
295                  */
296                 line_ip = strtoull(tmp, &tmp2, 16);
297                 if (*tmp2 != ':')
298                         line_ip = -1;
299         }
300
301         start = he->map->unmap_ip(he->map, sym->start);
302
303         if (line_ip != -1) {
304                 const char *path = NULL;
305                 unsigned int hits = 0;
306                 double percent = 0.0;
307                 const char *color;
308                 struct sym_priv *priv = symbol__priv(sym);
309                 struct sym_ext *sym_ext = priv->ext;
310                 struct sym_hist *h = priv->hist;
311
312                 offset = line_ip - start;
313                 if (offset < len)
314                         hits = h->ip[offset];
315
316                 if (offset < len && sym_ext) {
317                         path = sym_ext[offset].path;
318                         percent = sym_ext[offset].percent;
319                 } else if (h->sum)
320                         percent = 100.0 * hits / h->sum;
321
322                 color = get_percent_color(percent);
323
324                 /*
325                  * Also color the filename and line if needed, with
326                  * the same color than the percentage. Don't print it
327                  * twice for close colored ip with the same filename:line
328                  */
329                 if (path) {
330                         if (!prev_line || strcmp(prev_line, path)
331                                        || color != prev_color) {
332                                 color_fprintf(stdout, color, " %s", path);
333                                 prev_line = path;
334                                 prev_color = color;
335                         }
336                 }
337
338                 color_fprintf(stdout, color, " %7.2f", percent);
339                 printf(" :      ");
340                 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
341         } else {
342                 if (!*line)
343                         printf("         :\n");
344                 else
345                         printf("         :      %s\n", line);
346         }
347
348         return 0;
349 }
350
351 static struct rb_root root_sym_ext;
352
353 static void insert_source_line(struct sym_ext *sym_ext)
354 {
355         struct sym_ext *iter;
356         struct rb_node **p = &root_sym_ext.rb_node;
357         struct rb_node *parent = NULL;
358
359         while (*p != NULL) {
360                 parent = *p;
361                 iter = rb_entry(parent, struct sym_ext, node);
362
363                 if (sym_ext->percent > iter->percent)
364                         p = &(*p)->rb_left;
365                 else
366                         p = &(*p)->rb_right;
367         }
368
369         rb_link_node(&sym_ext->node, parent, p);
370         rb_insert_color(&sym_ext->node, &root_sym_ext);
371 }
372
373 static void free_source_line(struct hist_entry *he, int len)
374 {
375         struct sym_priv *priv = symbol__priv(he->sym);
376         struct sym_ext *sym_ext = priv->ext;
377         int i;
378
379         if (!sym_ext)
380                 return;
381
382         for (i = 0; i < len; i++)
383                 free(sym_ext[i].path);
384         free(sym_ext);
385
386         priv->ext = NULL;
387         root_sym_ext = RB_ROOT;
388 }
389
390 /* Get the filename:line for the colored entries */
391 static void
392 get_source_line(struct hist_entry *he, int len, const char *filename)
393 {
394         struct symbol *sym = he->sym;
395         u64 start;
396         int i;
397         char cmd[PATH_MAX * 2];
398         struct sym_ext *sym_ext;
399         struct sym_priv *priv = symbol__priv(sym);
400         struct sym_hist *h = priv->hist;
401
402         if (!h->sum)
403                 return;
404
405         sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
406         if (!priv->ext)
407                 return;
408
409         start = he->map->unmap_ip(he->map, sym->start);
410
411         for (i = 0; i < len; i++) {
412                 char *path = NULL;
413                 size_t line_len;
414                 u64 offset;
415                 FILE *fp;
416
417                 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
418                 if (sym_ext[i].percent <= 0.5)
419                         continue;
420
421                 offset = start + i;
422                 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
423                 fp = popen(cmd, "r");
424                 if (!fp)
425                         continue;
426
427                 if (getline(&path, &line_len, fp) < 0 || !line_len)
428                         goto next;
429
430                 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
431                 if (!sym_ext[i].path)
432                         goto next;
433
434                 strcpy(sym_ext[i].path, path);
435                 insert_source_line(&sym_ext[i]);
436
437         next:
438                 pclose(fp);
439         }
440 }
441
442 static void print_summary(const char *filename)
443 {
444         struct sym_ext *sym_ext;
445         struct rb_node *node;
446
447         printf("\nSorted summary for file %s\n", filename);
448         printf("----------------------------------------------\n\n");
449
450         if (RB_EMPTY_ROOT(&root_sym_ext)) {
451                 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
452                 return;
453         }
454
455         node = rb_first(&root_sym_ext);
456         while (node) {
457                 double percent;
458                 const char *color;
459                 char *path;
460
461                 sym_ext = rb_entry(node, struct sym_ext, node);
462                 percent = sym_ext->percent;
463                 color = get_percent_color(percent);
464                 path = sym_ext->path;
465
466                 color_fprintf(stdout, color, " %7.2f %s", percent, path);
467                 node = rb_next(node);
468         }
469 }
470
471 static void annotate_sym(struct hist_entry *he)
472 {
473         struct map *map = he->map;
474         struct dso *dso = map->dso;
475         struct symbol *sym = he->sym;
476         const char *filename = dso->long_name, *d_filename;
477         u64 len;
478         char command[PATH_MAX*2];
479         FILE *file;
480
481         if (!filename)
482                 return;
483
484         if (verbose)
485                 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
486                         __func__, filename, sym->name,
487                         map->unmap_ip(map, sym->start),
488                         map->unmap_ip(map, sym->end));
489
490         if (full_paths)
491                 d_filename = filename;
492         else
493                 d_filename = basename(filename);
494
495         len = sym->end - sym->start;
496
497         if (print_line) {
498                 get_source_line(he, len, filename);
499                 print_summary(filename);
500         }
501
502         printf("\n\n------------------------------------------------\n");
503         printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
504         printf("------------------------------------------------\n");
505
506         if (verbose >= 2)
507                 printf("annotating [%p] %30s : [%p] %30s\n",
508                        dso, dso->long_name, sym, sym->name);
509
510         sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
511                 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
512                 filename, filename);
513
514         if (verbose >= 3)
515                 printf("doing: %s\n", command);
516
517         file = popen(command, "r");
518         if (!file)
519                 return;
520
521         while (!feof(file)) {
522                 if (parse_line(file, he, len) < 0)
523                         break;
524         }
525
526         pclose(file);
527         if (print_line)
528                 free_source_line(he, len);
529 }
530
531 static void find_annotations(void)
532 {
533         struct rb_node *nd;
534
535         for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
536                 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
537                 struct sym_priv *priv;
538
539                 if (he->sym == NULL)
540                         continue;
541
542                 priv = symbol__priv(he->sym);
543                 if (priv->hist == NULL)
544                         continue;
545
546                 annotate_sym(he);
547                 /*
548                  * Since we have a hist_entry per IP for the same symbol, free
549                  * he->sym->hist to signal we already processed this symbol.
550                  */
551                 free(priv->hist);
552                 priv->hist = NULL;
553         }
554 }
555
556 static int __cmd_annotate(void)
557 {
558         int ret, rc = EXIT_FAILURE;
559         unsigned long offset = 0;
560         unsigned long head = 0;
561         struct stat input_stat;
562         event_t *event;
563         uint32_t size;
564         char *buf;
565
566         register_idle_thread();
567
568         input = open(input_name, O_RDONLY);
569         if (input < 0) {
570                 perror("failed to open file");
571                 exit(-1);
572         }
573
574         ret = fstat(input, &input_stat);
575         if (ret < 0) {
576                 perror("failed to stat file");
577                 exit(-1);
578         }
579
580         if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
581                 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
582                 exit(-1);
583         }
584
585         if (!input_stat.st_size) {
586                 fprintf(stderr, "zero-sized file, nothing to do!\n");
587                 exit(0);
588         }
589
590 remap:
591         buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
592                            MAP_SHARED, input, offset);
593         if (buf == MAP_FAILED) {
594                 perror("failed to mmap file");
595                 exit(-1);
596         }
597
598 more:
599         event = (event_t *)(buf + head);
600
601         size = event->header.size;
602         if (!size)
603                 size = 8;
604
605         if (head + event->header.size >= page_size * mmap_window) {
606                 unsigned long shift = page_size * (head / page_size);
607                 int munmap_ret;
608
609                 munmap_ret = munmap(buf, page_size * mmap_window);
610                 assert(munmap_ret == 0);
611
612                 offset += shift;
613                 head -= shift;
614                 goto remap;
615         }
616
617         size = event->header.size;
618
619         dump_printf("%p [%p]: event: %d\n",
620                         (void *)(offset + head),
621                         (void *)(long)event->header.size,
622                         event->header.type);
623
624         if (!size || process_event(event, offset, head) < 0) {
625
626                 dump_printf("%p [%p]: skipping unknown header type: %d\n",
627                         (void *)(offset + head),
628                         (void *)(long)(event->header.size),
629                         event->header.type);
630
631                 total_unknown++;
632
633                 /*
634                  * assume we lost track of the stream, check alignment, and
635                  * increment a single u64 in the hope to catch on again 'soon'.
636                  */
637
638                 if (unlikely(head & 7))
639                         head &= ~7ULL;
640
641                 size = 8;
642         }
643
644         head += size;
645
646         if (offset + head < (unsigned long)input_stat.st_size)
647                 goto more;
648
649         rc = EXIT_SUCCESS;
650         close(input);
651
652         dump_printf("      IP events: %10ld\n", total);
653         dump_printf("    mmap events: %10ld\n", total_mmap);
654         dump_printf("    comm events: %10ld\n", total_comm);
655         dump_printf("    fork events: %10ld\n", total_fork);
656         dump_printf(" unknown events: %10ld\n", total_unknown);
657
658         if (dump_trace)
659                 return 0;
660
661         if (verbose > 3)
662                 threads__fprintf(stdout);
663
664         if (verbose > 2)
665                 dsos__fprintf(stdout);
666
667         collapse__resort();
668         output__resort(total);
669
670         find_annotations();
671
672         return rc;
673 }
674
675 static const char * const annotate_usage[] = {
676         "perf annotate [<options>] <command>",
677         NULL
678 };
679
680 static const struct option options[] = {
681         OPT_STRING('i', "input", &input_name, "file",
682                     "input file name"),
683         OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
684                     "symbol to annotate"),
685         OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
686         OPT_BOOLEAN('v', "verbose", &verbose,
687                     "be more verbose (show symbol address, etc)"),
688         OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
689                     "dump raw trace in ASCII"),
690         OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
691                    "file", "vmlinux pathname"),
692         OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
693                     "load module symbols - WARNING: use only with -k and LIVE kernel"),
694         OPT_BOOLEAN('l', "print-line", &print_line,
695                     "print matching source lines (may be slow)"),
696         OPT_BOOLEAN('P', "full-paths", &full_paths,
697                     "Don't shorten the displayed pathnames"),
698         OPT_END()
699 };
700
701 static void setup_sorting(void)
702 {
703         char *tmp, *tok, *str = strdup(sort_order);
704
705         for (tok = strtok_r(str, ", ", &tmp);
706                         tok; tok = strtok_r(NULL, ", ", &tmp)) {
707                 if (sort_dimension__add(tok) < 0) {
708                         error("Unknown --sort key: `%s'", tok);
709                         usage_with_options(annotate_usage, options);
710                 }
711         }
712
713         free(str);
714 }
715
716 int cmd_annotate(int argc, const char **argv, const char *prefix __used)
717 {
718         if (symbol__init(&symbol_conf) < 0)
719                 return -1;
720
721         page_size = getpagesize();
722
723         argc = parse_options(argc, argv, options, annotate_usage, 0);
724
725         setup_sorting();
726
727         if (argc) {
728                 /*
729                  * Special case: if there's an argument left then assume tha
730                  * it's a symbol filter:
731                  */
732                 if (argc > 1)
733                         usage_with_options(annotate_usage, options);
734
735                 sym_hist_filter = argv[0];
736         }
737
738         setup_pager();
739
740         if (field_sep && *field_sep == '.') {
741                 fputs("'.' is the only non valid --field-separator argument\n",
742                                 stderr);
743                 exit(129);
744         }
745
746         return __cmd_annotate();
747 }