diff options
Diffstat (limited to 'tools/perf')
-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 */ |