aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-01-14 15:30:06 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-16 04:58:47 -0500
commit9e201442de7c954f03710ac76f28c1927d07550c (patch)
tree7682ebe87ca85468e0ecd28b277013e9359605c0 /tools/perf/util
parent8d0591f6ad9edf66697ce29de176fb6f3213b9e3 (diff)
perf symbols: Cache /proc/kallsyms files by build-id
So that when we don't have a vmlinux handy we can store the kallsyms for later use by 'perf report'. 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: <1263501006-14185-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.c2
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/symbol.c48
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/util.c30
5 files changed, 80 insertions, 20 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 24ec5be4a1c0..0e9820ac4f5e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -245,7 +245,7 @@ int event__synthesize_kernel_mmap(event__handler_t process,
245 */ 245 */
246 struct process_symbol_args args = { .name = symbol_name, }; 246 struct process_symbol_args args = { .name = symbol_name, };
247 247
248 if (kallsyms__parse(&args, find_symbol_cb) <= 0) 248 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
249 return -ENOENT; 249 return -ENOENT;
250 250
251 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 251 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b31e0ae4b8db..1b65fed0dd2d 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -237,11 +237,13 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
237 char *filename = malloc(size), 237 char *filename = malloc(size),
238 *linkname = malloc(size), *targetname, *sbuild_id; 238 *linkname = malloc(size), *targetname, *sbuild_id;
239 int len, err = -1; 239 int len, err = -1;
240 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
240 241
241 if (filename == NULL || linkname == NULL) 242 if (filename == NULL || linkname == NULL)
242 goto out_free; 243 goto out_free;
243 244
244 len = snprintf(filename, size, "%s%s", debugdir, self->long_name); 245 len = snprintf(filename, size, "%s%s%s",
246 debugdir, is_kallsyms ? "/" : "", self->long_name);
245 if (mkdir_p(filename, 0755)) 247 if (mkdir_p(filename, 0755))
246 goto out_free; 248 goto out_free;
247 249
@@ -249,9 +251,14 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
249 sbuild_id = filename + len; 251 sbuild_id = filename + len;
250 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 252 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
251 253
252 if (access(filename, F_OK) && link(self->long_name, filename) && 254 if (access(filename, F_OK)) {
253 copyfile(self->long_name, filename)) 255 if (is_kallsyms) {
254 goto out_free; 256 if (copyfile("/proc/kallsyms", filename))
257 goto out_free;
258 } else if (link(self->long_name, filename) &&
259 copyfile(self->long_name, filename))
260 goto out_free;
261 }
255 262
256 len = snprintf(linkname, size, "%s/.build-id/%.2s", 263 len = snprintf(linkname, size, "%s/.build-id/%.2s",
257 debugdir, sbuild_id); 264 debugdir, sbuild_id);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 71d23e1e30e8..ae61e9f4d6eb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -383,13 +383,14 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
383 return ret; 383 return ret;
384} 384}
385 385
386int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, 386int kallsyms__parse(const char *filename, void *arg,
387 int (*process_symbol)(void *arg, const char *name,
387 char type, u64 start)) 388 char type, u64 start))
388{ 389{
389 char *line = NULL; 390 char *line = NULL;
390 size_t n; 391 size_t n;
391 int err = 0; 392 int err = 0;
392 FILE *file = fopen("/proc/kallsyms", "r"); 393 FILE *file = fopen(filename, "r");
393 394
394 if (file == NULL) 395 if (file == NULL)
395 goto out_failure; 396 goto out_failure;
@@ -466,10 +467,11 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
466 * so that we can in the next step set the symbol ->end address and then 467 * so that we can in the next step set the symbol ->end address and then
467 * call kernel_maps__split_kallsyms. 468 * call kernel_maps__split_kallsyms.
468 */ 469 */
469static int dso__load_all_kallsyms(struct dso *self, struct map *map) 470static int dso__load_all_kallsyms(struct dso *self, const char *filename,
471 struct map *map)
470{ 472{
471 struct process_kallsyms_args args = { .map = map, .dso = self, }; 473 struct process_kallsyms_args args = { .map = map, .dso = self, };
472 return kallsyms__parse(&args, map__process_kallsym_symbol); 474 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
473} 475}
474 476
475/* 477/*
@@ -556,10 +558,10 @@ discard_symbol: rb_erase(&pos->rb_node, root);
556} 558}
557 559
558 560
559static int dso__load_kallsyms(struct dso *self, struct map *map, 561static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
560 struct perf_session *session, symbol_filter_t filter) 562 struct perf_session *session, symbol_filter_t filter)
561{ 563{
562 if (dso__load_all_kallsyms(self, map) < 0) 564 if (dso__load_all_kallsyms(self, filename, map) < 0)
563 return -1; 565 return -1;
564 566
565 symbols__fixup_end(&self->symbols[map->type]); 567 symbols__fixup_end(&self->symbols[map->type]);
@@ -1580,7 +1582,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1580 struct perf_session *session, symbol_filter_t filter) 1582 struct perf_session *session, symbol_filter_t filter)
1581{ 1583{
1582 int err; 1584 int err;
1583 bool is_kallsyms; 1585 const char *kallsyms_filename = NULL;
1586 char *kallsyms_allocated_filename = NULL;
1584 1587
1585 if (vmlinux_path != NULL) { 1588 if (vmlinux_path != NULL) {
1586 int i; 1589 int i;
@@ -1606,19 +1609,37 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1606 */ 1609 */
1607 if (self->has_build_id) { 1610 if (self->has_build_id) {
1608 u8 kallsyms_build_id[BUILD_ID_SIZE]; 1611 u8 kallsyms_build_id[BUILD_ID_SIZE];
1612 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1609 1613
1610 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 1614 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1611 sizeof(kallsyms_build_id)) == 0) { 1615 sizeof(kallsyms_build_id)) == 0) {
1612 is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); 1616 if (dso__build_id_equal(self, kallsyms_build_id)) {
1613 if (is_kallsyms) 1617 kallsyms_filename = "/proc/kallsyms";
1614 goto do_kallsyms; 1618 goto do_kallsyms;
1619 }
1615 } 1620 }
1621
1622 build_id__sprintf(self->build_id, sizeof(self->build_id),
1623 sbuild_id);
1624
1625 if (asprintf(&kallsyms_allocated_filename,
1626 "%s/.debug/[kernel.kallsyms]/%s",
1627 getenv("HOME"), sbuild_id) != -1) {
1628 if (access(kallsyms_filename, F_OK)) {
1629 kallsyms_filename = kallsyms_allocated_filename;
1630 goto do_kallsyms;
1631 }
1632 free(kallsyms_allocated_filename);
1633 kallsyms_allocated_filename = NULL;
1634 }
1635
1616 goto do_vmlinux; 1636 goto do_vmlinux;
1617 } 1637 }
1618 1638
1619 is_kallsyms = self->long_name[0] == '['; 1639 if (self->long_name[0] == '[') {
1620 if (is_kallsyms) 1640 kallsyms_filename = "/proc/kallsyms";
1621 goto do_kallsyms; 1641 goto do_kallsyms;
1642 }
1622 1643
1623do_vmlinux: 1644do_vmlinux:
1624 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1645 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
@@ -1629,9 +1650,10 @@ do_vmlinux:
1629 pr_info("The file %s cannot be used, " 1650 pr_info("The file %s cannot be used, "
1630 "trying to use /proc/kallsyms...", self->long_name); 1651 "trying to use /proc/kallsyms...", self->long_name);
1631do_kallsyms: 1652do_kallsyms:
1632 err = dso__load_kallsyms(self, map, session, filter); 1653 err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter);
1633 if (err > 0 && !is_kallsyms) 1654 if (err > 0 && kallsyms_filename == NULL)
1634 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1655 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1656 free(kallsyms_allocated_filename);
1635 } 1657 }
1636 1658
1637 if (err > 0) { 1659 if (err > 0) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 594156e43b10..36b7c717f5ee 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -144,8 +144,9 @@ int filename__read_build_id(const char *filename, void *bf, size_t size);
144int sysfs__read_build_id(const char *filename, void *bf, size_t size); 144int sysfs__read_build_id(const char *filename, void *bf, size_t size);
145bool dsos__read_build_ids(void); 145bool dsos__read_build_ids(void);
146int build_id__sprintf(u8 *self, int len, char *bf); 146int build_id__sprintf(u8 *self, int len, char *bf);
147int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, 147int kallsyms__parse(const char *filename, void *arg,
148 char type, u64 start)); 148 int (*process_symbol)(void *arg, const char *name,
149 char type, u64 start));
149 150
150int symbol__init(void); 151int symbol__init(void);
151bool symbol_type__is_a(char symbol_type, enum map_type map_type); 152bool symbol_type__is_a(char symbol_type, enum map_type map_type);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index f3c0798a5e78..f0685849b244 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -32,6 +32,33 @@ int mkdir_p(char *path, mode_t mode)
32 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; 32 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
33} 33}
34 34
35static int slow_copyfile(const char *from, const char *to)
36{
37 int err = 0;
38 char *line = NULL;
39 size_t n;
40 FILE *from_fp = fopen(from, "r"), *to_fp;
41
42 if (from_fp == NULL)
43 goto out;
44
45 to_fp = fopen(to, "w");
46 if (to_fp == NULL)
47 goto out_fclose_from;
48
49 while (getline(&line, &n, from_fp) > 0)
50 if (fputs(line, to_fp) == EOF)
51 goto out_fclose_to;
52 err = 0;
53out_fclose_to:
54 fclose(to_fp);
55 free(line);
56out_fclose_from:
57 fclose(from_fp);
58out:
59 return err;
60}
61
35int copyfile(const char *from, const char *to) 62int copyfile(const char *from, const char *to)
36{ 63{
37 int fromfd, tofd; 64 int fromfd, tofd;
@@ -42,6 +69,9 @@ int copyfile(const char *from, const char *to)
42 if (stat(from, &st)) 69 if (stat(from, &st))
43 goto out; 70 goto out;
44 71
72 if (st.st_size == 0) /* /proc? do it slowly... */
73 return slow_copyfile(from, to);
74
45 fromfd = open(from, O_RDONLY); 75 fromfd = open(from, O_RDONLY);
46 if (fromfd < 0) 76 if (fromfd < 0)
47 goto out; 77 goto out;