aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.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-report.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-report.c')
-rw-r--r--tools/perf/builtin-report.c79
1 files changed, 35 insertions, 44 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c1a54fc8527a..3ed3baf96ffb 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -349,22 +349,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
349 349
350 350
351static struct symbol * 351static struct symbol *
352resolve_symbol(struct thread *thread, struct map **mapp, 352resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
353 struct dso **dsop, u64 *ipp)
354{ 353{
355 struct dso *dso = dsop ? *dsop : NULL;
356 struct map *map = mapp ? *mapp : NULL; 354 struct map *map = mapp ? *mapp : NULL;
357 u64 ip = *ipp; 355 u64 ip = *ipp;
358 356
359 if (!thread)
360 return NULL;
361
362 if (dso)
363 goto got_dso;
364
365 if (map) 357 if (map)
366 goto got_map; 358 goto got_map;
367 359
360 if (!thread)
361 return NULL;
362
368 map = thread__find_map(thread, ip); 363 map = thread__find_map(thread, ip);
369 if (map != NULL) { 364 if (map != NULL) {
370 /* 365 /*
@@ -379,29 +374,29 @@ resolve_symbol(struct thread *thread, struct map **mapp,
379 *mapp = map; 374 *mapp = map;
380got_map: 375got_map:
381 ip = map->map_ip(map, ip); 376 ip = map->map_ip(map, ip);
382
383 dso = map->dso;
384 } else { 377 } else {
385 /* 378 /*
386 * If this is outside of all known maps, 379 * If this is outside of all known maps,
387 * and is a negative address, try to look it 380 * and is a negative address, try to look it
388 * up in the kernel dso, as it might be a 381 * up in the kernel dso, as it might be a
389 * vsyscall (which executes in user-mode): 382 * vsyscall or vdso (which executes in user-mode).
383 *
384 * XXX This is nasty, we should have a symbol list in
385 * the "[vdso]" dso, but for now lets use the old
386 * trick of looking in the whole kernel symbol list.
390 */ 387 */
391 if ((long long)ip < 0) 388 if ((long long)ip < 0) {
392 dso = kernel_dso; 389 map = kernel_map;
390 if (mapp)
391 *mapp = map;
392 }
393 } 393 }
394 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 394 dump_printf(" ...... dso: %s\n",
395 map ? map->dso->long_name : "<not found>");
395 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 396 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
396 *ipp = ip; 397 *ipp = ip;
397 398
398 if (dsop) 399 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
399 *dsop = dso;
400
401 if (!dso)
402 return NULL;
403got_dso:
404 return dso->find_symbol(dso, ip);
405} 400}
406 401
407static int call__match(struct symbol *sym) 402static int call__match(struct symbol *sym)
@@ -413,7 +408,7 @@ static int call__match(struct symbol *sym)
413} 408}
414 409
415static struct symbol ** 410static struct symbol **
416resolve_callchain(struct thread *thread, struct map *map __used, 411resolve_callchain(struct thread *thread, struct map *map,
417 struct ip_callchain *chain, struct hist_entry *entry) 412 struct ip_callchain *chain, struct hist_entry *entry)
418{ 413{
419 u64 context = PERF_CONTEXT_MAX; 414 u64 context = PERF_CONTEXT_MAX;
@@ -430,8 +425,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
430 425
431 for (i = 0; i < chain->nr; i++) { 426 for (i = 0; i < chain->nr; i++) {
432 u64 ip = chain->ips[i]; 427 u64 ip = chain->ips[i];
433 struct dso *dso = NULL; 428 struct symbol *sym = NULL;
434 struct symbol *sym;
435 429
436 if (ip >= PERF_CONTEXT_MAX) { 430 if (ip >= PERF_CONTEXT_MAX) {
437 context = ip; 431 context = ip;
@@ -440,17 +434,15 @@ resolve_callchain(struct thread *thread, struct map *map __used,
440 434
441 switch (context) { 435 switch (context) {
442 case PERF_CONTEXT_HV: 436 case PERF_CONTEXT_HV:
443 dso = hypervisor_dso;
444 break; 437 break;
445 case PERF_CONTEXT_KERNEL: 438 case PERF_CONTEXT_KERNEL:
446 dso = kernel_dso; 439 sym = kernel_maps__find_symbol(ip, &map);
447 break; 440 break;
448 default: 441 default:
442 sym = resolve_symbol(thread, &map, &ip);
449 break; 443 break;
450 } 444 }
451 445
452 sym = resolve_symbol(thread, NULL, &dso, &ip);
453
454 if (sym) { 446 if (sym) {
455 if (sort__has_parent && call__match(sym) && 447 if (sort__has_parent && call__match(sym) &&
456 !entry->parent) 448 !entry->parent)
@@ -469,7 +461,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
469 */ 461 */
470 462
471static int 463static int
472hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 464hist_entry__add(struct thread *thread, struct map *map,
473 struct symbol *sym, u64 ip, struct ip_callchain *chain, 465 struct symbol *sym, u64 ip, struct ip_callchain *chain,
474 char level, u64 count) 466 char level, u64 count)
475{ 467{
@@ -480,7 +472,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
480 struct hist_entry entry = { 472 struct hist_entry entry = {
481 .thread = thread, 473 .thread = thread,
482 .map = map, 474 .map = map,
483 .dso = dso,
484 .sym = sym, 475 .sym = sym,
485 .ip = ip, 476 .ip = ip,
486 .level = level, 477 .level = level,
@@ -641,7 +632,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
641{ 632{
642 char level; 633 char level;
643 int show = 0; 634 int show = 0;
644 struct dso *dso = NULL; 635 struct symbol *sym = NULL;
645 struct thread *thread; 636 struct thread *thread;
646 u64 ip = event->ip.ip; 637 u64 ip = event->ip.ip;
647 u64 period = 1; 638 u64 period = 1;
@@ -700,35 +691,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
700 show = SHOW_KERNEL; 691 show = SHOW_KERNEL;
701 level = 'k'; 692 level = 'k';
702 693
703 dso = kernel_dso; 694 sym = kernel_maps__find_symbol(ip, &map);
704 695 dump_printf(" ...... dso: %s\n",
705 dump_printf(" ...... dso: %s\n", dso->name); 696 map ? map->dso->long_name : "<not found>");
706
707 } else if (cpumode == PERF_RECORD_MISC_USER) { 697 } else if (cpumode == PERF_RECORD_MISC_USER) {
708 698
709 show = SHOW_USER; 699 show = SHOW_USER;
710 level = '.'; 700 level = '.';
701 sym = resolve_symbol(thread, &map, &ip);
711 702
712 } else { 703 } else {
713 show = SHOW_HV; 704 show = SHOW_HV;
714 level = 'H'; 705 level = 'H';
715 706
716 dso = hypervisor_dso;
717
718 dump_printf(" ...... dso: [hypervisor]\n"); 707 dump_printf(" ...... dso: [hypervisor]\n");
719 } 708 }
720 709
721 if (show & show_mask) { 710 if (show & show_mask) {
722 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 711 if (dso_list &&
723 712 (!map || !map->dso ||
724 if (dso_list && (!dso || !dso->name || 713 !(strlist__has_entry(dso_list, map->dso->short_name) ||
725 !strlist__has_entry(dso_list, dso->name))) 714 (map->dso->short_name != map->dso->long_name &&
715 strlist__has_entry(dso_list, map->dso->long_name)))))
726 return 0; 716 return 0;
727 717
728 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) 718 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
729 return 0; 719 return 0;
730 720
731 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 721 if (hist_entry__add(thread, map, sym, ip,
722 chain, level, period)) {
732 eprintf("problem incrementing symbol count, skipping event\n"); 723 eprintf("problem incrementing symbol count, skipping event\n");
733 return -1; 724 return -1;
734 } 725 }