aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-annotate.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-10-02 02:29:58 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-02 04:48:42 -0400
commit439d473b4777de510e1322168ac6f2f377ecd5bc (patch)
treef33622a0b98c2b0ce16637322d48542eb93e2fa3 /tools/perf/builtin-annotate.c
parent2ccdc450e658053681202d42ac64b3638f22dc1a (diff)
perf tools: Rewrite and improve support for kernel modules
Representing modules as struct map entries, backed by a DSO, etc, using /proc/modules to find where the module is loaded. DSOs now can have a short and long name, so that in verbose mode we can show exactly which .ko or vmlinux image was used. As kernel modules now are a DSO separate from the kernel, we can ask for just the hits for a particular set of kernel modules, just like we can do with shared libraries: [root@doppio linux-2.6-tip]# perf report -n --vmlinux /home/acme/git/build/tip-recvmmsg/vmlinux --modules --dsos \[drm\] | head -15 84.58% 13266 Xorg [k] drm_clflush_pages 4.02% 630 Xorg [k] trace_kmalloc.clone.0 3.95% 619 Xorg [k] drm_ioctl 2.07% 324 Xorg [k] drm_addbufs 1.68% 263 Xorg [k] drm_gem_close_ioctl 0.77% 120 Xorg [k] drm_setmaster_ioctl 0.70% 110 Xorg [k] drm_lastclose 0.68% 106 Xorg [k] drm_open 0.54% 85 Xorg [k] drm_mm_search_free [root@doppio linux-2.6-tip]# Specifying --dsos /lib/modules/2.6.31-tip/kernel/drivers/gpu/drm/drm.ko would have the same effect. Allowing specifying just 'drm.ko' is left for another patch. Processing kallsyms so that per kernel module struct map are instantiated was also left for another patch. That will allow removing the module name from each of its symbols. struct symbol was reduced by removing the ->module backpointer and moving it (well now the map) to struct symbol_entry in perf top, that is its only user right now. The total linecount went down by ~500 lines. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Avi Kivity <avi@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r--tools/perf/builtin-annotate.c73
1 files changed, 32 insertions, 41 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index df516dce9540..7d5a3b1bcda9 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -63,6 +63,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
63 return; 63 return;
64 64
65 sym_size = sym->end - sym->start; 65 sym_size = sym->end - sym->start;
66 ip = he->map->map_ip(he->map, ip);
66 offset = ip - sym->start; 67 offset = ip - sym->start;
67 68
68 if (offset >= sym_size) 69 if (offset >= sym_size)
@@ -80,7 +81,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
80} 81}
81 82
82static int 83static int
83hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 84hist_entry__add(struct thread *thread, struct map *map,
84 struct symbol *sym, u64 ip, char level) 85 struct symbol *sym, u64 ip, char level)
85{ 86{
86 struct rb_node **p = &hist.rb_node; 87 struct rb_node **p = &hist.rb_node;
@@ -89,7 +90,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
89 struct hist_entry entry = { 90 struct hist_entry entry = {
90 .thread = thread, 91 .thread = thread,
91 .map = map, 92 .map = map,
92 .dso = dso,
93 .sym = sym, 93 .sym = sym,
94 .ip = ip, 94 .ip = ip,
95 .level = level, 95 .level = level,
@@ -130,10 +130,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
130{ 130{
131 char level; 131 char level;
132 int show = 0; 132 int show = 0;
133 struct dso *dso = NULL;
134 struct thread *thread; 133 struct thread *thread;
135 u64 ip = event->ip.ip; 134 u64 ip = event->ip.ip;
136 struct map *map = NULL; 135 struct map *map = NULL;
136 struct symbol *sym = NULL;
137 137
138 thread = threads__findnew(event->ip.pid, &threads, &last_match); 138 thread = threads__findnew(event->ip.pid, &threads, &last_match);
139 139
@@ -155,32 +155,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
155 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 155 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
156 show = SHOW_KERNEL; 156 show = SHOW_KERNEL;
157 level = 'k'; 157 level = 'k';
158 158 sym = kernel_maps__find_symbol(ip, &map);
159 dso = kernel_dso; 159 dump_printf(" ...... dso: %s\n",
160 160 map ? map->dso->long_name : "<not found>");
161 dump_printf(" ...... dso: %s\n", dso->name);
162
163 } else if (event->header.misc & PERF_RECORD_MISC_USER) { 161 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
164
165 show = SHOW_USER; 162 show = SHOW_USER;
166 level = '.'; 163 level = '.';
167
168 map = thread__find_map(thread, ip); 164 map = thread__find_map(thread, ip);
169 if (map != NULL) { 165 if (map != NULL) {
166got_map:
170 ip = map->map_ip(map, ip); 167 ip = map->map_ip(map, ip);
171 dso = map->dso; 168 sym = map->dso->find_symbol(map->dso, ip);
172 } else { 169 } else {
173 /* 170 /*
174 * If this is outside of all known maps, 171 * If this is outside of all known maps,
175 * and is a negative address, try to look it 172 * and is a negative address, try to look it
176 * up in the kernel dso, as it might be a 173 * up in the kernel dso, as it might be a
177 * vsyscall (which executes in user-mode): 174 * vsyscall or vdso (which executes in user-mode).
175 *
176 * XXX This is nasty, we should have a symbol list in
177 * the "[vdso]" dso, but for now lets use the old
178 * trick of looking in the whole kernel symbol list.
178 */ 179 */
179 if ((long long)ip < 0) 180 if ((long long)ip < 0) {
180 dso = kernel_dso; 181 map = kernel_map;
182 goto got_map;
183 }
181 } 184 }
182 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 185 dump_printf(" ...... dso: %s\n",
183 186 map ? map->dso->long_name : "<not found>");
184 } else { 187 } else {
185 show = SHOW_HV; 188 show = SHOW_HV;
186 level = 'H'; 189 level = 'H';
@@ -188,12 +191,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
188 } 191 }
189 192
190 if (show & show_mask) { 193 if (show & show_mask) {
191 struct symbol *sym = NULL; 194 if (hist_entry__add(thread, map, sym, ip, level)) {
192
193 if (dso)
194 sym = dso->find_symbol(dso, ip);
195
196 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
197 fprintf(stderr, 195 fprintf(stderr,
198 "problem incrementing symbol count, skipping event\n"); 196 "problem incrementing symbol count, skipping event\n");
199 return -1; 197 return -1;
@@ -313,7 +311,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
313} 311}
314 312
315static int 313static int
316parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 314parse_line(FILE *file, struct symbol *sym, u64 len)
317{ 315{
318 char *line = NULL, *tmp, *tmp2; 316 char *line = NULL, *tmp, *tmp2;
319 static const char *prev_line; 317 static const char *prev_line;
@@ -363,7 +361,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
363 const char *color; 361 const char *color;
364 struct sym_ext *sym_ext = sym->priv; 362 struct sym_ext *sym_ext = sym->priv;
365 363
366 offset = line_ip - start; 364 offset = line_ip - sym->start;
367 if (offset < len) 365 if (offset < len)
368 hits = sym->hist[offset]; 366 hits = sym->hist[offset];
369 367
@@ -442,7 +440,7 @@ static void free_source_line(struct symbol *sym, int len)
442 440
443/* Get the filename:line for the colored entries */ 441/* Get the filename:line for the colored entries */
444static void 442static void
445get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 443get_source_line(struct symbol *sym, int len, const char *filename)
446{ 444{
447 int i; 445 int i;
448 char cmd[PATH_MAX * 2]; 446 char cmd[PATH_MAX * 2];
@@ -467,7 +465,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
467 if (sym_ext[i].percent <= 0.5) 465 if (sym_ext[i].percent <= 0.5)
468 continue; 466 continue;
469 467
470 offset = start + i; 468 offset = sym->start + i;
471 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 469 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
472 fp = popen(cmd, "r"); 470 fp = popen(cmd, "r");
473 if (!fp) 471 if (!fp)
@@ -519,31 +517,23 @@ static void print_summary(const char *filename)
519 517
520static void annotate_sym(struct dso *dso, struct symbol *sym) 518static void annotate_sym(struct dso *dso, struct symbol *sym)
521{ 519{
522 const char *filename = dso->name, *d_filename; 520 const char *filename = dso->long_name, *d_filename;
523 u64 start, end, len; 521 u64 len;
524 char command[PATH_MAX*2]; 522 char command[PATH_MAX*2];
525 FILE *file; 523 FILE *file;
526 524
527 if (!filename) 525 if (!filename)
528 return; 526 return;
529 if (sym->module) 527
530 filename = sym->module->path;
531 else if (dso == kernel_dso)
532 filename = vmlinux_name;
533
534 start = sym->obj_start;
535 if (!start)
536 start = sym->start;
537 if (full_paths) 528 if (full_paths)
538 d_filename = filename; 529 d_filename = filename;
539 else 530 else
540 d_filename = basename(filename); 531 d_filename = basename(filename);
541 532
542 end = start + sym->end - sym->start + 1;
543 len = sym->end - sym->start; 533 len = sym->end - sym->start;
544 534
545 if (print_line) { 535 if (print_line) {
546 get_source_line(sym, start, len, filename); 536 get_source_line(sym, len, filename);
547 print_summary(filename); 537 print_summary(filename);
548 } 538 }
549 539
@@ -552,10 +542,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
552 printf("------------------------------------------------\n"); 542 printf("------------------------------------------------\n");
553 543
554 if (verbose >= 2) 544 if (verbose >= 2)
555 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 545 printf("annotating [%p] %30s : [%p] %30s\n",
546 dso, dso->long_name, sym, sym->name);
556 547
557 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 548 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
558 (u64)start, (u64)end, filename, filename); 549 sym->start, sym->end, filename, filename);
559 550
560 if (verbose >= 3) 551 if (verbose >= 3)
561 printf("doing: %s\n", command); 552 printf("doing: %s\n", command);
@@ -565,7 +556,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
565 return; 556 return;
566 557
567 while (!feof(file)) { 558 while (!feof(file)) {
568 if (parse_line(file, sym, start, len) < 0) 559 if (parse_line(file, sym, len) < 0)
569 break; 560 break;
570 } 561 }
571 562