2010-12-09 20:27:12

by David Ahern

[permalink] [raw]
Subject: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

The symfs argument allows analysis of perf.data file using a locally
accessible filesystem tree with debug symbols - e.g., tree created
during image builds, sshfs mount, loop mounted KVM disk images,
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 <[email protected]>

v2 --> v3: handle symfs="/"

v1 --> v2: removed symfs changes from builtin-annotate.c
fixed tab/space inconsistencies
changed new strlen() to symbol_conf.symfs[0]
added symfs option to Documentation files

---
tools/perf/Documentation/perf-diff.txt | 2 +
tools/perf/Documentation/perf-report.txt | 3 +
tools/perf/Documentation/perf-timechart.txt | 2 +
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 | 57 ++++++++++++++++++++-------
tools/perf/util/symbol.h | 1 +
9 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 6a9ec2b..74d7481 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -66,6 +66,8 @@ OPTIONS
--force::
Don't complain, do it.

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.

SEE ALSO
--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 59a1f57..9ed6079 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -113,6 +113,9 @@ OPTIONS
--force::
Don't complain, do it.

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.
+
SEE ALSO
--------
linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 4b17883..d7b79e2 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -38,6 +38,8 @@ OPTIONS
--process::
Select the processes to display, by name or PID

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.

SEE ALSO
--------
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 5e1a043..71126a6 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -192,6 +192,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 904519f..57b0f49 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -479,6 +479,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index d2fc461..965aa4e 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1021,6 +1021,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2022e87..b6f9f3b 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 symfs_filename[PATH_MAX];
+
+ if (filename) {
+ snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+ symbol_conf.symfs, 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(symfs_filename, command, sizeof(command)) < 0 ||
strstr(command, "[kernel.kallsyms]") ||
- access(filename, R_OK)) {
+ access(symfs_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(symfs_filename, sizeof(symfs_filename), "%s%s",
+ symbol_conf.symfs, 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);
+ symfs_filename, filename);

pr_debug("Executing: %s\n", command);

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index a348906..f61b419 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,
+ .symfs = "",
};

int dso__name_len(const struct dso *self)
@@ -833,8 +834,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.symfs, self->long_name);
+ fd = open(name, O_RDONLY);
if (fd < 0)
goto out;

@@ -1446,16 +1450,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 symfs is given */
+ if (symbol_conf.symfs[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.symfs, 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.symfs, self->long_name);
break;
case DSO__ORIG_BUILDID: {
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -1467,12 +1474,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.symfs, 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.symfs, self->long_name);
break;
case DSO__ORIG_GUEST_KMODULE:
if (map->groups && map->groups->machine)
@@ -1778,17 +1786,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
const char *vmlinux, symbol_filter_t filter)
{
int err = -1, fd;
+ char symfs_vmlinux[PATH_MAX];

- fd = open(vmlinux, O_RDONLY);
+ snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
+ symbol_conf.symfs, vmlinux);
+ fd = open(symfs_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, symfs_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", symfs_vmlinux);

return err;
}
@@ -1861,6 +1872,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
goto out_fixup;
}

+ /* do not try local files if a symfs was given */
+ if (symbol_conf.symfs[0] != 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,
@@ -2210,9 +2225,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;
@@ -2225,6 +2237,14 @@ static int vmlinux_path__init(void)
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
goto out_fail;
++vmlinux_path__nr_entries;
+
+ /* only try running kernel version if no symfs was given */
+ if (symbol_conf.symfs[0] != 0)
+ return 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)
@@ -2312,6 +2332,13 @@ int symbol__init(void)
symbol_conf.sym_list_str, "symbol") < 0)
goto out_free_comm_list;

+ /* a path to symbols of "/" is identical to ""
+ * reset here for simplicity.
+ */
+ if ((symbol_conf.symfs[0] == '/') &&
+ (symbol_conf.symfs[1] == '\0'))
+ symbol_conf.symfs = "";
+
symbol_conf.initialized = true;
return 0;

diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 038f220..bbe90d1 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 *symfs;
};

extern struct symbol_conf symbol_conf;
--
1.7.2.3


2010-12-14 12:24:36

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

