aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-01-13 10:22:17 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-13 11:39:43 -0500
commitb7cece76783c68fb391f9882235b4b0c9c300c46 (patch)
tree8a0224493acc3cf74c218384a3b76b3e47c131a2 /tools/perf/util/symbol.c
parentff314d3903c2843de65c2148f66f277f2440ed26 (diff)
perf tools: Encode kernel module mappings in perf.data
We were always looking at the running machine /proc/modules, even when processing a perf.data file, which only makes sense when we're doing 'perf record' and 'perf report' on the same machine, and in close sucession, or if we don't use modules at all, right Peter? ;-) Now, at 'perf record' time we read /proc/modules, find the long path for modules, and put them as PERF_MMAP events, just like we did to encode the reloc reference symbol for vmlinux. Talking about that now it is encoded in .pgoff, so that we can use .{start,len} to store the address boundaries for the kernel so that when we reconstruct the kmaps tree we can do lookups right away, without having to fixup the end of the kernel maps like we did in the past (and now only in perf record). One more step in the 'perf archive' direction when we'll finally be able to collect data in one machine and analyse in another. 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: <1263396139-4798-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c116
1 files changed, 84 insertions, 32 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8e6627e6b778..381999dd5c1f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -161,7 +161,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
161 self->start, self->end, self->name); 161 self->start, self->end, self->name);
162} 162}
163 163
164static void dso__set_long_name(struct dso *self, char *name) 164void dso__set_long_name(struct dso *self, char *name)
165{ 165{
166 if (name == NULL) 166 if (name == NULL)
167 return; 167 return;
@@ -176,7 +176,7 @@ static void dso__set_basename(struct dso *self)
176 176
177struct dso *dso__new(const char *name) 177struct dso *dso__new(const char *name)
178{ 178{
179 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 179 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
180 180
181 if (self != NULL) { 181 if (self != NULL) {
182 int i; 182 int i;
@@ -500,13 +500,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
500 500
501 *module++ = '\0'; 501 *module++ = '\0';
502 502
503 if (strcmp(self->name, module)) { 503 if (strcmp(curr_map->dso->short_name, module)) {
504 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 504 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
505 if (curr_map == NULL) { 505 if (curr_map == NULL) {
506 pr_debug("/proc/{kallsyms,modules} " 506 pr_debug("/proc/{kallsyms,modules} "
507 "inconsistency!\n"); 507 "inconsistency while looking "
508 "for \"%s\" module!\n", module);
508 return -1; 509 return -1;
509 } 510 }
511
512 if (curr_map->dso->loaded)
513 goto discard_symbol;
510 } 514 }
511 /* 515 /*
512 * So that we look just like we get from .ko files, 516 * So that we look just like we get from .ko files,
@@ -1343,13 +1347,33 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1343 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1347 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1344 struct map *map = rb_entry(nd, struct map, rb_node); 1348 struct map *map = rb_entry(nd, struct map, rb_node);
1345 1349
1346 if (map->dso && strcmp(map->dso->name, name) == 0) 1350 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1347 return map; 1351 return map;
1348 } 1352 }
1349 1353
1350 return NULL; 1354 return NULL;
1351} 1355}
1352 1356
1357static int dso__kernel_module_get_build_id(struct dso *self)
1358{
1359 char filename[PATH_MAX];
1360 /*
1361 * kernel module short names are of the form "[module]" and
1362 * we need just "module" here.
1363 */
1364 const char *name = self->short_name + 1;
1365
1366 snprintf(filename, sizeof(filename),
1367 "/sys/module/%.*s/notes/.note.gnu.build-id",
1368 (int)strlen(name - 1), name);
1369
1370 if (sysfs__read_build_id(filename, self->build_id,
1371 sizeof(self->build_id)) == 0)
1372 self->has_build_id = true;
1373
1374 return 0;
1375}
1376
1353static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1377static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1354{ 1378{
1355 struct dirent *dent; 1379 struct dirent *dent;
@@ -1395,6 +1419,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1395 if (long_name == NULL) 1419 if (long_name == NULL)
1396 goto failure; 1420 goto failure;
1397 dso__set_long_name(map->dso, long_name); 1421 dso__set_long_name(map->dso, long_name);
1422 dso__kernel_module_get_build_id(map->dso);
1398 } 1423 }
1399 } 1424 }
1400 1425
@@ -1437,6 +1462,24 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1437 return self; 1462 return self;
1438} 1463}
1439 1464
1465struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
1466 const char *filename)
1467{
1468 struct map *map;
1469 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1470
1471 if (dso == NULL)
1472 return NULL;
1473
1474 map = map__new2(start, dso, MAP__FUNCTION);
1475 if (map == NULL)
1476 return NULL;
1477
1478 dso->origin = DSO__ORIG_KMODULE;
1479 map_groups__insert(&self->kmaps, map);
1480 return map;
1481}
1482
1440static int perf_session__create_module_maps(struct perf_session *self) 1483static int perf_session__create_module_maps(struct perf_session *self)
1441{ 1484{
1442 char *line = NULL; 1485 char *line = NULL;
@@ -1450,7 +1493,6 @@ static int perf_session__create_module_maps(struct perf_session *self)
1450 while (!feof(file)) { 1493 while (!feof(file)) {
1451 char name[PATH_MAX]; 1494 char name[PATH_MAX];
1452 u64 start; 1495 u64 start;
1453 struct dso *dso;
1454 char *sep; 1496 char *sep;
1455 int line_len; 1497 int line_len;
1456 1498
@@ -1476,26 +1518,10 @@ static int perf_session__create_module_maps(struct perf_session *self)
1476 *sep = '\0'; 1518 *sep = '\0';
1477 1519
1478 snprintf(name, sizeof(name), "[%s]", line); 1520 snprintf(name, sizeof(name), "[%s]", line);
1479 dso = dso__new(name); 1521 map = perf_session__new_module_map(self, start, name);
1480 1522 if (map == NULL)
1481 if (dso == NULL)
1482 goto out_delete_line;
1483
1484 map = map__new2(start, dso, MAP__FUNCTION);
1485 if (map == NULL) {
1486 dso__delete(dso);
1487 goto out_delete_line; 1523 goto out_delete_line;
1488 } 1524 dso__kernel_module_get_build_id(map->dso);
1489
1490 snprintf(name, sizeof(name),
1491 "/sys/module/%s/notes/.note.gnu.build-id", line);
1492 if (sysfs__read_build_id(name, dso->build_id,
1493 sizeof(dso->build_id)) == 0)
1494 dso->has_build_id = true;
1495
1496 dso->origin = DSO__ORIG_KMODULE;
1497 map_groups__insert(&self->kmaps, map);
1498 dsos__add(&dsos__kernel, dso);
1499 } 1525 }
1500 1526
1501 free(line); 1527 free(line);
@@ -1573,10 +1599,28 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1573 } 1599 }
1574 } 1600 }
1575 1601
1602 /*
1603 * Say the kernel DSO was created when processing the build-id header table,
1604 * we have a build-id, so check if it is the same as the running kernel,
1605 * using it if it is.
1606 */
1607 if (self->has_build_id) {
1608 u8 kallsyms_build_id[BUILD_ID_SIZE];
1609
1610 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1611 sizeof(kallsyms_build_id)) == 0)
1612
1613 is_kallsyms = dso__build_id_equal(self, kallsyms_build_id);
1614 if (is_kallsyms)
1615 goto do_kallsyms;
1616 goto do_vmlinux;
1617 }
1618
1576 is_kallsyms = self->long_name[0] == '['; 1619 is_kallsyms = self->long_name[0] == '[';
1577 if (is_kallsyms) 1620 if (is_kallsyms)
1578 goto do_kallsyms; 1621 goto do_kallsyms;
1579 1622
1623do_vmlinux:
1580 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1624 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1581 if (err <= 0) { 1625 if (err <= 0) {
1582 pr_info("The file %s cannot be used, " 1626 pr_info("The file %s cannot be used, "
@@ -1694,16 +1738,12 @@ out_delete_kernel_dso:
1694 return NULL; 1738 return NULL;
1695} 1739}
1696 1740
1697static int map_groups__create_kernel_maps(struct map_groups *self, 1741int __map_groups__create_kernel_maps(struct map_groups *self,
1698 struct map *vmlinux_maps[MAP__NR_TYPES], 1742 struct map *vmlinux_maps[MAP__NR_TYPES],
1699 const char *vmlinux) 1743 struct dso *kernel)
1700{ 1744{
1701 struct dso *kernel = dsos__create_kernel(vmlinux);
1702 enum map_type type; 1745 enum map_type type;
1703 1746
1704 if (kernel == NULL)
1705 return -1;
1706
1707 for (type = 0; type < MAP__NR_TYPES; ++type) { 1747 for (type = 0; type < MAP__NR_TYPES; ++type) {
1708 vmlinux_maps[type] = map__new2(0, kernel, type); 1748 vmlinux_maps[type] = map__new2(0, kernel, type);
1709 if (vmlinux_maps[type] == NULL) 1749 if (vmlinux_maps[type] == NULL)
@@ -1717,6 +1757,18 @@ static int map_groups__create_kernel_maps(struct map_groups *self,
1717 return 0; 1757 return 0;
1718} 1758}
1719 1759
1760static int map_groups__create_kernel_maps(struct map_groups *self,
1761 struct map *vmlinux_maps[MAP__NR_TYPES],
1762 const char *vmlinux)
1763{
1764 struct dso *kernel = dsos__create_kernel(vmlinux);
1765
1766 if (kernel == NULL)
1767 return -1;
1768
1769 return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel);
1770}
1771
1720static void vmlinux_path__exit(void) 1772static void vmlinux_path__exit(void)
1721{ 1773{
1722 while (--vmlinux_path__nr_entries >= 0) { 1774 while (--vmlinux_path__nr_entries >= 0) {