diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-11-27 13:29:20 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-27 14:22:00 -0500 |
commit | 95011c600740837288a3b34b411244a4d9157c4e (patch) | |
tree | f52496d2d378a338e7b0eee9b75e627bdfc4d2f1 /tools | |
parent | 23ea4a3fadc6b1692dec935397ea15e2affc1cba (diff) |
perf symbols: Support multiple symtabs in struct thread
Making the routines that were so far specific to the kernel maps
useful for all threads.
This is done by making the kernel maps be contained in a kernel
"thread".
This gets the kernel specific routines closer to the userspace
counterparts, which will help in reducing the boilerplate for
resolving a symbol, as will be demonstrated in the next patches.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.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-9-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 157 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 115 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 15 |
7 files changed, 162 insertions, 133 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index c32e7609b77b..3ebd70b1ef93 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -167,7 +167,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
167 | map ? map->dso->long_name : "<not found>"); | 167 | map ? map->dso->long_name : "<not found>"); |
168 | } else if (event->header.misc & PERF_RECORD_MISC_USER) { | 168 | } else if (event->header.misc & PERF_RECORD_MISC_USER) { |
169 | level = '.'; | 169 | level = '.'; |
170 | map = thread__find_map(thread, ip); | 170 | map = thread__find_map(thread, MAP__FUNCTION, ip); |
171 | if (map != NULL) { | 171 | if (map != NULL) { |
172 | ip = map->map_ip(map, ip); | 172 | ip = map->map_ip(map, ip); |
173 | sym = map__find_symbol(map, ip, symbol_filter); | 173 | sym = map__find_symbol(map, ip, symbol_filter); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 400bef981c6c..9bd20c2ee3dd 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -422,7 +422,7 @@ resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp) | |||
422 | if (!thread) | 422 | if (!thread) |
423 | return NULL; | 423 | return NULL; |
424 | 424 | ||
425 | map = thread__find_map(thread, ip); | 425 | map = thread__find_map(thread, MAP__FUNCTION, ip); |
426 | if (map != NULL) { | 426 | if (map != NULL) { |
427 | /* | 427 | /* |
428 | * We have to do this here as we may have a dso | 428 | * We have to do this here as we may have a dso |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index abe78bbd154a..bf6730c76033 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -945,7 +945,7 @@ static void event__process_sample(const event_t *self, int counter) | |||
945 | if (thread == NULL) | 945 | if (thread == NULL) |
946 | return; | 946 | return; |
947 | 947 | ||
948 | map = thread__find_map(thread, ip); | 948 | map = thread__find_map(thread, MAP__FUNCTION, ip); |
949 | if (map != NULL) { | 949 | if (map != NULL) { |
950 | ip = map->map_ip(map, ip); | 950 | ip = map->map_ip(map, ip); |
951 | sym = map__find_symbol(map, ip, symbol_filter); | 951 | sym = map__find_symbol(map, ip, symbol_filter); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 581db4c43251..b6a2941e7786 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -29,12 +29,11 @@ enum dso_origin { | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | static void dsos__add(struct list_head *head, struct dso *dso); | 31 | static void dsos__add(struct list_head *head, struct dso *dso); |
32 | static struct map *kernel_maps__find_by_dso_name(const char *name); | 32 | static struct map *thread__find_map_by_name(struct thread *self, char *name); |
33 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 33 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
34 | static void kernel_maps__insert(struct map *map); | ||
35 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | 34 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); |
36 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 35 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
37 | symbol_filter_t filter); | 36 | struct thread *thread, symbol_filter_t filter); |
38 | unsigned int symbol__priv_size; | 37 | unsigned int symbol__priv_size; |
39 | static int vmlinux_path__nr_entries; | 38 | static int vmlinux_path__nr_entries; |
40 | static char **vmlinux_path; | 39 | static char **vmlinux_path; |
@@ -44,7 +43,7 @@ static struct symbol_conf symbol_conf__defaults = { | |||
44 | .try_vmlinux_path = true, | 43 | .try_vmlinux_path = true, |
45 | }; | 44 | }; |
46 | 45 | ||
47 | static struct rb_root kernel_maps[MAP__NR_TYPES]; | 46 | static struct thread kthread_mem, *kthread = &kthread_mem; |
48 | 47 | ||
49 | bool dso__loaded(const struct dso *self, enum map_type type) | 48 | bool dso__loaded(const struct dso *self, enum map_type type) |
50 | { | 49 | { |
@@ -79,10 +78,10 @@ static void symbols__fixup_end(struct rb_root *self) | |||
79 | curr->end = roundup(curr->start, 4096); | 78 | curr->end = roundup(curr->start, 4096); |
80 | } | 79 | } |
81 | 80 | ||
82 | static void __kernel_maps__fixup_end(struct rb_root *root) | 81 | static void __thread__fixup_maps_end(struct thread *self, enum map_type type) |
83 | { | 82 | { |
84 | struct map *prev, *curr; | 83 | struct map *prev, *curr; |
85 | struct rb_node *nd, *prevnd = rb_first(root); | 84 | struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); |
86 | 85 | ||
87 | if (prevnd == NULL) | 86 | if (prevnd == NULL) |
88 | return; | 87 | return; |
@@ -102,11 +101,11 @@ static void __kernel_maps__fixup_end(struct rb_root *root) | |||
102 | curr->end = ~0UL; | 101 | curr->end = ~0UL; |
103 | } | 102 | } |
104 | 103 | ||
105 | static void kernel_maps__fixup_end(void) | 104 | static void thread__fixup_maps_end(struct thread *self) |
106 | { | 105 | { |
107 | int i; | 106 | int i; |
108 | for (i = 0; i < MAP__NR_TYPES; ++i) | 107 | for (i = 0; i < MAP__NR_TYPES; ++i) |
109 | __kernel_maps__fixup_end(&kernel_maps[i]); | 108 | __thread__fixup_maps_end(self, i); |
110 | } | 109 | } |
111 | 110 | ||
112 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 111 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) |
@@ -274,25 +273,16 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp) | |||
274 | return fprintf(fp, "%s", sbuild_id); | 273 | return fprintf(fp, "%s", sbuild_id); |
275 | } | 274 | } |
276 | 275 | ||
277 | static const char * map_type__name[MAP__NR_TYPES] = { | 276 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) |
278 | [MAP__FUNCTION] = "Functions", | ||
279 | }; | ||
280 | |||
281 | size_t dso__fprintf(struct dso *self, FILE *fp) | ||
282 | { | 277 | { |
283 | int i; | ||
284 | struct rb_node *nd; | 278 | struct rb_node *nd; |
285 | size_t ret = fprintf(fp, "dso: %s (", self->short_name); | 279 | size_t ret = fprintf(fp, "dso: %s (", self->short_name); |
286 | 280 | ||
287 | ret += dso__fprintf_buildid(self, fp); | 281 | ret += dso__fprintf_buildid(self, fp); |
288 | ret += fprintf(fp, ")\n"); | 282 | ret += fprintf(fp, ")\n"); |
289 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 283 | for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { |
290 | ret += fprintf(fp, "%s:\n", map_type__name[i]); | 284 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
291 | 285 | ret += symbol__fprintf(pos, fp); | |
292 | for (nd = rb_first(&self->symbols[i]); nd; nd = rb_next(nd)) { | ||
293 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
294 | ret += symbol__fprintf(pos, fp); | ||
295 | } | ||
296 | } | 286 | } |
297 | 287 | ||
298 | return ret; | 288 | return ret; |
@@ -373,7 +363,7 @@ out_failure: | |||
373 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 363 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
374 | * the original ELF section names vmlinux have. | 364 | * the original ELF section names vmlinux have. |
375 | */ | 365 | */ |
376 | static int dso__split_kallsyms(struct dso *self, struct map *map, | 366 | static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, |
377 | symbol_filter_t filter) | 367 | symbol_filter_t filter) |
378 | { | 368 | { |
379 | struct map *curr_map = map; | 369 | struct map *curr_map = map; |
@@ -394,10 +384,10 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
394 | *module++ = '\0'; | 384 | *module++ = '\0'; |
395 | 385 | ||
396 | if (strcmp(self->name, module)) { | 386 | if (strcmp(self->name, module)) { |
397 | curr_map = kernel_maps__find_by_dso_name(module); | 387 | curr_map = thread__find_map_by_name(thread, module); |
398 | if (curr_map == NULL) { | 388 | if (curr_map == NULL) { |
399 | pr_err("/proc/{kallsyms,modules} " | 389 | pr_debug("/proc/{kallsyms,modules} " |
400 | "inconsistency!\n"); | 390 | "inconsistency!\n"); |
401 | return -1; | 391 | return -1; |
402 | } | 392 | } |
403 | } | 393 | } |
@@ -425,7 +415,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
425 | } | 415 | } |
426 | 416 | ||
427 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; | 417 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; |
428 | kernel_maps__insert(curr_map); | 418 | __thread__insert_map(thread, curr_map); |
429 | ++kernel_range; | 419 | ++kernel_range; |
430 | } | 420 | } |
431 | 421 | ||
@@ -446,7 +436,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
446 | 436 | ||
447 | 437 | ||
448 | static int dso__load_kallsyms(struct dso *self, struct map *map, | 438 | static int dso__load_kallsyms(struct dso *self, struct map *map, |
449 | symbol_filter_t filter) | 439 | struct thread *thread, symbol_filter_t filter) |
450 | { | 440 | { |
451 | if (dso__load_all_kallsyms(self, map) < 0) | 441 | if (dso__load_all_kallsyms(self, map) < 0) |
452 | return -1; | 442 | return -1; |
@@ -454,35 +444,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, | |||
454 | symbols__fixup_end(&self->symbols[map->type]); | 444 | symbols__fixup_end(&self->symbols[map->type]); |
455 | self->origin = DSO__ORIG_KERNEL; | 445 | self->origin = DSO__ORIG_KERNEL; |
456 | 446 | ||
457 | return dso__split_kallsyms(self, map, filter); | 447 | return dso__split_kallsyms(self, map, thread, filter); |
458 | } | ||
459 | |||
460 | static size_t __kernel_maps__fprintf(enum map_type type, FILE *fp) | ||
461 | { | ||
462 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
463 | struct rb_node *nd; | ||
464 | |||
465 | for (nd = rb_first(&kernel_maps[type]); nd; nd = rb_next(nd)) { | ||
466 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
467 | |||
468 | printed += fprintf(fp, "Map:"); | ||
469 | printed += map__fprintf(pos, fp); | ||
470 | if (verbose > 1) { | ||
471 | printed += dso__fprintf(pos->dso, fp); | ||
472 | printed += fprintf(fp, "--\n"); | ||
473 | } | ||
474 | } | ||
475 | |||
476 | return printed; | ||
477 | } | 448 | } |
478 | 449 | ||
479 | size_t kernel_maps__fprintf(FILE *fp) | 450 | size_t kernel_maps__fprintf(FILE *fp) |
480 | { | 451 | { |
481 | size_t printed = fprintf(fp, "Kernel maps:\n"); | 452 | size_t printed = fprintf(fp, "Kernel maps:\n"); |
482 | int i; | 453 | printed += thread__fprintf_maps(kthread, fp); |
483 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
484 | printed += __kernel_maps__fprintf(i, fp); | ||
485 | |||
486 | return printed + fprintf(fp, "END kernel maps\n"); | 454 | return printed + fprintf(fp, "END kernel maps\n"); |
487 | } | 455 | } |
488 | 456 | ||
@@ -772,9 +740,9 @@ out: | |||
772 | return 0; | 740 | return 0; |
773 | } | 741 | } |
774 | 742 | ||
775 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, | 743 | static int dso__load_sym(struct dso *self, struct map *map, |
776 | int fd, symbol_filter_t filter, int kernel, | 744 | struct thread *thread, const char *name, int fd, |
777 | int kmodule) | 745 | symbol_filter_t filter, int kernel, int kmodule) |
778 | { | 746 | { |
779 | struct map *curr_map = map; | 747 | struct map *curr_map = map; |
780 | struct dso *curr_dso = self; | 748 | struct dso *curr_dso = self; |
@@ -877,7 +845,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
877 | snprintf(dso_name, sizeof(dso_name), | 845 | snprintf(dso_name, sizeof(dso_name), |
878 | "%s%s", self->short_name, section_name); | 846 | "%s%s", self->short_name, section_name); |
879 | 847 | ||
880 | curr_map = kernel_maps__find_by_dso_name(dso_name); | 848 | curr_map = thread__find_map_by_name(thread, dso_name); |
881 | if (curr_map == NULL) { | 849 | if (curr_map == NULL) { |
882 | u64 start = sym.st_value; | 850 | u64 start = sym.st_value; |
883 | 851 | ||
@@ -896,7 +864,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
896 | curr_map->map_ip = identity__map_ip; | 864 | curr_map->map_ip = identity__map_ip; |
897 | curr_map->unmap_ip = identity__map_ip; | 865 | curr_map->unmap_ip = identity__map_ip; |
898 | curr_dso->origin = DSO__ORIG_KERNEL; | 866 | curr_dso->origin = DSO__ORIG_KERNEL; |
899 | kernel_maps__insert(curr_map); | 867 | __thread__insert_map(kthread, curr_map); |
900 | dsos__add(&dsos__kernel, curr_dso); | 868 | dsos__add(&dsos__kernel, curr_dso); |
901 | } else | 869 | } else |
902 | curr_dso = curr_map->dso; | 870 | curr_dso = curr_map->dso; |
@@ -1121,7 +1089,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1121 | dso__set_loaded(self, map->type); | 1089 | dso__set_loaded(self, map->type); |
1122 | 1090 | ||
1123 | if (self->kernel) | 1091 | if (self->kernel) |
1124 | return dso__load_kernel_sym(self, map, filter); | 1092 | return dso__load_kernel_sym(self, map, kthread, filter); |
1125 | 1093 | ||
1126 | name = malloc(size); | 1094 | name = malloc(size); |
1127 | if (!name) | 1095 | if (!name) |
@@ -1186,7 +1154,7 @@ compare_build_id: | |||
1186 | fd = open(name, O_RDONLY); | 1154 | fd = open(name, O_RDONLY); |
1187 | } while (fd < 0); | 1155 | } while (fd < 0); |
1188 | 1156 | ||
1189 | ret = dso__load_sym(self, map, name, fd, filter, 0, 0); | 1157 | ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); |
1190 | close(fd); | 1158 | close(fd); |
1191 | 1159 | ||
1192 | /* | 1160 | /* |
@@ -1207,16 +1175,11 @@ out: | |||
1207 | return ret; | 1175 | return ret; |
1208 | } | 1176 | } |
1209 | 1177 | ||
1210 | static void kernel_maps__insert(struct map *map) | 1178 | static struct symbol *thread__find_symbol(struct thread *self, u64 ip, |
1211 | { | 1179 | enum map_type type, struct map **mapp, |
1212 | maps__insert(&kernel_maps[map->type], map); | 1180 | symbol_filter_t filter) |
1213 | } | ||
1214 | |||
1215 | static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, | ||
1216 | struct map **mapp, | ||
1217 | symbol_filter_t filter) | ||
1218 | { | 1181 | { |
1219 | struct map *map = maps__find(&kernel_maps[type], ip); | 1182 | struct map *map = thread__find_map(self, type, ip); |
1220 | 1183 | ||
1221 | if (mapp) | 1184 | if (mapp) |
1222 | *mapp = map; | 1185 | *mapp = map; |
@@ -1224,9 +1187,7 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, | |||
1224 | if (map) { | 1187 | if (map) { |
1225 | ip = map->map_ip(map, ip); | 1188 | ip = map->map_ip(map, ip); |
1226 | return map__find_symbol(map, ip, filter); | 1189 | return map__find_symbol(map, ip, filter); |
1227 | } else | 1190 | } |
1228 | WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps[type]), | ||
1229 | "Empty kernel_maps, was symbol__init() called?\n"); | ||
1230 | 1191 | ||
1231 | return NULL; | 1192 | return NULL; |
1232 | } | 1193 | } |
@@ -1234,14 +1195,14 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, | |||
1234 | struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, | 1195 | struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, |
1235 | symbol_filter_t filter) | 1196 | symbol_filter_t filter) |
1236 | { | 1197 | { |
1237 | return kernel_maps__find_symbol(ip, MAP__FUNCTION, mapp, filter); | 1198 | return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter); |
1238 | } | 1199 | } |
1239 | 1200 | ||
1240 | static struct map *kernel_maps__find_by_dso_name(const char *name) | 1201 | static struct map *thread__find_map_by_name(struct thread *self, char *name) |
1241 | { | 1202 | { |
1242 | struct rb_node *nd; | 1203 | struct rb_node *nd; |
1243 | 1204 | ||
1244 | for (nd = rb_first(&kernel_maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { | 1205 | for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { |
1245 | struct map *map = rb_entry(nd, struct map, rb_node); | 1206 | struct map *map = rb_entry(nd, struct map, rb_node); |
1246 | 1207 | ||
1247 | if (map->dso && strcmp(map->dso->name, name) == 0) | 1208 | if (map->dso && strcmp(map->dso->name, name) == 0) |
@@ -1285,7 +1246,7 @@ static int dsos__set_modules_path_dir(char *dirname) | |||
1285 | (int)(dot - dent->d_name), dent->d_name); | 1246 | (int)(dot - dent->d_name), dent->d_name); |
1286 | 1247 | ||
1287 | strxfrchar(dso_name, '-', '_'); | 1248 | strxfrchar(dso_name, '-', '_'); |
1288 | map = kernel_maps__find_by_dso_name(dso_name); | 1249 | map = thread__find_map_by_name(kthread, dso_name); |
1289 | if (map == NULL) | 1250 | if (map == NULL) |
1290 | continue; | 1251 | continue; |
1291 | 1252 | ||
@@ -1338,7 +1299,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
1338 | return self; | 1299 | return self; |
1339 | } | 1300 | } |
1340 | 1301 | ||
1341 | static int kernel_maps__create_module_maps(void) | 1302 | static int thread__create_module_maps(struct thread *self) |
1342 | { | 1303 | { |
1343 | char *line = NULL; | 1304 | char *line = NULL; |
1344 | size_t n; | 1305 | size_t n; |
@@ -1395,7 +1356,7 @@ static int kernel_maps__create_module_maps(void) | |||
1395 | dso->has_build_id = true; | 1356 | dso->has_build_id = true; |
1396 | 1357 | ||
1397 | dso->origin = DSO__ORIG_KMODULE; | 1358 | dso->origin = DSO__ORIG_KMODULE; |
1398 | kernel_maps__insert(map); | 1359 | __thread__insert_map(self, map); |
1399 | dsos__add(&dsos__kernel, dso); | 1360 | dsos__add(&dsos__kernel, dso); |
1400 | } | 1361 | } |
1401 | 1362 | ||
@@ -1410,7 +1371,7 @@ out_failure: | |||
1410 | return -1; | 1371 | return -1; |
1411 | } | 1372 | } |
1412 | 1373 | ||
1413 | static int dso__load_vmlinux(struct dso *self, struct map *map, | 1374 | static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, |
1414 | const char *vmlinux, symbol_filter_t filter) | 1375 | const char *vmlinux, symbol_filter_t filter) |
1415 | { | 1376 | { |
1416 | int err = -1, fd; | 1377 | int err = -1, fd; |
@@ -1444,15 +1405,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, | |||
1444 | return -1; | 1405 | return -1; |
1445 | 1406 | ||
1446 | dso__set_loaded(self, map->type); | 1407 | dso__set_loaded(self, map->type); |
1447 | err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); | 1408 | err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); |
1448 | |||
1449 | close(fd); | 1409 | close(fd); |
1450 | 1410 | ||
1451 | return err; | 1411 | return err; |
1452 | } | 1412 | } |
1453 | 1413 | ||
1454 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 1414 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
1455 | symbol_filter_t filter) | 1415 | struct thread *thread, symbol_filter_t filter) |
1456 | { | 1416 | { |
1457 | int err; | 1417 | int err; |
1458 | bool is_kallsyms; | 1418 | bool is_kallsyms; |
@@ -1462,8 +1422,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1462 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", | 1422 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", |
1463 | vmlinux_path__nr_entries); | 1423 | vmlinux_path__nr_entries); |
1464 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1424 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1465 | err = dso__load_vmlinux(self, map, vmlinux_path[i], | 1425 | err = dso__load_vmlinux(self, map, thread, |
1466 | filter); | 1426 | vmlinux_path[i], filter); |
1467 | if (err > 0) { | 1427 | if (err > 0) { |
1468 | pr_debug("Using %s for symbols\n", | 1428 | pr_debug("Using %s for symbols\n", |
1469 | vmlinux_path[i]); | 1429 | vmlinux_path[i]); |
@@ -1478,12 +1438,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1478 | if (is_kallsyms) | 1438 | if (is_kallsyms) |
1479 | goto do_kallsyms; | 1439 | goto do_kallsyms; |
1480 | 1440 | ||
1481 | err = dso__load_vmlinux(self, map, self->long_name, filter); | 1441 | err = dso__load_vmlinux(self, map, thread, self->long_name, filter); |
1482 | if (err <= 0) { | 1442 | if (err <= 0) { |
1483 | pr_info("The file %s cannot be used, " | 1443 | pr_info("The file %s cannot be used, " |
1484 | "trying to use /proc/kallsyms...", self->long_name); | 1444 | "trying to use /proc/kallsyms...", self->long_name); |
1485 | do_kallsyms: | 1445 | do_kallsyms: |
1486 | err = dso__load_kallsyms(self, map, filter); | 1446 | err = dso__load_kallsyms(self, map, thread, filter); |
1487 | if (err > 0 && !is_kallsyms) | 1447 | if (err > 0 && !is_kallsyms) |
1488 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); | 1448 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); |
1489 | } | 1449 | } |
@@ -1535,8 +1495,11 @@ static void __dsos__fprintf(struct list_head *head, FILE *fp) | |||
1535 | { | 1495 | { |
1536 | struct dso *pos; | 1496 | struct dso *pos; |
1537 | 1497 | ||
1538 | list_for_each_entry(pos, head, node) | 1498 | list_for_each_entry(pos, head, node) { |
1539 | dso__fprintf(pos, fp); | 1499 | int i; |
1500 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
1501 | dso__fprintf(pos, i, fp); | ||
1502 | } | ||
1540 | } | 1503 | } |
1541 | 1504 | ||
1542 | void dsos__fprintf(FILE *fp) | 1505 | void dsos__fprintf(FILE *fp) |
@@ -1563,10 +1526,10 @@ size_t dsos__fprintf_buildid(FILE *fp) | |||
1563 | __dsos__fprintf_buildid(&dsos__user, fp)); | 1526 | __dsos__fprintf_buildid(&dsos__user, fp)); |
1564 | } | 1527 | } |
1565 | 1528 | ||
1566 | static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) | 1529 | static int thread__create_kernel_map(struct thread *self, const char *vmlinux) |
1567 | { | 1530 | { |
1568 | struct map *kmap; | 1531 | struct map *kmap; |
1569 | struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]"); | 1532 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); |
1570 | 1533 | ||
1571 | if (kernel == NULL) | 1534 | if (kernel == NULL) |
1572 | return -1; | 1535 | return -1; |
@@ -1588,7 +1551,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) | |||
1588 | sizeof(kernel->build_id)) == 0) | 1551 | sizeof(kernel->build_id)) == 0) |
1589 | kernel->has_build_id = true; | 1552 | kernel->has_build_id = true; |
1590 | 1553 | ||
1591 | kernel_maps__insert(kmap); | 1554 | __thread__insert_map(self, kmap); |
1592 | dsos__add(&dsos__kernel, kernel); | 1555 | dsos__add(&dsos__kernel, kernel); |
1593 | dsos__add(&dsos__user, vdso); | 1556 | dsos__add(&dsos__user, vdso); |
1594 | 1557 | ||
@@ -1656,32 +1619,28 @@ out_fail: | |||
1656 | return -1; | 1619 | return -1; |
1657 | } | 1620 | } |
1658 | 1621 | ||
1659 | static int kernel_maps__init(const struct symbol_conf *conf) | 1622 | int symbol__init(struct symbol_conf *conf) |
1660 | { | 1623 | { |
1661 | const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; | 1624 | const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; |
1662 | 1625 | ||
1626 | elf_version(EV_CURRENT); | ||
1663 | symbol__priv_size = pconf->priv_size; | 1627 | symbol__priv_size = pconf->priv_size; |
1628 | thread__init(kthread, 0); | ||
1664 | 1629 | ||
1665 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) | 1630 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) |
1666 | return -1; | 1631 | return -1; |
1667 | 1632 | ||
1668 | if (kernel_maps__create_kernel_map(pconf) < 0) { | 1633 | if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { |
1669 | vmlinux_path__exit(); | 1634 | vmlinux_path__exit(); |
1670 | return -1; | 1635 | return -1; |
1671 | } | 1636 | } |
1672 | 1637 | ||
1673 | if (pconf->use_modules && kernel_maps__create_module_maps() < 0) | 1638 | if (pconf->use_modules && thread__create_module_maps(kthread) < 0) |
1674 | pr_debug("Failed to load list of modules in use, " | 1639 | pr_debug("Failed to load list of modules in use, " |
1675 | "continuing...\n"); | 1640 | "continuing...\n"); |
1676 | /* | 1641 | /* |
1677 | * Now that we have all the maps created, just set the ->end of them: | 1642 | * Now that we have all the maps created, just set the ->end of them: |
1678 | */ | 1643 | */ |
1679 | kernel_maps__fixup_end(); | 1644 | thread__fixup_maps_end(kthread); |
1680 | return 0; | 1645 | return 0; |
1681 | } | 1646 | } |
1682 | |||
1683 | int symbol__init(struct symbol_conf *conf) | ||
1684 | { | ||
1685 | elf_version(EV_CURRENT); | ||
1686 | return kernel_maps__init(conf); | ||
1687 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8934814d5a64..3f9e4a4d83dd 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -92,7 +92,7 @@ void dsos__fprintf(FILE *fp); | |||
92 | size_t dsos__fprintf_buildid(FILE *fp); | 92 | size_t dsos__fprintf_buildid(FILE *fp); |
93 | 93 | ||
94 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp); | 94 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp); |
95 | size_t dso__fprintf(struct dso *self, FILE *fp); | 95 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); |
96 | char dso__symtab_origin(const struct dso *self); | 96 | char dso__symtab_origin(const struct dso *self); |
97 | void dso__set_build_id(struct dso *self, void *build_id); | 97 | void dso__set_build_id(struct dso *self, void *build_id); |
98 | 98 | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 1796625f7784..2229f82cd630 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -9,17 +9,26 @@ | |||
9 | static struct rb_root threads; | 9 | static struct rb_root threads; |
10 | static struct thread *last_match; | 10 | static struct thread *last_match; |
11 | 11 | ||
12 | void thread__init(struct thread *self, pid_t pid) | ||
13 | { | ||
14 | int i; | ||
15 | self->pid = pid; | ||
16 | self->comm = NULL; | ||
17 | for (i = 0; i < MAP__NR_TYPES; ++i) { | ||
18 | self->maps[i] = RB_ROOT; | ||
19 | INIT_LIST_HEAD(&self->removed_maps[i]); | ||
20 | } | ||
21 | } | ||
22 | |||
12 | static struct thread *thread__new(pid_t pid) | 23 | static struct thread *thread__new(pid_t pid) |
13 | { | 24 | { |
14 | struct thread *self = zalloc(sizeof(*self)); | 25 | struct thread *self = zalloc(sizeof(*self)); |
15 | 26 | ||
16 | if (self != NULL) { | 27 | if (self != NULL) { |
17 | self->pid = pid; | 28 | thread__init(self, pid); |
18 | self->comm = malloc(32); | 29 | self->comm = malloc(32); |
19 | if (self->comm) | 30 | if (self->comm) |
20 | snprintf(self->comm, 32, ":%d", self->pid); | 31 | snprintf(self->comm, 32, ":%d", self->pid); |
21 | self->maps = RB_ROOT; | ||
22 | INIT_LIST_HEAD(&self->removed_maps); | ||
23 | } | 32 | } |
24 | 33 | ||
25 | return self; | 34 | return self; |
@@ -44,24 +53,68 @@ int thread__comm_len(struct thread *self) | |||
44 | return self->comm_len; | 53 | return self->comm_len; |
45 | } | 54 | } |
46 | 55 | ||
47 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 56 | static const char *map_type__name[MAP__NR_TYPES] = { |
57 | [MAP__FUNCTION] = "Functions", | ||
58 | }; | ||
59 | |||
60 | static size_t __thread__fprintf_maps(struct thread *self, | ||
61 | enum map_type type, FILE *fp) | ||
48 | { | 62 | { |
63 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
49 | struct rb_node *nd; | 64 | struct rb_node *nd; |
50 | struct map *pos; | ||
51 | size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", | ||
52 | self->pid, self->comm); | ||
53 | 65 | ||
54 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { | 66 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { |
55 | pos = rb_entry(nd, struct map, rb_node); | 67 | struct map *pos = rb_entry(nd, struct map, rb_node); |
56 | ret += map__fprintf(pos, fp); | 68 | printed += fprintf(fp, "Map:"); |
69 | printed += map__fprintf(pos, fp); | ||
70 | if (verbose > 1) { | ||
71 | printed += dso__fprintf(pos->dso, type, fp); | ||
72 | printed += fprintf(fp, "--\n"); | ||
73 | } | ||
57 | } | 74 | } |
58 | 75 | ||
59 | ret = fprintf(fp, "Removed maps:\n"); | 76 | return printed; |
77 | } | ||
78 | |||
79 | size_t thread__fprintf_maps(struct thread *self, FILE *fp) | ||
80 | { | ||
81 | size_t printed = 0, i; | ||
82 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
83 | printed += __thread__fprintf_maps(self, i, fp); | ||
84 | return printed; | ||
85 | } | ||
60 | 86 | ||
61 | list_for_each_entry(pos, &self->removed_maps, node) | 87 | static size_t __thread__fprintf_removed_maps(struct thread *self, |
62 | ret += map__fprintf(pos, fp); | 88 | enum map_type type, FILE *fp) |
89 | { | ||
90 | struct map *pos; | ||
91 | size_t printed = 0; | ||
92 | |||
93 | list_for_each_entry(pos, &self->removed_maps[type], node) { | ||
94 | printed += fprintf(fp, "Map:"); | ||
95 | printed += map__fprintf(pos, fp); | ||
96 | if (verbose > 1) { | ||
97 | printed += dso__fprintf(pos->dso, type, fp); | ||
98 | printed += fprintf(fp, "--\n"); | ||
99 | } | ||
100 | } | ||
101 | return printed; | ||
102 | } | ||
63 | 103 | ||
64 | return ret; | 104 | static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) |
105 | { | ||
106 | size_t printed = 0, i; | ||
107 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
108 | printed += __thread__fprintf_removed_maps(self, i, fp); | ||
109 | return printed; | ||
110 | } | ||
111 | |||
112 | static size_t thread__fprintf(struct thread *self, FILE *fp) | ||
113 | { | ||
114 | size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | ||
115 | printed += thread__fprintf_removed_maps(self, fp); | ||
116 | printed += fprintf(fp, "Removed maps:\n"); | ||
117 | return printed + thread__fprintf_removed_maps(self, fp); | ||
65 | } | 118 | } |
66 | 119 | ||
67 | struct thread *threads__findnew(pid_t pid) | 120 | struct thread *threads__findnew(pid_t pid) |
@@ -117,7 +170,8 @@ struct thread *register_idle_thread(void) | |||
117 | 170 | ||
118 | static void thread__remove_overlappings(struct thread *self, struct map *map) | 171 | static void thread__remove_overlappings(struct thread *self, struct map *map) |
119 | { | 172 | { |
120 | struct rb_node *next = rb_first(&self->maps); | 173 | struct rb_root *root = &self->maps[map->type]; |
174 | struct rb_node *next = rb_first(root); | ||
121 | 175 | ||
122 | while (next) { | 176 | while (next) { |
123 | struct map *pos = rb_entry(next, struct map, rb_node); | 177 | struct map *pos = rb_entry(next, struct map, rb_node); |
@@ -132,13 +186,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) | |||
132 | map__fprintf(pos, stderr); | 186 | map__fprintf(pos, stderr); |
133 | } | 187 | } |
134 | 188 | ||
135 | rb_erase(&pos->rb_node, &self->maps); | 189 | rb_erase(&pos->rb_node, root); |
136 | /* | 190 | /* |
137 | * We may have references to this map, for instance in some | 191 | * We may have references to this map, for instance in some |
138 | * hist_entry instances, so just move them to a separate | 192 | * hist_entry instances, so just move them to a separate |
139 | * list. | 193 | * list. |
140 | */ | 194 | */ |
141 | list_add_tail(&pos->node, &self->removed_maps); | 195 | list_add_tail(&pos->node, &self->removed_maps[map->type]); |
142 | } | 196 | } |
143 | } | 197 | } |
144 | 198 | ||
@@ -185,12 +239,26 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
185 | void thread__insert_map(struct thread *self, struct map *map) | 239 | void thread__insert_map(struct thread *self, struct map *map) |
186 | { | 240 | { |
187 | thread__remove_overlappings(self, map); | 241 | thread__remove_overlappings(self, map); |
188 | maps__insert(&self->maps, map); | 242 | maps__insert(&self->maps[map->type], map); |
189 | } | 243 | } |
190 | 244 | ||
191 | int thread__fork(struct thread *self, struct thread *parent) | 245 | static int thread__clone_maps(struct thread *self, struct thread *parent, |
246 | enum map_type type) | ||
192 | { | 247 | { |
193 | struct rb_node *nd; | 248 | struct rb_node *nd; |
249 | for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { | ||
250 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
251 | struct map *new = map__clone(map); | ||
252 | if (new == NULL) | ||
253 | return -ENOMEM; | ||
254 | thread__insert_map(self, new); | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int thread__fork(struct thread *self, struct thread *parent) | ||
260 | { | ||
261 | int i; | ||
194 | 262 | ||
195 | if (self->comm) | 263 | if (self->comm) |
196 | free(self->comm); | 264 | free(self->comm); |
@@ -198,14 +266,9 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
198 | if (!self->comm) | 266 | if (!self->comm) |
199 | return -ENOMEM; | 267 | return -ENOMEM; |
200 | 268 | ||
201 | for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { | 269 | for (i = 0; i < MAP__NR_TYPES; ++i) |
202 | struct map *map = rb_entry(nd, struct map, rb_node); | 270 | if (thread__clone_maps(self, parent, i) < 0) |
203 | struct map *new = map__clone(map); | ||
204 | if (!new) | ||
205 | return -ENOMEM; | 271 | return -ENOMEM; |
206 | thread__insert_map(self, new); | ||
207 | } | ||
208 | |||
209 | return 0; | 272 | return 0; |
210 | } | 273 | } |
211 | 274 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 54580bb80008..3bdd9b2276f0 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -7,20 +7,22 @@ | |||
7 | 7 | ||
8 | struct thread { | 8 | struct thread { |
9 | struct rb_node rb_node; | 9 | struct rb_node rb_node; |
10 | struct rb_root maps; | 10 | struct rb_root maps[MAP__NR_TYPES]; |
11 | struct list_head removed_maps; | 11 | struct list_head removed_maps[MAP__NR_TYPES]; |
12 | pid_t pid; | 12 | pid_t pid; |
13 | char shortname[3]; | 13 | char shortname[3]; |
14 | char *comm; | 14 | char *comm; |
15 | int comm_len; | 15 | int comm_len; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | void thread__init(struct thread *self, pid_t pid); | ||
18 | int thread__set_comm(struct thread *self, const char *comm); | 19 | int thread__set_comm(struct thread *self, const char *comm); |
19 | int thread__comm_len(struct thread *self); | 20 | int thread__comm_len(struct thread *self); |
20 | struct thread *threads__findnew(pid_t pid); | 21 | struct thread *threads__findnew(pid_t pid); |
21 | struct thread *register_idle_thread(void); | 22 | struct thread *register_idle_thread(void); |
22 | void thread__insert_map(struct thread *self, struct map *map); | 23 | void thread__insert_map(struct thread *self, struct map *map); |
23 | int thread__fork(struct thread *self, struct thread *parent); | 24 | int thread__fork(struct thread *self, struct thread *parent); |
25 | size_t thread__fprintf_maps(struct thread *self, FILE *fp); | ||
24 | size_t threads__fprintf(FILE *fp); | 26 | size_t threads__fprintf(FILE *fp); |
25 | 27 | ||
26 | void maps__insert(struct rb_root *maps, struct map *map); | 28 | void maps__insert(struct rb_root *maps, struct map *map); |
@@ -29,9 +31,14 @@ struct map *maps__find(struct rb_root *maps, u64 ip); | |||
29 | struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, | 31 | struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, |
30 | symbol_filter_t filter); | 32 | symbol_filter_t filter); |
31 | 33 | ||
32 | static inline struct map *thread__find_map(struct thread *self, u64 ip) | 34 | static inline struct map *thread__find_map(struct thread *self, |
35 | enum map_type type, u64 ip) | ||
33 | { | 36 | { |
34 | return self ? maps__find(&self->maps, ip) : NULL; | 37 | return self ? maps__find(&self->maps[type], ip) : NULL; |
35 | } | 38 | } |
36 | 39 | ||
40 | static inline void __thread__insert_map(struct thread *self, struct map *map) | ||
41 | { | ||
42 | maps__insert(&self->maps[map->type], map); | ||
43 | } | ||
37 | #endif /* __PERF_THREAD_H */ | 44 | #endif /* __PERF_THREAD_H */ |