Em Thu, Dec 09, 2010 at 01:27:07PM -0700, David Ahern escreveu:
> The symfs argument allows analysis of perf.data file using a locally
> accessible filesystem tree with debug symbols - e.g., tree created
> during image builds, sshfs mount, loop mounted KVM disk images,
> 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 <[email protected]>
>
> v2 --> v3: handle symfs="/"

> @@ -2312,6 +2332,13 @@ int symbol__init(void)
> symbol_conf.sym_list_str, "symbol") < 0)
> goto out_free_comm_list;
>
> + /* a path to symbols of "/" is identical to ""
> + * reset here for simplicity.
> + */
> + if ((symbol_conf.symfs[0] == '/') &&
> + (symbol_conf.symfs[1] == '\0'))
> + symbol_conf.symfs = "";
> +
> symbol_conf.initialized = true;
> return 0;
>

Call me a nitpicker:

[acme@felicio ~]$ cat realpath.c
#include <limits.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
char *resolved = realpath(argv[1], NULL);

puts(resolved);
}
[acme@felicio ~]$ make realpath
cc realpath.c -o realpath
[acme@felicio ~]$ ./realpath //
/
[acme@felicio ~]$ ./realpath ////////////////
/
[acme@felicio ~]$ ./realpath /./././
/
[acme@felicio ~]$ ./realpath /..//.
/
[acme@felicio ~]$

I'll fix this up and merge, thanks!

- Arnaldo

2010-12-14 12:52:52

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

Em Tue, Dec 14, 2010 at 10:24:28AM -0200, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Dec 09, 2010 at 01:27:07PM -0700, David Ahern escreveu:
> > The symfs argument allows analysis of perf.data file using a locally
> > accessible filesystem tree with debug symbols - e.g., tree created
> > during image builds, sshfs mount, loop mounted KVM disk images,
> > 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 <[email protected]>
> >
> > v2 --> v3: handle symfs="/"
>
> [acme@felicio ~]$ ./realpath /..//.
> /
> [acme@felicio ~]$
>
> I'll fix this up and merge, thanks!

Ok, there are still some problems:

It is escaping the symfs jail for /home/acme/bin/perf, /lib64/libpthread-2.5.so
and kernel modules, investigating...

- Arnaldo

