From: David Ahern <daahern@cisco.com>
To: linux-perf-users@vger.kernel.org
Cc: David Ahern <daahern@cisco.com>
Subject: [PATCH] perf tools: Add rootfs option for off-box analysis using specified tree
Date: Sun, 21 Nov 2010 09:19:16 -0700 [thread overview]
Message-ID: <1290356356-10008-1-git-send-email-daahern@cisco.com> (raw)
The rootfs argument allows analysis of perf.data file using a locally
accessible filesystem tree with debug symbols - e.g., loop mounted
KVM disk images, NFS, USB keys, initrds, etc. Anything with an OS tree
can be analyzed from anywhere without the need to populate a local
data store with build-ids.
Signed-off-by: David Ahern <daahern@cisco.com>
---
tools/perf/builtin-annotate.c | 16 +++++--
tools/perf/builtin-diff.c | 2 +
tools/perf/builtin-report.c | 2 +
tools/perf/builtin-timechart.c | 2 +
tools/perf/util/hist.c | 14 +++++-
tools/perf/util/symbol.c | 82 +++++++++++++++++++++++++---------------
tools/perf/util/symbol.h | 1 +
7 files changed, 80 insertions(+), 39 deletions(-)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 6d5604d8d..0ad6876 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -280,7 +280,8 @@ static int hist_entry__tty_annotate(struct hist_entry *he)
struct map *map = he->ms.map;
struct dso *dso = map->dso;
struct symbol *sym = he->ms.sym;
- const char *filename = dso->long_name, *d_filename;
+ const char *filename = dso->long_name;
+ char d_filename[PATH_MAX];
u64 len;
LIST_HEAD(head);
struct objdump_line *pos, *n;
@@ -288,10 +289,13 @@ static int hist_entry__tty_annotate(struct hist_entry *he)
if (hist_entry__annotate(he, &head, 0) < 0)
return -1;
- if (full_paths)
- d_filename = filename;
- else
- d_filename = basename(filename);
+ if (full_paths) {
+ snprintf(d_filename, sizeof(d_filename), "%s%s",
+ symbol_conf.rootfs, filename);
+ } else {
+ snprintf(d_filename, sizeof(d_filename), "%s/%s",
+ symbol_conf.rootfs, basename(filename));
+ }
len = sym->end - sym->start;
@@ -437,6 +441,8 @@ static const struct option options[] = {
"print matching source lines (may be slow)"),
OPT_BOOLEAN('P', "full-paths", &full_paths,
"Don't shorten the displayed pathnames"),
+ OPT_STRING(0, "rootfs", &symbol_conf.rootfs, "directory",
+ "Look for symbol files relative to this root directory."),
OPT_END()
};
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index fca1d44..92754fa 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -191,6 +191,8 @@ static const struct option options[] = {
OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
"separator for columns, no spaces will be added between "
"columns '.' is reserved."),
+ OPT_STRING(0, "rootfs", &symbol_conf.rootfs, "directory",
+ "Look for symbol files relative to this root directory."),
OPT_END()
};
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5de405d..dd07dda 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -478,6 +478,8 @@ static const struct option options[] = {
"columns '.' is reserved."),
OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
"Only display entries resolved to a symbol"),
+ OPT_STRING(0, "rootfs", &symbol_conf.rootfs, "directory",
+ "Look for symbol files relative to this root directory."),
OPT_END()
};
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 9bcc38f..9745cd0 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1018,6 +1018,8 @@ static const struct option options[] = {
OPT_CALLBACK('p', "process", NULL, "process",
"process selector. Pass a pid or process name.",
parse_process),
+ OPT_STRING(0, "rootfs", &symbol_conf.rootfs, "directory",
+ "Look for symbol files relative to this root directory."),
OPT_END()
};
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2022e87..f4de675 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1092,6 +1092,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
FILE *file;
int err = 0;
u64 len;
+ char rootfs_filename[PATH_MAX];
+
+ if (filename) {
+ snprintf(rootfs_filename, sizeof(rootfs_filename), "%s%s",
+ symbol_conf.rootfs, filename);
+ }
if (filename == NULL) {
if (dso->has_build_id) {
@@ -1100,9 +1106,9 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
return -ENOMEM;
}
goto fallback;
- } else if (readlink(filename, command, sizeof(command)) < 0 ||
+ } else if (readlink(rootfs_filename, command, sizeof(command)) < 0 ||
strstr(command, "[kernel.kallsyms]") ||
- access(filename, R_OK)) {
+ access(rootfs_filename, R_OK)) {
free(filename);
fallback:
/*
@@ -1111,6 +1117,8 @@ fallback:
* DSO is the same as when 'perf record' ran.
*/
filename = dso->long_name;
+ snprintf(rootfs_filename, sizeof(rootfs_filename), "%s%s",
+ symbol_conf.rootfs, filename);
free_filename = false;
}
@@ -1137,7 +1145,7 @@ fallback:
"objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
- filename, filename);
+ rootfs_filename, filename);
pr_debug("Executing: %s\n", command);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 861be8b..6fdbcaa 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -41,6 +41,7 @@ struct symbol_conf symbol_conf = {
.exclude_other = true,
.use_modules = true,
.try_vmlinux_path = true,
+ .rootfs = "",
};
int dso__name_len(const struct dso *self)
@@ -831,8 +832,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
char sympltname[1024];
Elf *elf;
int nr = 0, symidx, fd, err = 0;
+ char name[PATH_MAX];
- fd = open(self->long_name, O_RDONLY);
+ snprintf(name, sizeof(name), "%s%s",
+ symbol_conf.rootfs, self->long_name);
+ fd = open(name, O_RDONLY);
if (fd < 0)
goto out;
@@ -1444,16 +1448,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
self->origin++) {
switch (self->origin) {
case DSO__ORIG_BUILD_ID_CACHE:
- if (dso__build_id_filename(self, name, size) == NULL)
+ /* skip the locally configured cache if a rootfs is given */
+ if ((strlen(symbol_conf.rootfs) != 0) ||
+ (dso__build_id_filename(self, name, size) == NULL)) {
continue;
+ }
break;
case DSO__ORIG_FEDORA:
- snprintf(name, size, "/usr/lib/debug%s.debug",
- self->long_name);
+ snprintf(name, size, "%s/usr/lib/debug%s.debug",
+ symbol_conf.rootfs, self->long_name);
break;
case DSO__ORIG_UBUNTU:
- snprintf(name, size, "/usr/lib/debug%s",
- self->long_name);
+ snprintf(name, size, "%s/usr/lib/debug%s",
+ symbol_conf.rootfs, self->long_name);
break;
case DSO__ORIG_BUILDID: {
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -1465,12 +1472,13 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
sizeof(self->build_id),
build_id_hex);
snprintf(name, size,
- "/usr/lib/debug/.build-id/%.2s/%s.debug",
- build_id_hex, build_id_hex + 2);
+ "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
+ symbol_conf.rootfs, build_id_hex, build_id_hex + 2);
}
break;
case DSO__ORIG_DSO:
- snprintf(name, size, "%s", self->long_name);
+ snprintf(name, size, "%s%s",
+ symbol_conf.rootfs, self->long_name);
break;
case DSO__ORIG_GUEST_KMODULE:
if (!map->groups || !map->groups->machine)
@@ -1776,17 +1784,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
const char *vmlinux, symbol_filter_t filter)
{
int err = -1, fd;
+ char rootfs_vmlinux[PATH_MAX];
- fd = open(vmlinux, O_RDONLY);
+ snprintf(rootfs_vmlinux, sizeof(rootfs_vmlinux), "%s/%s",
+ symbol_conf.rootfs, vmlinux);
+ fd = open(rootfs_vmlinux, O_RDONLY);
if (fd < 0)
return -1;
dso__set_loaded(self, map->type);
- err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
+ err = dso__load_sym(self, map, rootfs_vmlinux, fd, filter, 0, 0);
close(fd);
if (err > 0)
- pr_debug("Using %s for symbols\n", vmlinux);
+ pr_debug("Using %s for symbols\n", rootfs_vmlinux);
return err;
}
@@ -1859,6 +1870,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
goto out_fixup;
}
+ /* do not try local files if a rootfs was given */
+ if (strlen(symbol_conf.rootfs) != 0)
+ return -1;
+
/*
* Say the kernel DSO was created when processing the build-id header table,
* we have a build-id, so check if it is the same as the running kernel,
@@ -2208,9 +2223,6 @@ static int vmlinux_path__init(void)
struct utsname uts;
char bf[PATH_MAX];
- if (uname(&uts) < 0)
- return -1;
-
vmlinux_path = malloc(sizeof(char *) * 5);
if (vmlinux_path == NULL)
return -1;
@@ -2223,22 +2235,30 @@ static int vmlinux_path__init(void)
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
goto out_fail;
++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
- uts.release);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
+
+ /* if no rootfs has been given try running kernel version too */
+ if (strlen(symbol_conf.rootfs) == 0) {
+ if (uname(&uts) < 0)
+ return -1;
+
+ snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
+ vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+ if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+ goto out_fail;
+ ++vmlinux_path__nr_entries;
+ snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux",
+ uts.release);
+ vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+ if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+ goto out_fail;
+ ++vmlinux_path__nr_entries;
+ snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
+ uts.release);
+ vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+ if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+ goto out_fail;
+ ++vmlinux_path__nr_entries;
+ }
return 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 038f220..a97b6d3 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -85,6 +85,7 @@ struct symbol_conf {
struct strlist *dso_list,
*comm_list,
*sym_list;
+ const char *rootfs;
};
extern struct symbol_conf symbol_conf;
--
1.7.2.3
next reply other threads:[~2010-11-21 16:19 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-21 16:19 David Ahern [this message]
[not found] <1290356275-9969-1-git-send-email-y>
2010-11-21 16:34 ` [PATCH] perf tools: Add rootfs option for off-box analysis using specified tree Arnaldo Carvalho de Melo
2010-11-21 17:02 ` David S. Ahern
2010-11-21 18:12 ` Arnaldo Carvalho de Melo
-- strict thread matches above, loose matches on Subject: below --
2010-11-21 16:17 y
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1290356356-10008-1-git-send-email-daahern@cisco.com \
--to=daahern@cisco.com \
--cc=linux-perf-users@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).