diff options
Diffstat (limited to 'tools/perf/util')
-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 |
8 files changed, 117 insertions, 41 deletions
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 */ |