[acme@mica linux]$ find /tmp/bla
/tmp/bla
/tmp/bla/lib64
/tmp/bla/lib64/libc-2.5.so
[acme@mica linux]$ perf report -v -g none --stdio --symfs /tmp/bla > /tmp/out
Looking at the vmlinux_path (3 entries long)
Failed to open [kernel.kallsyms], continuing without symbols
dso__synthesize_plt_symbols: problems reading /home/acme/bin/perf PLT info.
dso__synthesize_plt_symbols: problems reading /lib64/libpthread-2.5.so PLT info.
dso__synthesize_plt_symbols: problems reading /lib/modules/2.6.37-rc3-00084-gd937616/kernel/drivers/net/ixgbe/ixgbe.ko PLT info.
[acme@mica linux]$ cat /tmp/out
# Events: 503 cycles
#
# Overhead Command Shared Object Symbol
# ........ ........... ........................................................................ .............................
#
86.67% perf [kernel.kallsyms] 0xffffffff8106f697 ! [k] 0xffffffff8106f697
2.56% swapper [kernel.kallsyms] 0xffffffff81089f50 ! [k] 0xffffffff81089f50
0.84% perf /lib64/libc-2.5.so 0x798ed d [.] __memchr
0.84% perf /home/acme/bin/perf 0x26bf1 G [.] die_builtin
0.82% perf /lib64/libc-2.5.so 0x728ea d [.] _int_malloc
0.63% perf /lib64/libc-2.5.so 0xe6077 d [.] ___snprintf_chk
0.63% perf /lib64/libc-2.5.so 0x7b528 d [.] __GI_memcpy
0.63% perf /lib64/libc-2.5.so 0x786c0 d [.] index
0.51% perf /lib64/libc-2.5.so 0x625b0 d [.] _IO_getline_internal
0.42% perf /lib64/libc-2.5.so 0x6265a d [.] _IO_getline_info
0.42% perf /lib64/libc-2.5.so 0x6cbc4 d [.] _IO_new_file_underflow
0.42% perf /lib64/libc-2.5.so 0x6d148 d [.] _IO_un_link_internal
0.34% perf /lib64/libc-2.5.so 0x60c49 d [.] _IO_new_fclose
0.21% perf /lib64/libc-2.5.so 0x5ff40 d [.] __find_specmb
0.21% perf /lib64/libc-2.5.so 0x6c35b d [.] _IO_new_file_fopen
0.21% perf /home/acme/bin/perf 0x1db4b G [.] event__synthesize_kernel_mmap
0.21% perf /lib64/libc-2.5.so 0x6d3c5 d [.] _IO_link_in_internal
0.21% perf /lib64/libc-2.5.so 0x34524 d [.] __GI_____strtoll_l_internal
0.21% perf /home/acme/bin/perf 0x4700 G [.] _init
0.21% perf /lib64/libc-2.5.so 0x41907 d [.] _itoa_word
0.21% perf /lib64/libc-2.5.so 0x6148f d [.] fgets
0.21% perf /home/acme/bin/perf 0x1deca G [.] event__synthesize_comm
0.21% perf /lib64/libc-2.5.so 0xcfe7d d [.] __munmap
0.21% perf /lib64/libc-2.5.so 0x79513 d [.] __GI_strstr
0.21% perf /lib64/libc-2.5.so 0x6e060 d [.] _IO_setb_internal
0.21% perf /lib64/libc-2.5.so 0x6bac3 d [.] _IO_file_close_internal
0.21% perf /lib64/libc-2.5.so 0x95dc3 d [.] __getdents64
0.21% perf /lib64/libc-2.5.so 0x6f1b2 d [.] _IO_str_init_static_internal
0.21% perf /lib64/libpthread-2.5.so 0xd210 G [.] __write_nocancel
0.21% perf /lib64/libc-2.5.so 0x9595a d [.] __readdir_r
0.21% perf /home/acme/bin/perf 0xddbd G [.] atexit_header
0.21% perf /lib64/libc-2.5.so 0xc4de7 d [.] __GI___open
0.12% pcscd [unknown] 0x3f44a79110 ! [.] 0x3f44a79110
0.09% pcscd [kernel.kallsyms] 0xffffffff810e59ac ! [k] 0xffffffff810e59ac
0.03% sshd [kernel.kallsyms] 0xffffffff810f45f9 ! [k] 0xffffffff810f45f9
0.03% kworker/0:1 /lib/modules/2.6.37-rc3-00084-gd937616/kernel/drivers/net/ixgbe/ixgbe.ko 0x605 G [k] ixgbe_update_stats
0.02% sshd [unknown] 0x7f78ed5f8ccb ! [.] 0x7f78ed5f8ccb


#
# (For a higher level overview, try: perf report --sort comm,dso)
#
[acme@mica linux]$

2010-12-14 14:06:12

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

Em Tue, Dec 14, 2010 at 10:52:45AM -0200, Arnaldo Carvalho de Melo escreveu:
> Ok, there are still some problems:
>
> It is escaping the symfs jail for /home/acme/bin/perf, /lib64/libpthread-2.5.so
> and kernel modules, investigating...

Those 'G' signals means DSO__ORIG_GUEST_KMODULE, since you were not
prefixing that case with symfs, it was the jail leak point, fixed, doing
some more testing before merging.

> [acme@mica linux]$ find /tmp/bla
> /tmp/bla
> /tmp/bla/lib64
> /tmp/bla/lib64/libc-2.5.so
> [acme@mica linux]$ perf report -v -g none --stdio --symfs /tmp/bla
> Failed to open [kernel.kallsyms], continuing without symbols
> # Events: 503 cycles
> #
> # Overhead Command Shared Object Symbol
> # ........ .......... ..................................... ....................
> #
> 0.84% perf /home/acme/bin/perf 0x26bf1 G [.] die_builtin
> 0.21% perf /home/acme/bin/perf 0x1db4b G [.] event__synthesize_kernel_mmap
> 0.21% perf /home/acme/bin/perf 0x4700 G [.] _init
> 0.21% perf /home/acme/bin/perf 0x1deca G [.] event__synthesize_comm
> 0.21% perf /lib64/libpthread-2.5.so 0xd210 G [.] __write_nocancel
> 0.21% perf /home/acme/bin/perf 0xddbd G [.] atexit_header
> 0.03% kworker/0:1 /lib/modules/2.6.37-rc3/.../ixgbe.ko 0x605 G [k] ixgbe_update_stats

