diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-01-14 15:30:06 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-01-16 04:58:47 -0500 |
commit | 9e201442de7c954f03710ac76f28c1927d07550c (patch) | |
tree | 7682ebe87ca85468e0ecd28b277013e9359605c0 /tools/perf | |
parent | 8d0591f6ad9edf66697ce29de176fb6f3213b9e3 (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')
-rw-r--r-- | tools/perf/util/event.c | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 15 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 48 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 5 | ||||
-rw-r--r-- | tools/perf/util/util.c | 30 |
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 | ||
386 | int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, | 386 | int 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 | */ |
469 | static int dso__load_all_kallsyms(struct dso *self, struct map *map) | 470 | static 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 | ||
559 | static int dso__load_kallsyms(struct dso *self, struct map *map, | 561 | static 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 | ||
1623 | do_vmlinux: | 1644 | do_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); |
1631 | do_kallsyms: | 1652 | do_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); | |||
144 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 144 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
145 | bool dsos__read_build_ids(void); | 145 | bool dsos__read_build_ids(void); |
146 | int build_id__sprintf(u8 *self, int len, char *bf); | 146 | int build_id__sprintf(u8 *self, int len, char *bf); |
147 | int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, | 147 | int 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 | ||
150 | int symbol__init(void); | 151 | int symbol__init(void); |
151 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 152 | bool 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 | ||
35 | static 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; | ||
53 | out_fclose_to: | ||
54 | fclose(to_fp); | ||
55 | free(line); | ||
56 | out_fclose_from: | ||
57 | fclose(from_fp); | ||
58 | out: | ||
59 | return err; | ||
60 | } | ||
61 | |||
35 | int copyfile(const char *from, const char *to) | 62 | int 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; |