aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-01-20 12:28:45 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-21 02:31:29 -0500
commitef12a141306c90336a3a10d40213ecd98624d274 (patch)
tree6c6d06c1c7bb5b769cc46c8da05f561aa2443b91 /tools
parentdc8d6ab2b61a2d92b5d7438565ccd20b29724cb2 (diff)
perf buildid-cache: Add new command to manage build-id cache
For now it just has operations to examine a given file, find its build-id and add or remove it to/from the cache. Useful, for instance, when adding binaries sent together with a perf.data file, so that we can add them to the cache and have the tools find it when resolving symbols. It'll also manage the size of the cache like 'ccache' does. 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: <1264008525-29025-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-buildid-cache.c133
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/util/header.c72
-rw-r--r--tools/perf/util/header.h5
-rw-r--r--tools/perf/util/symbol.c4
-rw-r--r--tools/perf/util/symbol.h2
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 @@
1perf-buildid-cache(1)
2=====================
3
4NAME
5----
6perf-buildid-cache - Manage build-id cache.
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command manages the build-id cache. It can add and remove files to the
16cache. In the future it should as well purge older entries, set upper limits
17for the space used by the cache, etc.
18
19OPTIONS
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
31SEE ALSO
32--------
33linkperf: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
445BUILTIN_OBJS += builtin-help.o 445BUILTIN_OBJS += builtin-help.o
446BUILTIN_OBJS += builtin-sched.o 446BUILTIN_OBJS += builtin-sched.o
447BUILTIN_OBJS += builtin-buildid-list.o 447BUILTIN_OBJS += builtin-buildid-list.o
448BUILTIN_OBJS += builtin-buildid-cache.o
448BUILTIN_OBJS += builtin-list.o 449BUILTIN_OBJS += builtin-list.o
449BUILTIN_OBJS += builtin-record.o 450BUILTIN_OBJS += builtin-record.o
450BUILTIN_OBJS += builtin-report.o 451BUILTIN_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
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static 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
34static 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
53static 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
75static 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
123int 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
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern 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 @@
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-archive mainporcelain common 6perf-archive mainporcelain common
7perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
8perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
9perf-diff mainporcelain common 10perf-diff mainporcelain common
10perf-list mainporcelain common 11perf-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
234static int dso__cache_build_id(struct dso *self, const char *debugdir) 234int 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
278static 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
289int 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;
321out_free:
322 free(filename);
323 free(linkname);
324 return err;
325}
326
327static 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
281static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 335static 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
88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int 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
348int build_id__sprintf(u8 *self, int len, char *bf) 348int 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,
144int filename__read_build_id(const char *filename, void *bf, size_t size); 144int filename__read_build_id(const char *filename, void *bf, size_t size);
145int sysfs__read_build_id(const char *filename, void *bf, size_t size); 145int sysfs__read_build_id(const char *filename, void *bf, size_t size);
146bool dsos__read_build_ids(void); 146bool dsos__read_build_ids(void);
147int build_id__sprintf(u8 *self, int len, char *bf); 147int build_id__sprintf(const u8 *self, int len, char *bf);
148int kallsyms__parse(const char *filename, void *arg, 148int 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));