2010-12-14 14:27:43

by David Ahern

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree



On 12/14/10 05:52, Arnaldo Carvalho de Melo wrote:
> Em Tue, Dec 14, 2010 at 10:24:28AM -0200, Arnaldo Carvalho de Melo escreveu:
>> Em Thu, Dec 09, 2010 at 01:27:07PM -0700, David Ahern escreveu:
>>> The symfs argument allows analysis of perf.data file using a locally
>>> accessible filesystem tree with debug symbols - e.g., tree created
>>> during image builds, sshfs mount, loop mounted KVM disk images,
>>> 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 <[email protected]>
>>>
>>> v2 --> v3: handle symfs="/"
>>
>> [acme@felicio ~]$ ./realpath /..//.
>> /
>> [acme@felicio ~]$
>>
>> I'll fix this up and merge, thanks!

I was not aware of realpath. Simple change to symbol__init?

>
> Ok, there are still some problems:
>
> It is escaping the symfs jail for /home/acme/bin/perf, /lib64/libpthread-2.5.so
> and kernel modules, investigating...

>
> - Arnaldo
>
> [acme@mica linux]$ find /tmp/bla
> /tmp/bla
> /tmp/bla/lib64
> /tmp/bla/lib64/libc-2.5.so
> [acme@mica linux]$ perf report -v -g none --stdio --symfs /tmp/bla > /tmp/out
> Looking at the vmlinux_path (3 entries long)
> Failed to open [kernel.kallsyms], continuing without symbols
> dso__synthesize_plt_symbols: problems reading /home/acme/bin/perf PLT info.
> dso__synthesize_plt_symbols: problems reading /lib64/libpthread-2.5.so PLT info.
> dso__synthesize_plt_symbols: problems reading /lib/modules/2.6.37-rc3-00084-gd937616/kernel/drivers/net/ixgbe/ixgbe.ko PLT info.
> [acme@mica linux]$ cat /tmp/out

strace -e trace=open /tmp/build-perf/perf report -v --symfs /tmp/f14-mnt
-i /tmp/perf-cs.data

does not show any attempts to open a file not starting with the symfs path.

At the top of dso__synthesize_plt_symbols() is:
snprintf(name, sizeof(name), "%s%s",
symbol_conf.symfs, self->long_name);
fd = open(name, O_RDONLY);

so the open only gets the relative path.

David

2010-12-14 14:33:29

by David Ahern

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree



On 12/14/10 07:06, Arnaldo Carvalho de Melo wrote:
> Em Tue, Dec 14, 2010 at 10:52:45AM -0200, Arnaldo Carvalho de Melo escreveu:
>> Ok, there are still some problems:
>>
>> It is escaping the symfs jail for /home/acme/bin/perf, /lib64/libpthread-2.5.so
>> and kernel modules, investigating...
>
> Those 'G' signals means DSO__ORIG_GUEST_KMODULE, since you were not
> prefixing that case with symfs, it was the jail leak point, fixed, doing
> some more testing before merging.

yuk. I did not touch the hypervisor paths.

So the 'guest' route is tried all the time because of the origin list --
even when it's not applicable.

David

>
>> [acme@mica linux]$ find /tmp/bla
>> /tmp/bla
>> /tmp/bla/lib64
>> /tmp/bla/lib64/libc-2.5.so
>> [acme@mica linux]$ perf report -v -g none --stdio --symfs /tmp/bla
>> Failed to open [kernel.kallsyms], continuing without symbols
>> # Events: 503 cycles
>> #
>> # Overhead Command Shared Object Symbol
>> # ........ .......... ..................................... ....................
>> #
>> 0.84% perf /home/acme/bin/perf 0x26bf1 G [.] die_builtin
>> 0.21% perf /home/acme/bin/perf 0x1db4b G [.] event__synthesize_kernel_mmap
>> 0.21% perf /home/acme/bin/perf 0x4700 G [.] _init
>> 0.21% perf /home/acme/bin/perf 0x1deca G [.] event__synthesize_comm
>> 0.21% perf /lib64/libpthread-2.5.so 0xd210 G [.] __write_nocancel
>> 0.21% perf /home/acme/bin/perf 0xddbd G [.] atexit_header
>> 0.03% kworker/0:1 /lib/modules/2.6.37-rc3/.../ixgbe.ko 0x605 G [k] ixgbe_update_stats

