diff options
-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 */ |