diff options
| -rw-r--r-- | tools/perf/builtin-annotate.c | 55 | ||||
| -rw-r--r-- | tools/perf/builtin-kmem.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 135 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 44 | ||||
| -rw-r--r-- | tools/perf/util/event.c | 62 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 15 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 6 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 26 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 10 | ||||
| -rw-r--r-- | tools/perf/util/thread.c | 12 | ||||
| -rw-r--r-- | tools/perf/util/thread.h | 23 |
12 files changed, 172 insertions, 222 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7d39bd2b19b8..7f85c6e159a4 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -124,71 +124,30 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
| 124 | h->ip[offset]); | 124 | h->ip[offset]); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static int hist_entry__add(struct thread *thread, struct map *map, | 127 | static int hist_entry__add(struct addr_location *al, u64 count) |
| 128 | struct symbol *sym, u64 ip, u64 count, char level) | ||
| 129 | { | 128 | { |
| 130 | bool hit; | 129 | bool hit; |
| 131 | struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip, | 130 | struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit); |
| 132 | count, level, &hit); | ||
| 133 | if (he == NULL) | 131 | if (he == NULL) |
| 134 | return -ENOMEM; | 132 | return -ENOMEM; |
| 135 | hist_hit(he, ip); | 133 | hist_hit(he, al->addr); |
| 136 | return 0; | 134 | return 0; |
| 137 | } | 135 | } |
| 138 | 136 | ||
| 139 | static int process_sample_event(event_t *event) | 137 | static int process_sample_event(event_t *event) |
| 140 | { | 138 | { |
| 141 | char level; | 139 | struct addr_location al; |
| 142 | u64 ip = event->ip.ip; | ||
| 143 | struct map *map = NULL; | ||
| 144 | struct symbol *sym = NULL; | ||
| 145 | struct thread *thread = threads__findnew(event->ip.pid); | ||
| 146 | 140 | ||
| 147 | dump_printf("(IP, %d): %d: %p\n", event->header.misc, | 141 | dump_printf("(IP, %d): %d: %p\n", event->header.misc, |
| 148 | event->ip.pid, (void *)(long)ip); | 142 | event->ip.pid, (void *)(long)event->ip.ip); |
| 149 | 143 | ||
| 150 | if (thread == NULL) { | 144 | if (event__preprocess_sample(event, &al, symbol_filter) < 0) { |
| 151 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 145 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
| 152 | event->header.type); | 146 | event->header.type); |
| 153 | return -1; | 147 | return -1; |
| 154 | } | 148 | } |
| 155 | 149 | ||
| 156 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 150 | if (hist_entry__add(&al, 1)) { |
| 157 | |||
| 158 | if (event->header.misc & PERF_RECORD_MISC_KERNEL) { | ||
| 159 | level = 'k'; | ||
| 160 | sym = kernel_maps__find_function(ip, &map, symbol_filter); | ||
| 161 | dump_printf(" ...... dso: %s\n", | ||
| 162 | map ? map->dso->long_name : "<not found>"); | ||
| 163 | } else if (event->header.misc & PERF_RECORD_MISC_USER) { | ||
| 164 | level = '.'; | ||
| 165 | map = thread__find_map(thread, MAP__FUNCTION, ip); | ||
| 166 | if (map != NULL) { | ||
| 167 | ip = map->map_ip(map, ip); | ||
| 168 | sym = map__find_symbol(map, ip, symbol_filter); | ||
| 169 | } else { | ||
| 170 | /* | ||
| 171 | * If this is outside of all known maps, | ||
| 172 | * and is a negative address, try to look it | ||
| 173 | * up in the kernel dso, as it might be a | ||
| 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. | ||
| 179 | */ | ||
| 180 | if ((long long)ip < 0) | ||
| 181 | sym = kernel_maps__find_function(ip, &map, | ||
| 182 | symbol_filter); | ||
| 183 | } | ||
| 184 | dump_printf(" ...... dso: %s\n", | ||
| 185 | map ? map->dso->long_name : "<not found>"); | ||
| 186 | } else { | ||
| 187 | level = 'H'; | ||
| 188 | dump_printf(" ...... dso: [hypervisor]\n"); | ||
| 189 | } | ||
| 190 | |||
| 191 | if (hist_entry__add(thread, map, sym, ip, 1, level)) { | ||
| 192 | fprintf(stderr, "problem incrementing symbol count, " | 151 | fprintf(stderr, "problem incrementing symbol count, " |
| 193 | "skipping event\n"); | 152 | "skipping event\n"); |
| 194 | return -1; | 153 | return -1; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index e7294c8fc620..047fef74bd52 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -420,7 +420,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) | |||
| 420 | if (is_caller) { | 420 | if (is_caller) { |
| 421 | addr = data->call_site; | 421 | addr = data->call_site; |
| 422 | if (!raw_ip) | 422 | if (!raw_ip) |
| 423 | sym = kernel_maps__find_function(addr, NULL, NULL); | 423 | sym = thread__find_function(kthread, addr, NULL); |
| 424 | } else | 424 | } else |
| 425 | addr = data->ptr; | 425 | addr = data->ptr; |
| 426 | 426 | ||
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 | |||
| 412 | static struct symbol * | ||
| 413 | resolve_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; | ||
| 436 | got_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 | |||
| 460 | static int call__match(struct symbol *sym) | 411 | static 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 | ||
| 520 | static int | 472 | static int hist_entry__add(struct addr_location *al, |
| 521 | hist_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 | ||
| 657 | static int process_sample_event(event_t *event) | 606 | static 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 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a3c0c7aad3d..e0a374d0e43a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -929,55 +929,28 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
| 929 | static void event__process_sample(const event_t *self, int counter) | 929 | static void event__process_sample(const event_t *self, int counter) |
| 930 | { | 930 | { |
| 931 | u64 ip = self->ip.ip; | 931 | u64 ip = self->ip.ip; |
| 932 | struct map *map; | ||
| 933 | struct sym_entry *syme; | 932 | struct sym_entry *syme; |
| 934 | struct symbol *sym; | 933 | struct addr_location al; |
| 935 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 934 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 936 | 935 | ||
| 937 | switch (origin) { | 936 | switch (origin) { |
| 938 | case PERF_RECORD_MISC_USER: { | 937 | case PERF_RECORD_MISC_USER: |
| 939 | struct thread *thread; | ||
| 940 | |||
| 941 | if (hide_user_symbols) | 938 | if (hide_user_symbols) |
| 942 | return; | 939 | return; |
| 943 | 940 | break; | |
| 944 | thread = threads__findnew(self->ip.pid); | ||
| 945 | if (thread == NULL) | ||
| 946 | return; | ||
| 947 | |||
| 948 | map = thread__find_map(thread, MAP__FUNCTION, ip); | ||
| 949 | if (map != NULL) { | ||
| 950 | ip = map->map_ip(map, ip); | ||
| 951 | sym = map__find_symbol(map, ip, symbol_filter); | ||
| 952 | if (sym == NULL) | ||
| 953 | return; | ||
| 954 | userspace_samples++; | ||
| 955 | break; | ||
| 956 | } | ||
| 957 | } | ||
| 958 | /* | ||
| 959 | * If this is outside of all known maps, | ||
| 960 | * and is a negative address, try to look it | ||
| 961 | * up in the kernel dso, as it might be a | ||
| 962 | * vsyscall or vdso (which executes in user-mode). | ||
| 963 | */ | ||
| 964 | if ((long long)ip >= 0) | ||
| 965 | return; | ||
| 966 | /* Fall thru */ | ||
| 967 | case PERF_RECORD_MISC_KERNEL: | 941 | case PERF_RECORD_MISC_KERNEL: |
| 968 | if (hide_kernel_symbols) | 942 | if (hide_kernel_symbols) |
| 969 | return; | 943 | return; |
| 970 | |||
| 971 | sym = kernel_maps__find_function(ip, &map, symbol_filter); | ||
| 972 | if (sym == NULL) | ||
| 973 | return; | ||
| 974 | break; | 944 | break; |
| 975 | default: | 945 | default: |
| 976 | return; | 946 | return; |
| 977 | } | 947 | } |
| 978 | 948 | ||
| 979 | syme = symbol__priv(sym); | 949 | if (event__preprocess_sample(self, &al, symbol_filter) < 0 || |
| 950 | al.sym == NULL) | ||
| 951 | return; | ||
| 980 | 952 | ||
| 953 | syme = symbol__priv(al.sym); | ||
| 981 | if (!syme->skip) { | 954 | if (!syme->skip) { |
| 982 | syme->count[counter]++; | 955 | syme->count[counter]++; |
| 983 | syme->origin = origin; | 956 | syme->origin = origin; |
| @@ -986,8 +959,9 @@ static void event__process_sample(const event_t *self, int counter) | |||
| 986 | if (list_empty(&syme->node) || !syme->node.next) | 959 | if (list_empty(&syme->node) || !syme->node.next) |
| 987 | __list_insert_active_sym(syme); | 960 | __list_insert_active_sym(syme); |
| 988 | pthread_mutex_unlock(&active_symbols_lock); | 961 | pthread_mutex_unlock(&active_symbols_lock); |
| 962 | if (origin == PERF_RECORD_MISC_USER) | ||
| 963 | ++userspace_samples; | ||
| 989 | ++samples; | 964 | ++samples; |
| 990 | return; | ||
| 991 | } | 965 | } |
| 992 | } | 966 | } |
| 993 | 967 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 70b4aa03b472..233d7ad9bd7f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -249,3 +249,65 @@ int event__process_task(event_t *self) | |||
| 249 | 249 | ||
| 250 | return 0; | 250 | return 0; |
| 251 | } | 251 | } |
| 252 | |||
| 253 | void thread__find_addr_location(struct thread *self, u8 cpumode, | ||
| 254 | enum map_type type, u64 addr, | ||
| 255 | struct addr_location *al, | ||
| 256 | symbol_filter_t filter) | ||
| 257 | { | ||
| 258 | struct thread *thread = al->thread = self; | ||
| 259 | |||
| 260 | al->addr = addr; | ||
| 261 | |||
| 262 | if (cpumode & PERF_RECORD_MISC_KERNEL) { | ||
| 263 | al->level = 'k'; | ||
| 264 | thread = kthread; | ||
| 265 | } else if (cpumode & PERF_RECORD_MISC_USER) | ||
| 266 | al->level = '.'; | ||
| 267 | else { | ||
| 268 | al->level = 'H'; | ||
| 269 | al->map = NULL; | ||
| 270 | al->sym = NULL; | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | try_again: | ||
| 274 | al->map = thread__find_map(thread, type, al->addr); | ||
| 275 | if (al->map == NULL) { | ||
| 276 | /* | ||
| 277 | * If this is outside of all known maps, and is a negative | ||
| 278 | * address, try to look it up in the kernel dso, as it might be | ||
| 279 | * a vsyscall or vdso (which executes in user-mode). | ||
| 280 | * | ||
| 281 | * XXX This is nasty, we should have a symbol list in the | ||
| 282 | * "[vdso]" dso, but for now lets use the old trick of looking | ||
| 283 | * in the whole kernel symbol list. | ||
| 284 | */ | ||
| 285 | if ((long long)al->addr < 0 && thread != kthread) { | ||
| 286 | thread = kthread; | ||
| 287 | goto try_again; | ||
| 288 | } | ||
| 289 | al->sym = NULL; | ||
| 290 | } else { | ||
| 291 | al->addr = al->map->map_ip(al->map, al->addr); | ||
| 292 | al->sym = map__find_symbol(al->map, al->addr, filter); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | int event__preprocess_sample(const event_t *self, struct addr_location *al, | ||
| 297 | symbol_filter_t filter) | ||
| 298 | { | ||
| 299 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
| 300 | struct thread *thread = threads__findnew(self->ip.pid); | ||
| 301 | |||
| 302 | if (thread == NULL) | ||
| 303 | return -1; | ||
| 304 | |||
| 305 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | ||
| 306 | |||
| 307 | thread__find_addr_location(thread, cpumode, MAP__FUNCTION, | ||
| 308 | self->ip.ip, al, filter); | ||
| 309 | dump_printf(" ...... dso: %s\n", | ||
| 310 | al->map ? al->map->dso->long_name : | ||
| 311 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | ||
| 312 | return 0; | ||
| 313 | } | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 13c12c75f970..a4cc8105cf67 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -152,4 +152,8 @@ int event__process_lost(event_t *self); | |||
| 152 | int event__process_mmap(event_t *self); | 152 | int event__process_mmap(event_t *self); |
| 153 | int event__process_task(event_t *self); | 153 | int event__process_task(event_t *self); |
| 154 | 154 | ||
| 155 | struct addr_location; | ||
| 156 | int event__preprocess_sample(const event_t *self, struct addr_location *al, | ||
| 157 | symbol_filter_t filter); | ||
| 158 | |||
| 155 | #endif /* __PERF_RECORD_H */ | 159 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f26cd9ba00fd..0ebf6ee16caa 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -14,20 +14,19 @@ struct callchain_param callchain_param = { | |||
| 14 | * histogram, sorted on item, collects counts | 14 | * histogram, sorted on item, collects counts |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, | 17 | struct hist_entry *__hist_entry__add(struct addr_location *al, |
| 18 | struct symbol *sym, | ||
| 19 | struct symbol *sym_parent, | 18 | struct symbol *sym_parent, |
| 20 | u64 ip, u64 count, char level, bool *hit) | 19 | u64 count, bool *hit) |
| 21 | { | 20 | { |
| 22 | struct rb_node **p = &hist.rb_node; | 21 | struct rb_node **p = &hist.rb_node; |
| 23 | struct rb_node *parent = NULL; | 22 | struct rb_node *parent = NULL; |
| 24 | struct hist_entry *he; | 23 | struct hist_entry *he; |
| 25 | struct hist_entry entry = { | 24 | struct hist_entry entry = { |
| 26 | .thread = thread, | 25 | .thread = al->thread, |
| 27 | .map = map, | 26 | .map = al->map, |
| 28 | .sym = sym, | 27 | .sym = al->sym, |
| 29 | .ip = ip, | 28 | .ip = al->addr, |
| 30 | .level = level, | 29 | .level = al->level, |
| 31 | .count = count, | 30 | .count = count, |
| 32 | .parent = sym_parent, | 31 | .parent = sym_parent, |
| 33 | }; | 32 | }; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ac2149c559b0..3020db0c9292 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -36,9 +36,9 @@ extern unsigned long total_fork; | |||
| 36 | extern unsigned long total_unknown; | 36 | extern unsigned long total_unknown; |
| 37 | extern unsigned long total_lost; | 37 | extern unsigned long total_lost; |
| 38 | 38 | ||
| 39 | struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, | 39 | struct hist_entry *__hist_entry__add(struct addr_location *al, |
| 40 | struct symbol *sym, struct symbol *parent, | 40 | struct symbol *parent, |
| 41 | u64 ip, u64 count, char level, bool *hit); | 41 | u64 count, bool *hit); |
| 42 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | 42 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); |
| 43 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 43 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
| 44 | extern void hist_entry__free(struct hist_entry *); | 44 | extern void hist_entry__free(struct hist_entry *); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b788c2f5d672..fffcb937cdcb 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -43,7 +43,8 @@ static struct symbol_conf symbol_conf__defaults = { | |||
| 43 | .try_vmlinux_path = true, | 43 | .try_vmlinux_path = true, |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| 46 | static struct thread kthread_mem, *kthread = &kthread_mem; | 46 | static struct thread kthread_mem; |
| 47 | struct thread *kthread = &kthread_mem; | ||
| 47 | 48 | ||
| 48 | bool dso__loaded(const struct dso *self, enum map_type type) | 49 | bool dso__loaded(const struct dso *self, enum map_type type) |
| 49 | { | 50 | { |
| @@ -1178,29 +1179,6 @@ out: | |||
| 1178 | return ret; | 1179 | return ret; |
| 1179 | } | 1180 | } |
| 1180 | 1181 | ||
| 1181 | static struct symbol *thread__find_symbol(struct thread *self, u64 ip, | ||
| 1182 | enum map_type type, struct map **mapp, | ||
| 1183 | symbol_filter_t filter) | ||
| 1184 | { | ||
| 1185 | struct map *map = thread__find_map(self, type, ip); | ||
| 1186 | |||
| 1187 | if (mapp) | ||
| 1188 | *mapp = map; | ||
| 1189 | |||
| 1190 | if (map) { | ||
| 1191 | ip = map->map_ip(map, ip); | ||
| 1192 | return map__find_symbol(map, ip, filter); | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | return NULL; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, | ||
| 1199 | symbol_filter_t filter) | ||
| 1200 | { | ||
| 1201 | return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter); | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | static struct map *thread__find_map_by_name(struct thread *self, char *name) | 1182 | static struct map *thread__find_map_by_name(struct thread *self, char *name) |
| 1205 | { | 1183 | { |
| 1206 | struct rb_node *nd; | 1184 | struct rb_node *nd; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 3f9e4a4d83dd..17003efa0b39 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -63,6 +63,14 @@ static inline void *symbol__priv(struct symbol *self) | |||
| 63 | return ((void *)self) - symbol__priv_size; | 63 | return ((void *)self) - symbol__priv_size; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | struct addr_location { | ||
| 67 | struct thread *thread; | ||
| 68 | struct map *map; | ||
| 69 | struct symbol *sym; | ||
| 70 | u64 addr; | ||
| 71 | char level; | ||
| 72 | }; | ||
| 73 | |||
| 66 | struct dso { | 74 | struct dso { |
| 67 | struct list_head node; | 75 | struct list_head node; |
| 68 | struct rb_root symbols[MAP__NR_TYPES]; | 76 | struct rb_root symbols[MAP__NR_TYPES]; |
| @@ -105,6 +113,8 @@ size_t kernel_maps__fprintf(FILE *fp); | |||
| 105 | 113 | ||
| 106 | int symbol__init(struct symbol_conf *conf); | 114 | int symbol__init(struct symbol_conf *conf); |
| 107 | 115 | ||
| 116 | struct thread; | ||
| 117 | struct thread *kthread; | ||
| 108 | extern struct list_head dsos__user, dsos__kernel; | 118 | extern struct list_head dsos__user, dsos__kernel; |
| 109 | extern struct dso *vdso; | 119 | extern struct dso *vdso; |
| 110 | #endif /* __PERF_SYMBOL */ | 120 | #endif /* __PERF_SYMBOL */ |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2229f82cd630..603f5610861b 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -285,3 +285,15 @@ size_t threads__fprintf(FILE *fp) | |||
| 285 | 285 | ||
| 286 | return ret; | 286 | return ret; |
| 287 | } | 287 | } |
| 288 | |||
| 289 | struct symbol *thread__find_symbol(struct thread *self, | ||
| 290 | enum map_type type, u64 addr, | ||
| 291 | symbol_filter_t filter) | ||
| 292 | { | ||
| 293 | struct map *map = thread__find_map(self, type, addr); | ||
| 294 | |||
| 295 | if (map != NULL) | ||
| 296 | return map__find_symbol(map, map->map_ip(map, addr), filter); | ||
| 297 | |||
| 298 | return NULL; | ||
| 299 | } | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 59b0d9b577d6..686d6e914d9e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
| @@ -27,19 +27,30 @@ size_t thread__fprintf_maps(struct thread *self, FILE *fp); | |||
| 27 | size_t threads__fprintf(FILE *fp); | 27 | size_t threads__fprintf(FILE *fp); |
| 28 | 28 | ||
| 29 | void maps__insert(struct rb_root *maps, struct map *map); | 29 | void maps__insert(struct rb_root *maps, struct map *map); |
| 30 | struct map *maps__find(struct rb_root *maps, u64 ip); | 30 | struct map *maps__find(struct rb_root *maps, u64 addr); |
| 31 | |||
| 32 | struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, | ||
| 33 | symbol_filter_t filter); | ||
| 34 | 31 | ||
| 35 | static inline struct map *thread__find_map(struct thread *self, | 32 | static inline struct map *thread__find_map(struct thread *self, |
| 36 | enum map_type type, u64 ip) | 33 | enum map_type type, u64 addr) |
| 37 | { | 34 | { |
| 38 | return self ? maps__find(&self->maps[type], ip) : NULL; | 35 | return self ? maps__find(&self->maps[type], addr) : NULL; |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | static inline void __thread__insert_map(struct thread *self, struct map *map) | 38 | static inline void __thread__insert_map(struct thread *self, struct map *map) |
| 42 | { | 39 | { |
| 43 | maps__insert(&self->maps[map->type], map); | 40 | maps__insert(&self->maps[map->type], map); |
| 44 | } | 41 | } |
| 42 | |||
| 43 | void thread__find_addr_location(struct thread *self, u8 cpumode, | ||
| 44 | enum map_type type, u64 addr, | ||
| 45 | struct addr_location *al, | ||
| 46 | symbol_filter_t filter); | ||
| 47 | struct symbol *thread__find_symbol(struct thread *self, | ||
| 48 | enum map_type type, u64 addr, | ||
| 49 | symbol_filter_t filter); | ||
| 50 | |||
| 51 | static inline struct symbol * | ||
| 52 | thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) | ||
| 53 | { | ||
| 54 | return thread__find_symbol(self, MAP__FUNCTION, addr, filter); | ||
| 55 | } | ||
| 45 | #endif /* __PERF_THREAD_H */ | 56 | #endif /* __PERF_THREAD_H */ |