2010-12-14 14:35:58

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

Em Tue, Dec 14, 2010 at 07:27:42AM -0700, David S. Ahern escreveu:
> On 12/14/10 05:52, Arnaldo Carvalho de Melo wrote:
> > Em Tue, Dec 14, 2010 at 10:24:28AM -0200, Arnaldo Carvalho de Melo escreveu:
> I was not aware of realpath. Simple change to symbol__init?

I made symbol__init use realpath to reduce the arg to --symfs.

> > [acme@mica linux]$ find /tmp/bla
> > /tmp/bla
> > /tmp/bla/lib64
> > /tmp/bla/lib64/libc-2.5.so
> > [acme@mica linux]$ perf report -v -g none --stdio --symfs /tmp/bla > /tmp/out
> > Looking at the vmlinux_path (3 entries long)
> > Failed to open [kernel.kallsyms], continuing without symbols
> > dso__synthesize_plt_symbols: problems reading /home/acme/bin/perf PLT info.
> > [acme@mica linux]$ cat /tmp/out

> strace -e trace=open /tmp/build-perf/perf report -v --symfs /tmp/f14-mnt
> -i /tmp/perf-cs.data

> does not show any attempts to open a file not starting with the symfs path.

Probably because all the files you need are in the directories you
passed to --symfs, remove one and it will leak.

Anyway, fixed in my perf/core branch, still not propagated from
master.k.o to git.k.o :-\

- Arnaldo

2010-12-14 14:39:36

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v3] perf tools: Add symfs option for off-box analysis using specified tree

Em Tue, Dec 14, 2010 at 07:33:27AM -0700, David S. Ahern escreveu:
> On 12/14/10 07:06, Arnaldo Carvalho de Melo wrote:
> > Em Tue, Dec 14, 2010 at 10:52:45AM -0200, Arnaldo Carvalho de Melo escreveu:
> >> Ok, there are still some problems:

> >> It is escaping the symfs jail for /home/acme/bin/perf, /lib64/libpthread-2.5.so
> >> and kernel modules, investigating...

> > Those 'G' signals means DSO__ORIG_GUEST_KMODULE, since you were not
> > prefixing that case with symfs, it was the jail leak point, fixed, doing
> > some more testing before merging.

> yuk. I did not touch the hypervisor paths.

> So the 'guest' route is tried all the time because of the origin list --
> even when it's not applicable.

Right, I don't like the way kvm is supported, will revisit this at some
point.

If build-ids were first class citizens, all this would be moot :-\

- Arnaldo

2010-12-22 11:30:08

by David Ahern

[permalink] [raw]
Subject: [tip:perf/core] perf symbols: Add symfs option for off-box analysis using specified tree

Commit-ID: ec5761eab318e50e69fcf8e63e9edaef5949c067
Gitweb: http://git.kernel.org/tip/ec5761eab318e50e69fcf8e63e9edaef5949c067
Author: David Ahern <[email protected]>
AuthorDate: Thu, 9 Dec 2010 13:27:07 -0700
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Dec 2010 20:17:51 -0200

perf symbols: Add symfs option for off-box analysis using specified tree

The symfs argument allows analysis of perf.data file using a locally accessible
filesystem tree with debug symbols - e.g., tree created during image builds,
sshfs mount, loop mounted KVM disk images, 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.

Commiter notes:

o Fixed up symfs="/" variants handling.

o prefixed DSO__ORIG_GUEST_KMODULE case with symfs too, avoiding use of files
outside the symfs directory.

LKML-Reference: <[email protected]>
Signed-off-by: David Ahern <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Documentation/perf-diff.txt | 2 +
tools/perf/Documentation/perf-report.txt | 3 +
tools/perf/Documentation/perf-timechart.txt | 2 +
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 | 72 +++++++++++++++++++++------
tools/perf/util/symbol.h | 1 +
9 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 6a9ec2b..74d7481 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -66,6 +66,8 @@ OPTIONS
--force::
Don't complain, do it.

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.

