Commit ef12a141 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by Ingo Molnar

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: default avatarArnaldo 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: default avatarIngo Molnar <mingo@elte.hu>
parent dc8d6ab2
perf-buildid-cache(1)
=====================
NAME
----
perf-buildid-cache - Manage build-id cache.
SYNOPSIS
--------
[verse]
'perf buildid-list <options>'
DESCRIPTION
-----------
This command manages the build-id cache. It can add and remove files to the
cache. In the future it should as well purge older entries, set upper limits
for the space used by the cache, etc.
OPTIONS
-------
-a::
--add=::
Add specified file to the cache.
-r::
--remove=::
Remove specified file to the cache.
-v::
--verbose::
Be more verbose.
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-report[1]
...@@ -445,6 +445,7 @@ BUILTIN_OBJS += builtin-diff.o ...@@ -445,6 +445,7 @@ BUILTIN_OBJS += builtin-diff.o
BUILTIN_OBJS += builtin-help.o BUILTIN_OBJS += builtin-help.o
BUILTIN_OBJS += builtin-sched.o BUILTIN_OBJS += builtin-sched.o
BUILTIN_OBJS += builtin-buildid-list.o BUILTIN_OBJS += builtin-buildid-list.o
BUILTIN_OBJS += builtin-buildid-cache.o
BUILTIN_OBJS += builtin-list.o BUILTIN_OBJS += builtin-list.o
BUILTIN_OBJS += builtin-record.o BUILTIN_OBJS += builtin-record.o
BUILTIN_OBJS += builtin-report.o BUILTIN_OBJS += builtin-report.o
......
/*
* builtin-buildid-cache.c
*
* Builtin buildid-cache command: Manages build-id cache
*
* Copyright (C) 2010, Red Hat Inc.
* Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include "builtin.h"
#include "perf.h"
#include "util/cache.h"
#include "util/debug.h"
#include "util/header.h"
#include "util/parse-options.h"
#include "util/strlist.h"
#include "util/symbol.h"
static char const *add_name_list_str, *remove_name_list_str;
static const char * const buildid_cache_usage[] = {
"perf buildid-cache [<options>]",
NULL
};
static const struct option buildid_cache_options[] = {
OPT_STRING('a', "add", &add_name_list_str,
"file list", "file(s) to add"),
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
"file(s) to remove"),
OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"),
OPT_END()
};
static int build_id_cache__add_file(const char *filename, const char *debugdir)
{
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
u8 build_id[BUILD_ID_SIZE];
int err;
if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
pr_debug("Couldn't read a build-id in %s\n", filename);
return -1;
}
build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
if (verbose)
pr_info("Adding %s %s: %s\n", sbuild_id, filename,
err ? "FAIL" : "Ok");
return err;
}
static int build_id_cache__remove_file(const char *filename __used,
const char *debugdir __used)
{
u8 build_id[BUILD_ID_SIZE];
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
int err;
if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
pr_debug("Couldn't read a build-id in %s\n", filename);
return -1;
}
build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
err = build_id_cache__remove_s(sbuild_id, debugdir);
if (verbose)
pr_info("Removing %s %s: %s\n", sbuild_id, filename,
err ? "FAIL" : "Ok");
return err;
}
static int __cmd_buildid_cache(void)
{
struct strlist *list;
struct str_node *pos;
char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
DEBUG_CACHE_DIR);
if (add_name_list_str) {
list = strlist__new(true, add_name_list_str);
if (list) {
strlist__for_each(pos, list)
if (build_id_cache__add_file(pos->s, debugdir)) {
if (errno == EEXIST) {
pr_debug("%s already in the cache\n",
pos->s);
continue;
}
pr_warning("Couldn't add %s: %s\n",
pos->s, strerror(errno));
}
strlist__delete(list);
}
}
if (remove_name_list_str) {
list = strlist__new(true, remove_name_list_str);
if (list) {
strlist__for_each(pos, list)
if (build_id_cache__remove_file(pos->s, debugdir)) {
if (errno == ENOENT) {
pr_debug("%s wasn't in the cache\n",
pos->s);
continue;
}
pr_warning("Couldn't remove %s: %s\n",
pos->s, strerror(errno));
}
strlist__delete(list);
}
}
return 0;
}
int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
{
argc = parse_options(argc, argv, buildid_cache_options,
buildid_cache_usage, 0);
if (symbol__init() < 0)
return -1;
setup_pager();
return __cmd_buildid_cache();
}
...@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd); ...@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd);
extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_bench(int argc, const char **argv, const char *prefix); extern int cmd_bench(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix); extern int cmd_diff(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix); extern int cmd_help(int argc, const char **argv, const char *prefix);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
perf-annotate mainporcelain common perf-annotate mainporcelain common
perf-archive mainporcelain common perf-archive mainporcelain common
perf-bench mainporcelain common perf-bench mainporcelain common
perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common perf-buildid-list mainporcelain common
perf-diff mainporcelain common perf-diff mainporcelain common
perf-list mainporcelain common perf-list mainporcelain common
......
...@@ -285,6 +285,7 @@ static void handle_internal_command(int argc, const char **argv) ...@@ -285,6 +285,7 @@ static void handle_internal_command(int argc, const char **argv)
{ {
const char *cmd = argv[0]; const char *cmd = argv[0];
static struct cmd_struct commands[] = { static struct cmd_struct commands[] = {
{ "buildid-cache", cmd_buildid_cache, 0 },
{ "buildid-list", cmd_buildid_list, 0 }, { "buildid-list", cmd_buildid_list, 0 },
{ "diff", cmd_diff, 0 }, { "diff", cmd_diff, 0 },
{ "help", cmd_help, 0 }, { "help", cmd_help, 0 },
......
...@@ -231,32 +231,29 @@ static int dsos__write_buildid_table(int fd) ...@@ -231,32 +231,29 @@ static int dsos__write_buildid_table(int fd)
return err; return err;
} }
static int dso__cache_build_id(struct dso *self, const char *debugdir) int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
const char *name, bool is_kallsyms)
{ {
const size_t size = PATH_MAX; const size_t size = PATH_MAX;
char *filename = malloc(size), char *filename = malloc(size),
*linkname = malloc(size), *targetname, *sbuild_id; *linkname = malloc(size), *targetname;
int len, err = -1; int len, err = -1;
bool is_kallsyms = self->kernel && self->long_name[0] != '/';
if (filename == NULL || linkname == NULL) if (filename == NULL || linkname == NULL)
goto out_free; goto out_free;
len = snprintf(filename, size, "%s%s%s", len = snprintf(filename, size, "%s%s%s",
debugdir, is_kallsyms ? "/" : "", self->long_name); debugdir, is_kallsyms ? "/" : "", name);
if (mkdir_p(filename, 0755)) if (mkdir_p(filename, 0755))
goto out_free; goto out_free;
len += snprintf(filename + len, sizeof(filename) - len, "/"); snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
sbuild_id = filename + len;
build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
if (access(filename, F_OK)) { if (access(filename, F_OK)) {
if (is_kallsyms) { if (is_kallsyms) {
if (copyfile("/proc/kallsyms", filename)) if (copyfile("/proc/kallsyms", filename))
goto out_free; goto out_free;
} else if (link(self->long_name, filename) && } else if (link(name, filename) && copyfile(name, filename))
copyfile(self->long_name, filename))
goto out_free; goto out_free;
} }
...@@ -278,6 +275,63 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir) ...@@ -278,6 +275,63 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
return err; return err;
} }
static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
const char *name, const char *debugdir,
bool is_kallsyms)
{
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
build_id__sprintf(build_id, build_id_size, sbuild_id);
return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
}
int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
{
const size_t size = PATH_MAX;
char *filename = malloc(size),
*linkname = malloc(size);
int err = -1;
if (filename == NULL || linkname == NULL)
goto out_free;
snprintf(linkname, size, "%s/.build-id/%.2s/%s",
debugdir, sbuild_id, sbuild_id + 2);
if (access(linkname, F_OK))
goto out_free;
if (readlink(linkname, filename, size) < 0)
goto out_free;
if (unlink(linkname))
goto out_free;
/*
* Since the link is relative, we must make it absolute:
*/
snprintf(linkname, size, "%s/.build-id/%.2s/%s",
debugdir, sbuild_id, filename);
if (unlink(linkname))
goto out_free;
err = 0;
out_free:
free(filename);
free(linkname);
return err;
}
static int dso__cache_build_id(struct dso *self, const char *debugdir)
{
bool is_kallsyms = self->kernel && self->long_name[0] != '/';
return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
self->long_name, debugdir, is_kallsyms);
}
static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
{ {
struct dso *pos; struct dso *pos;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdbool.h> #include <stdbool.h>
#include "types.h" #include "types.h"
#include "event.h"
#include <linux/bitmap.h> #include <linux/bitmap.h>
...@@ -84,4 +85,8 @@ int perf_header__process_sections(struct perf_header *self, int fd, ...@@ -84,4 +85,8 @@ int perf_header__process_sections(struct perf_header *self, int fd,
struct perf_header *ph, struct perf_header *ph,
int feat, int fd)); int feat, int fd));
int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
const char *name, bool is_kallsyms);
int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
#endif /* __PERF_HEADER_H */ #endif /* __PERF_HEADER_H */
...@@ -345,10 +345,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type) ...@@ -345,10 +345,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
&self->symbols[type]); &self->symbols[type]);
} }
int build_id__sprintf(u8 *self, int len, char *bf) int build_id__sprintf(const u8 *self, int len, char *bf)
{ {
char *bid = bf; char *bid = bf;
u8 *raw = self; const u8 *raw = self;
int i; int i;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
......
...@@ -144,7 +144,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, ...@@ -144,7 +144,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
int filename__read_build_id(const char *filename, void *bf, size_t size); int filename__read_build_id(const char *filename, void *bf, size_t size);
int sysfs__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size);
bool dsos__read_build_ids(void); bool dsos__read_build_ids(void);
int build_id__sprintf(u8 *self, int len, char *bf); int build_id__sprintf(const u8 *self, int len, char *bf);
int kallsyms__parse(const char *filename, void *arg, int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name, int (*process_symbol)(void *arg, const char *name,
char type, u64 start)); char type, u64 start));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment