diff options
-rw-r--r-- | tools/perf/Documentation/perf-buildid-cache.txt | 33 | ||||
-rw-r--r-- | tools/perf/Makefile | 1 | ||||
-rw-r--r-- | tools/perf/builtin-buildid-cache.c | 133 | ||||
-rw-r--r-- | tools/perf/builtin.h | 1 | ||||
-rw-r--r-- | tools/perf/command-list.txt | 1 | ||||
-rw-r--r-- | tools/perf/perf.c | 1 | ||||
-rw-r--r-- | tools/perf/util/header.c | 72 | ||||
-rw-r--r-- | tools/perf/util/header.h | 5 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 4 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 |
10 files changed, 241 insertions, 12 deletions
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt new file mode 100644 index 000000000000..88bc3b519746 --- /dev/null +++ b/tools/perf/Documentation/perf-buildid-cache.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | perf-buildid-cache(1) | ||
2 | ===================== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-buildid-cache - Manage build-id cache. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | 'perf buildid-list <options>' | ||
12 | |||
13 | DESCRIPTION | ||
14 | ----------- | ||
15 | This command manages the build-id cache. It can add and remove files to the | ||
16 | cache. In the future it should as well purge older entries, set upper limits | ||
17 | for the space used by the cache, etc. | ||
18 | |||
19 | OPTIONS | ||
20 | ------- | ||
21 | -a:: | ||
22 | --add=:: | ||
23 | Add specified file to the cache. | ||
24 | -r:: | ||
25 | --remove=:: | ||
26 | Remove specified file to the cache. | ||
27 | -v:: | ||
28 | --verbose:: | ||
29 | Be more verbose. | ||
30 | |||
31 | SEE ALSO | ||
32 | -------- | ||
33 | linkperf:perf-record[1], linkperf:perf-report[1] | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ddbeeee9ade2..9b173e66fb41 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -445,6 +445,7 @@ BUILTIN_OBJS += builtin-diff.o | |||
445 | BUILTIN_OBJS += builtin-help.o | 445 | BUILTIN_OBJS += builtin-help.o |
446 | BUILTIN_OBJS += builtin-sched.o | 446 | BUILTIN_OBJS += builtin-sched.o |
447 | BUILTIN_OBJS += builtin-buildid-list.o | 447 | BUILTIN_OBJS += builtin-buildid-list.o |
448 | BUILTIN_OBJS += builtin-buildid-cache.o | ||
448 | BUILTIN_OBJS += builtin-list.o | 449 | BUILTIN_OBJS += builtin-list.o |
449 | BUILTIN_OBJS += builtin-record.o | 450 | BUILTIN_OBJS += builtin-record.o |
450 | BUILTIN_OBJS += builtin-report.o | 451 | BUILTIN_OBJS += builtin-report.o |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c new file mode 100644 index 000000000000..30a05f552c96 --- /dev/null +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * builtin-buildid-cache.c | ||
3 | * | ||
4 | * Builtin buildid-cache command: Manages build-id cache | ||
5 | * | ||
6 | * Copyright (C) 2010, Red Hat Inc. | ||
7 | * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
8 | */ | ||
9 | #include "builtin.h" | ||
10 | #include "perf.h" | ||
11 | #include "util/cache.h" | ||
12 | #include "util/debug.h" | ||
13 | #include "util/header.h" | ||
14 | #include "util/parse-options.h" | ||
15 | #include "util/strlist.h" | ||
16 | #include "util/symbol.h" | ||
17 | |||
18 | static char const *add_name_list_str, *remove_name_list_str; | ||
19 | |||
20 | static const char * const buildid_cache_usage[] = { | ||
21 | "perf buildid-cache [<options>]", | ||
22 | NULL | ||
23 | }; | ||
24 | |||
25 | static const struct option buildid_cache_options[] = { | ||
26 | OPT_STRING('a', "add", &add_name_list_str, | ||
27 | "file list", "file(s) to add"), | ||
28 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | ||
29 | "file(s) to remove"), | ||
30 | OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"), | ||
31 | OPT_END() | ||
32 | }; | ||
33 | |||
34 | static int build_id_cache__add_file(const char *filename, const char *debugdir) | ||
35 | { | ||
36 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
37 | u8 build_id[BUILD_ID_SIZE]; | ||
38 | int err; | ||
39 | |||
40 | if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { | ||
41 | pr_debug("Couldn't read a build-id in %s\n", filename); | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | build_id__sprintf(build_id, sizeof(build_id), sbuild_id); | ||
46 | err = build_id_cache__add_s(sbuild_id, debugdir, filename, false); | ||
47 | if (verbose) | ||
48 | pr_info("Adding %s %s: %s\n", sbuild_id, filename, | ||
49 | err ? "FAIL" : "Ok"); | ||
50 | return err; | ||
51 | } | ||
52 | |||
53 | static int build_id_cache__remove_file(const char *filename __used, | ||
54 | const char *debugdir __used) | ||
55 | { | ||
56 | u8 build_id[BUILD_ID_SIZE]; | ||
57 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
58 | |||
59 | int err; | ||
60 | |||
61 | if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { | ||
62 | pr_debug("Couldn't read a build-id in %s\n", filename); | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | build_id__sprintf(build_id, sizeof(build_id), sbuild_id); | ||
67 | err = build_id_cache__remove_s(sbuild_id, debugdir); | ||
68 | if (verbose) | ||
69 | pr_info("Removing %s %s: %s\n", sbuild_id, filename, | ||
70 | err ? "FAIL" : "Ok"); | ||
71 | |||
72 | return err; | ||
73 | } | ||
74 | |||
75 | static int __cmd_buildid_cache(void) | ||
76 | { | ||
77 | struct strlist *list; | ||
78 | struct str_node *pos; | ||
79 | char debugdir[PATH_MAX]; | ||
80 | |||
81 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | ||
82 | DEBUG_CACHE_DIR); | ||
83 | |||
84 | if (add_name_list_str) { | ||
85 | list = strlist__new(true, add_name_list_str); | ||
86 | if (list) { | ||
87 | strlist__for_each(pos, list) | ||
88 | if (build_id_cache__add_file(pos->s, debugdir)) { | ||
89 | if (errno == EEXIST) { | ||
90 | pr_debug("%s already in the cache\n", | ||
91 | pos->s); | ||
92 | continue; | ||
93 | } | ||
94 | pr_warning("Couldn't add %s: %s\n", | ||
95 | pos->s, strerror(errno)); | ||
96 | } | ||
97 | |||
98 | strlist__delete(list); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (remove_name_list_str) { | ||
103 | list = strlist__new(true, remove_name_list_str); | ||
104 | if (list) { | ||
105 | strlist__for_each(pos, list) | ||
106 | if (build_id_cache__remove_file(pos->s, debugdir)) { | ||
107 | if (errno == ENOENT) { | ||
108 | pr_debug("%s wasn't in the cache\n", | ||
109 | pos->s); | ||
110 | continue; | ||
111 | } | ||
112 | pr_warning("Couldn't remove %s: %s\n", | ||
113 | pos->s, strerror(errno)); | ||
114 | } | ||
115 | |||
116 | strlist__delete(list); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used) | ||
124 | { | ||
125 | argc = parse_options(argc, argv, buildid_cache_options, | ||
126 | buildid_cache_usage, 0); | ||
127 | |||
128 | if (symbol__init() < 0) | ||
129 | return -1; | ||
130 | |||
131 | setup_pager(); | ||
132 | return __cmd_buildid_cache(); | ||
133 | } | ||
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 18035b1f16c7..dee97cfe3794 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd); | |||
16 | 16 | ||
17 | extern int cmd_annotate(int argc, const char **argv, const char *prefix); | 17 | extern int cmd_annotate(int argc, const char **argv, const char *prefix); |
18 | extern int cmd_bench(int argc, const char **argv, const char *prefix); | 18 | extern int cmd_bench(int argc, const char **argv, const char *prefix); |
19 | extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); | ||
19 | extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); | 20 | extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); |
20 | extern int cmd_diff(int argc, const char **argv, const char *prefix); | 21 | extern int cmd_diff(int argc, const char **argv, const char *prefix); |
21 | extern int cmd_help(int argc, const char **argv, const char *prefix); | 22 | extern int cmd_help(int argc, const char **argv, const char *prefix); |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index cf6444dfd73a..9afcff2e3ae5 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
@@ -5,6 +5,7 @@ | |||
5 | perf-annotate mainporcelain common | 5 | perf-annotate mainporcelain common |
6 | perf-archive mainporcelain common | 6 | perf-archive mainporcelain common |
7 | perf-bench mainporcelain common | 7 | perf-bench mainporcelain common |
8 | perf-buildid-cache mainporcelain common | ||
8 | perf-buildid-list mainporcelain common | 9 | perf-buildid-list mainporcelain common |
9 | perf-diff mainporcelain common | 10 | perf-diff mainporcelain common |
10 | perf-list mainporcelain common | 11 | perf-list mainporcelain common |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fc89005c3e51..05c861c045d5 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -285,6 +285,7 @@ static void handle_internal_command(int argc, const char **argv) | |||
285 | { | 285 | { |
286 | const char *cmd = argv[0]; | 286 | const char *cmd = argv[0]; |
287 | static struct cmd_struct commands[] = { | 287 | static struct cmd_struct commands[] = { |
288 | { "buildid-cache", cmd_buildid_cache, 0 }, | ||
288 | { "buildid-list", cmd_buildid_list, 0 }, | 289 | { "buildid-list", cmd_buildid_list, 0 }, |
289 | { "diff", cmd_diff, 0 }, | 290 | { "diff", cmd_diff, 0 }, |
290 | { "help", cmd_help, 0 }, | 291 | { "help", cmd_help, 0 }, |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1b65fed0dd2d..2bb2bdb1f456 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -231,32 +231,29 @@ static int dsos__write_buildid_table(int fd) | |||
231 | return err; | 231 | return err; |
232 | } | 232 | } |
233 | 233 | ||
234 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | 234 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, |
235 | const char *name, bool is_kallsyms) | ||
235 | { | 236 | { |
236 | const size_t size = PATH_MAX; | 237 | const size_t size = PATH_MAX; |
237 | char *filename = malloc(size), | 238 | char *filename = malloc(size), |
238 | *linkname = malloc(size), *targetname, *sbuild_id; | 239 | *linkname = malloc(size), *targetname; |
239 | int len, err = -1; | 240 | int len, err = -1; |
240 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | ||
241 | 241 | ||
242 | if (filename == NULL || linkname == NULL) | 242 | if (filename == NULL || linkname == NULL) |
243 | goto out_free; | 243 | goto out_free; |
244 | 244 | ||
245 | len = snprintf(filename, size, "%s%s%s", | 245 | len = snprintf(filename, size, "%s%s%s", |
246 | debugdir, is_kallsyms ? "/" : "", self->long_name); | 246 | debugdir, is_kallsyms ? "/" : "", name); |
247 | if (mkdir_p(filename, 0755)) | 247 | if (mkdir_p(filename, 0755)) |
248 | goto out_free; | 248 | goto out_free; |
249 | 249 | ||
250 | len += snprintf(filename + len, sizeof(filename) - len, "/"); | 250 | snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); |
251 | sbuild_id = filename + len; | ||
252 | build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); | ||
253 | 251 | ||
254 | if (access(filename, F_OK)) { | 252 | if (access(filename, F_OK)) { |
255 | if (is_kallsyms) { | 253 | if (is_kallsyms) { |
256 | if (copyfile("/proc/kallsyms", filename)) | 254 | if (copyfile("/proc/kallsyms", filename)) |
257 | goto out_free; | 255 | goto out_free; |
258 | } else if (link(self->long_name, filename) && | 256 | } else if (link(name, filename) && copyfile(name, filename)) |
259 | copyfile(self->long_name, filename)) | ||
260 | goto out_free; | 257 | goto out_free; |
261 | } | 258 | } |
262 | 259 | ||
@@ -278,6 +275,63 @@ out_free: | |||
278 | return err; | 275 | return err; |
279 | } | 276 | } |
280 | 277 | ||
278 | static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | ||
279 | const char *name, const char *debugdir, | ||
280 | bool is_kallsyms) | ||
281 | { | ||
282 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
283 | |||
284 | build_id__sprintf(build_id, build_id_size, sbuild_id); | ||
285 | |||
286 | return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); | ||
287 | } | ||
288 | |||
289 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | ||
290 | { | ||
291 | const size_t size = PATH_MAX; | ||
292 | char *filename = malloc(size), | ||
293 | *linkname = malloc(size); | ||
294 | int err = -1; | ||
295 | |||
296 | if (filename == NULL || linkname == NULL) | ||
297 | goto out_free; | ||
298 | |||
299 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
300 | debugdir, sbuild_id, sbuild_id + 2); | ||
301 | |||
302 | if (access(linkname, F_OK)) | ||
303 | goto out_free; | ||
304 | |||
305 | if (readlink(linkname, filename, size) < 0) | ||
306 | goto out_free; | ||
307 | |||
308 | if (unlink(linkname)) | ||
309 | goto out_free; | ||
310 | |||
311 | /* | ||
312 | * Since the link is relative, we must make it absolute: | ||
313 | */ | ||
314 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
315 | debugdir, sbuild_id, filename); | ||
316 | |||
317 | if (unlink(linkname)) | ||
318 | goto out_free; | ||
319 | |||
320 | err = 0; | ||
321 | out_free: | ||
322 | free(filename); | ||
323 | free(linkname); | ||
324 | return err; | ||
325 | } | ||
326 | |||
327 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | ||
328 | { | ||
329 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | ||
330 | |||
331 | return build_id_cache__add_b(self->build_id, sizeof(self->build_id), | ||
332 | self->long_name, debugdir, is_kallsyms); | ||
333 | } | ||
334 | |||
281 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 335 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) |
282 | { | 336 | { |
283 | struct dso *pos; | 337 | struct dso *pos; |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index ccc8540feccd..82a6af72d4cc 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include "types.h" | 7 | #include "types.h" |
8 | #include "event.h" | ||
8 | 9 | ||
9 | #include <linux/bitmap.h> | 10 | #include <linux/bitmap.h> |
10 | 11 | ||
@@ -84,4 +85,8 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
84 | struct perf_header *ph, | 85 | struct perf_header *ph, |
85 | int feat, int fd)); | 86 | int feat, int fd)); |
86 | 87 | ||
88 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | ||
89 | const char *name, bool is_kallsyms); | ||
90 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); | ||
91 | |||
87 | #endif /* __PERF_HEADER_H */ | 92 | #endif /* __PERF_HEADER_H */ |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b6ab23dd5f9f..6f30fe18c265 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -345,10 +345,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type) | |||
345 | &self->symbols[type]); | 345 | &self->symbols[type]); |
346 | } | 346 | } |
347 | 347 | ||
348 | int build_id__sprintf(u8 *self, int len, char *bf) | 348 | int build_id__sprintf(const u8 *self, int len, char *bf) |
349 | { | 349 | { |
350 | char *bid = bf; | 350 | char *bid = bf; |
351 | u8 *raw = self; | 351 | const u8 *raw = self; |
352 | int i; | 352 | int i; |
353 | 353 | ||
354 | for (i = 0; i < len; ++i) { | 354 | for (i = 0; i < len; ++i) { |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 525085fd0735..ffe0b0f2e5d3 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -144,7 +144,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | |||
144 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 144 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
145 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 145 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
146 | bool dsos__read_build_ids(void); | 146 | bool dsos__read_build_ids(void); |
147 | int build_id__sprintf(u8 *self, int len, char *bf); | 147 | int build_id__sprintf(const u8 *self, int len, char *bf); |
148 | int kallsyms__parse(const char *filename, void *arg, | 148 | int kallsyms__parse(const char *filename, void *arg, |
149 | int (*process_symbol)(void *arg, const char *name, | 149 | int (*process_symbol)(void *arg, const char *name, |
150 | char type, u64 start)); | 150 | char type, u64 start)); |