aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-11-27 13:29:23 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-27 14:22:02 -0500
commit1ed091c45ae33b2179d387573c3fe3f3b4adf60a (patch)
treed2b689de158e5a11673b5f0d08b491d243768138 /tools/perf/builtin-report.c
parent62daacb51a2bf8480e6f6b3696b03f102fc15eb0 (diff)
perf tools: Consolidate symbol resolving across all tools
Now we have a very high level routine for simple tools to process IP sample events: int event__preprocess_sample(const event_t *self, struct addr_location *al, symbol_filter_t filter) It receives the event itself and will insert new threads in the global threads list and resolve the map and symbol, filling all this info into the new addr_location struct, so that tools like annotate and report can further process the event by creating hist_entries in their specific way (with or without callgraphs, etc). It in turn uses the new next layer function: void thread__find_addr_location(struct thread *self, u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter) This one will, given a thread (userspace or the kernel kthread one), will find the given type (MAP__FUNCTION now, MAP__VARIABLE too in the near future) at the given cpumode, taking vdsos into account (userspace hit, but kernel symbol) and will fill all these details in the addr_location given. Tools that need a more compact API for plain function resolution, like 'kmem', can use this other one: struct symbol *thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) So, to resolve a kernel symbol, that is all the 'kmem' tool needs, its just a matter of calling: sym = thread__find_function(kthread, addr, NULL); The 'filter' parameter is needed because we do lazy parsing/loading of ELF symtabs or /proc/kallsyms. With this we remove more code duplication all around, which is always good, huh? :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: John Kacur <jkacur@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1259346563-12568-12-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c135
1 files changed, 38 insertions, 97 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 01ef35cac5f9..383c4ab4f9af 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -408,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
408 return 0; 408 return 0;
409} 409}
410 410
411
412static struct symbol *
413resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
414{
415 struct map *map = mapp ? *mapp : NULL;
416 u64 ip = *ipp;
417
418 if (map)
419 goto got_map;
420
421 if (!thread)
422 return NULL;
423
424 map = thread__find_map(thread, MAP__FUNCTION, ip);
425 if (map != NULL) {
426 /*
427 * We have to do this here as we may have a dso
428 * with no symbol hit that has a name longer than
429 * the ones with symbols sampled.
430 */
431 if (!sort_dso.elide && !map->dso->slen_calculated)
432 dso__calc_col_width(map->dso);
433
434 if (mapp)
435 *mapp = map;
436got_map:
437 ip = map->map_ip(map, ip);
438 } else {
439 /*
440 * If this is outside of all known maps,
441 * and is a negative address, try to look it
442 * up in the kernel dso, as it might be a
443 * vsyscall or vdso (which executes in user-mode).
444 *
445 * XXX This is nasty, we should have a symbol list in
446 * the "[vdso]" dso, but for now lets use the old
447 * trick of looking in the whole kernel symbol list.
448 */
449 if ((long long)ip < 0)
450 return kernel_maps__find_function(ip, mapp, NULL);
451 }
452 dump_printf(" ...... dso: %s\n",
453 map ? map->dso->long_name : "<not found>");
454 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
455 *ipp = ip;
456
457 return map ? map__find_symbol(map, ip, NULL) : NULL;
458}
459
460static int call__match(struct symbol *sym) 411static int call__match(struct symbol *sym)
461{ 412{
462 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 413 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -469,7 +420,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
469 struct ip_callchain *chain, 420 struct ip_callchain *chain,
470 struct symbol **parent) 421 struct symbol **parent)
471{ 422{
472 u64 context = PERF_CONTEXT_MAX; 423 u8 cpumode = PERF_RECORD_MISC_USER;
473 struct symbol **syms = NULL; 424 struct symbol **syms = NULL;
474 unsigned int i; 425 unsigned int i;
475 426
@@ -483,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread,
483 434
484 for (i = 0; i < chain->nr; i++) { 435 for (i = 0; i < chain->nr; i++) {
485 u64 ip = chain->ips[i]; 436 u64 ip = chain->ips[i];
486 struct symbol *sym = NULL; 437 struct addr_location al;
487 438
488 if (ip >= PERF_CONTEXT_MAX) { 439 if (ip >= PERF_CONTEXT_MAX) {
489 context = ip; 440 switch (ip) {
441 case PERF_CONTEXT_HV:
442 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
443 case PERF_CONTEXT_KERNEL:
444 cpumode = PERF_RECORD_MISC_KERNEL; break;
445 case PERF_CONTEXT_USER:
446 cpumode = PERF_RECORD_MISC_USER; break;
447 default:
448 break;
449 }
490 continue; 450 continue;
491 } 451 }
492 452
493 switch (context) { 453 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
494 case PERF_CONTEXT_HV: 454 ip, &al, NULL);
495 break; 455 if (al.sym != NULL) {
496 case PERF_CONTEXT_KERNEL: 456 if (sort__has_parent && !*parent &&
497 sym = kernel_maps__find_function(ip, NULL, NULL); 457 call__match(al.sym))
498 break; 458 *parent = al.sym;
499 default:
500 sym = resolve_symbol(thread, NULL, &ip);
501 break;
502 }
503
504 if (sym) {
505 if (sort__has_parent && !*parent && call__match(sym))
506 *parent = sym;
507 if (!callchain) 459 if (!callchain)
508 break; 460 break;
509 syms[i] = sym; 461 syms[i] = al.sym;
510 } 462 }
511 } 463 }
512 464
@@ -517,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread,
517 * collect histogram counts 469 * collect histogram counts
518 */ 470 */
519 471
520static int 472static int hist_entry__add(struct addr_location *al,
521hist_entry__add(struct thread *thread, struct map *map, 473 struct ip_callchain *chain, u64 count)
522 struct symbol *sym, u64 ip, struct ip_callchain *chain,
523 char level, u64 count)
524{ 474{
525 struct symbol **syms = NULL, *parent = NULL; 475 struct symbol **syms = NULL, *parent = NULL;
526 bool hit; 476 bool hit;
527 struct hist_entry *he; 477 struct hist_entry *he;
528 478
529 if ((sort__has_parent || callchain) && chain) 479 if ((sort__has_parent || callchain) && chain)
530 syms = resolve_callchain(thread, chain, &parent); 480 syms = resolve_callchain(al->thread, chain, &parent);
531 481
532 he = __hist_entry__add(thread, map, sym, parent, 482 he = __hist_entry__add(al, parent, count, &hit);
533 ip, count, level, &hit);
534 if (he == NULL) 483 if (he == NULL)
535 return -ENOMEM; 484 return -ENOMEM;
536 485
@@ -656,14 +605,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
656 605
657static int process_sample_event(event_t *event) 606static int process_sample_event(event_t *event)
658{ 607{
659 char level;
660 struct symbol *sym = NULL;
661 u64 ip = event->ip.ip; 608 u64 ip = event->ip.ip;
662 u64 period = 1; 609 u64 period = 1;
663 struct map *map = NULL;
664 void *more_data = event->ip.__more_data; 610 void *more_data = event->ip.__more_data;
665 struct ip_callchain *chain = NULL; 611 struct ip_callchain *chain = NULL;
666 int cpumode; 612 int cpumode;
613 struct addr_location al;
667 struct thread *thread = threads__findnew(event->ip.pid); 614 struct thread *thread = threads__findnew(event->ip.pid);
668 615
669 if (sample_type & PERF_SAMPLE_PERIOD) { 616 if (sample_type & PERF_SAMPLE_PERIOD) {
@@ -709,32 +656,26 @@ static int process_sample_event(event_t *event)
709 656
710 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 657 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
711 658
712 if (cpumode == PERF_RECORD_MISC_KERNEL) { 659 thread__find_addr_location(thread, cpumode,
713 level = 'k'; 660 MAP__FUNCTION, ip, &al, NULL);
714 sym = kernel_maps__find_function(ip, &map, NULL); 661 /*
715 dump_printf(" ...... dso: %s\n", 662 * We have to do this here as we may have a dso with no symbol hit that
716 map ? map->dso->long_name : "<not found>"); 663 * has a name longer than the ones with symbols sampled.
717 } else if (cpumode == PERF_RECORD_MISC_USER) { 664 */
718 level = '.'; 665 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
719 sym = resolve_symbol(thread, &map, &ip); 666 dso__calc_col_width(al.map->dso);
720
721 } else {
722 level = 'H';
723 dump_printf(" ...... dso: [hypervisor]\n");
724 }
725 667
726 if (dso_list && 668 if (dso_list &&
727 (!map || !map->dso || 669 (!al.map || !al.map->dso ||
728 !(strlist__has_entry(dso_list, map->dso->short_name) || 670 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
729 (map->dso->short_name != map->dso->long_name && 671 (al.map->dso->short_name != al.map->dso->long_name &&
730 strlist__has_entry(dso_list, map->dso->long_name))))) 672 strlist__has_entry(dso_list, al.map->dso->long_name)))))
731 return 0; 673 return 0;
732 674
733 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 675 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
734 return 0; 676 return 0;
735 677
736 if (hist_entry__add(thread, map, sym, ip, 678 if (hist_entry__add(&al, chain, period)) {
737 chain, level, period)) {
738 pr_debug("problem incrementing symbol count, skipping event\n"); 679 pr_debug("problem incrementing symbol count, skipping event\n");
739 return -1; 680 return -1;
740 } 681 }