SEE ALSO
--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index fefea77..8ba03d6 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -116,6 +116,9 @@ OPTIONS
--force::
Don't complain, do it.

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.
+
SEE ALSO
--------
linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 4b17883..d7b79e2 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -38,6 +38,8 @@ OPTIONS
--process::
Select the processes to display, by name or PID

+--symfs=<directory>::
+ Look for files with symbols relative to this directory.

SEE ALSO
--------
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 97846dc..3153e49 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -194,6 +194,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4af7ce6..75183a4 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -483,6 +483,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 459b5e3..d75084b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1022,6 +1022,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, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index a3b8416..d503670 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 symfs_filename[PATH_MAX];
+
+ if (filename) {
+ snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+ symbol_conf.symfs, 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(symfs_filename, command, sizeof(command)) < 0 ||
strstr(command, "[kernel.kallsyms]") ||
- access(filename, R_OK)) {
+ access(symfs_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(symfs_filename, sizeof(symfs_filename), "%s%s",
+ symbol_conf.symfs, 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);
+ symfs_filename, filename);

pr_debug("Executing: %s\n", command);

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ceefa65..561db63 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,
+ .symfs = "",
};

int dso__name_len(const struct dso *self)
@@ -839,8 +840,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.symfs, self->long_name);
+ fd = open(name, O_RDONLY);
if (fd < 0)
goto out;

@@ -1452,16 +1456,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 symfs is given */
+ if (symbol_conf.symfs[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.symfs, 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.symfs, self->long_name);
break;
case DSO__ORIG_BUILDID: {
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -1473,19 +1480,26 @@ 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.symfs, 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.symfs, self->long_name);
break;
case DSO__ORIG_GUEST_KMODULE:
if (map->groups && map->groups->machine)
root_dir = map->groups->machine->root_dir;
else
root_dir = "";
- snprintf(name, size, "%s%s", root_dir, self->long_name);
+ snprintf(name, size, "%s%s%s", symbol_conf.symfs,
+ root_dir, self->long_name);
+ break;
+
+ case DSO__ORIG_KMODULE:
+ snprintf(name, size, "%s%s", symbol_conf.symfs,
+ self->long_name);
break;

default:
@@ -1784,17 +1798,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
const char *vmlinux, symbol_filter_t filter)
{
int err = -1, fd;
+ char symfs_vmlinux[PATH_MAX];

- fd = open(vmlinux, O_RDONLY);
+ snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
+ symbol_conf.symfs, vmlinux);
+ fd = open(symfs_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, symfs_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", symfs_vmlinux);

return err;
}
@@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
goto out_fixup;
}

+ /* do not try local files if a symfs was given */
+ if (symbol_conf.symfs[0] != 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,
@@ -2262,9 +2283,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;
@@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void)
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
goto out_fail;
++vmlinux_path__nr_entries;
+
+ /* only try running kernel version if no symfs was given */
+ if (symbol_conf.symfs[0] != 0)
+ return 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)
@@ -2336,6 +2362,8 @@ static int setup_list(struct strlist **list, const char *list_str,

int symbol__init(void)
{
+ const char *symfs;
+
if (symbol_conf.initialized)
return 0;

@@ -2364,6 +2392,18 @@ int symbol__init(void)
symbol_conf.sym_list_str, "symbol") < 0)
goto out_free_comm_list;

+ /*
+ * A path to symbols of "/" is identical to ""
+ * reset here for simplicity.
+ */
+ symfs = realpath(symbol_conf.symfs, NULL);
+ if (symfs == NULL)
+ symfs = symbol_conf.symfs;
+ if (strcmp(symfs, "/") == 0)
+ symbol_conf.symfs = "";
+ if (symfs != symbol_conf.symfs)
+ free((void *)symfs);
+
symbol_conf.initialized = true;
return 0;

diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 12defbe..bcd2f98 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -86,6 +86,7 @@ struct symbol_conf {
struct strlist *dso_list,
*comm_list,
*sym_list;
+ const char *symfs;
};

extern struct symbol_conf symbol_conf;