2010-01-14 20:30:19

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/3] perf tools: Convert getpagesize() uses to sysconf(_SC_GETPAGESIZE)

From: Arnaldo Carvalho de Melo <[email protected]>

Using the more portable and equivalent sysconf call.

Reported-by: Aristeu Rozanski <[email protected]>
Reported-by: Ulrich Drepper <[email protected]>
Cc: Aristeu Rozanski <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Ulrich Drepper <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/session.c | 2 +-
tools/perf/util/trace-event-info.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 604e14f..1951e33 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -384,7 +384,7 @@ int perf_session__process_events(struct perf_session *self,

perf_event_ops__fill_defaults(ops);

- page_size = getpagesize();
+ page_size = sysconf(_SC_PAGESIZE);

head = self->header.data_offset;

diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 407fd65..5ea8973 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -515,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
write_or_die(buf, 1);

/* save page_size */
- page_size = getpagesize();
+ page_size = sysconf(_SC_PAGESIZE);
write_or_die(&page_size, 4);

read_header_files();
--
1.6.2.5


2010-01-14 20:30:27

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/3] perf symbols: Don't try to load kallsyms if doesn't match the record build-id

From: Arnaldo Carvalho de Melo <[email protected]>

Now a perf.data file collected on a x86_64 fedora 12 machine gets properly
parsed on a Debian testing PARISC64 machine with 32-bit userland:

acme@parisc:~/git/linux-2.6-tip$ perf report 2> /dev/null | head -15
# Samples: 293085637
#
# Overhead Command Shared Object Symbol
# ........ ............... ................................. ......
#
35.11% find [kernel.kallsyms] [k] 0xffffffff81002b5a
18.25% perf [kernel.kallsyms] [k] 0xffffffff8102235f
9.07% find find [.] 0x0000000000fb0e
5.80% swapper [kernel.kallsyms] [k] 0xffffffff8102235f
3.29% perf libc-2.10.2.so [.] __GI_strcmp
2.70% find libc-2.10.2.so [.] __GI_memmove
2.33% init [kernel.kallsyms] [k] 0xffffffff810091b9
2.03% find libc-2.10.2.so [.] _int_malloc
1.67% find libc-2.10.2.so [.] _IO_vfprintf_internal
1.65% sshd libcrypto.so.0.9.8k [.] 0x00000000105440
acme@parisc:~/git/linux-2.6-tip$

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 381999d..71d23e1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1608,11 +1608,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
u8 kallsyms_build_id[BUILD_ID_SIZE];

if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
- sizeof(kallsyms_build_id)) == 0)
-
- is_kallsyms = dso__build_id_equal(self, kallsyms_build_id);
- if (is_kallsyms)
- goto do_kallsyms;
+ sizeof(kallsyms_build_id)) == 0) {
+ is_kallsyms = dso__build_id_equal(self, kallsyms_build_id);
+ if (is_kallsyms)
+ goto do_kallsyms;
+ }
goto do_vmlinux;
}

@@ -1623,6 +1623,9 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
do_vmlinux:
err = dso__load_vmlinux(self, map, session, self->long_name, filter);
if (err <= 0) {
+ if (self->has_build_id)
+ return -1;
+
pr_info("The file %s cannot be used, "
"trying to use /proc/kallsyms...", self->long_name);
do_kallsyms:
--
1.6.2.5

2010-01-14 20:30:43

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/3] perf symbols: Cache /proc/kallsyms files by build-id

From: Arnaldo Carvalho de Melo <[email protected]>

So that when we don't have a vmlinux handy we can store the kallsyms for
later use by 'perf report'.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/event.c | 2 +-
tools/perf/util/header.c | 15 ++++++++++---
tools/perf/util/symbol.c | 48 +++++++++++++++++++++++++++++++++------------
tools/perf/util/symbol.h | 5 ++-
tools/perf/util/util.c | 30 ++++++++++++++++++++++++++++
5 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 24ec5be..0e9820a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -245,7 +245,7 @@ int event__synthesize_kernel_mmap(event__handler_t process,
*/
struct process_symbol_args args = { .name = symbol_name, };

- if (kallsyms__parse(&args, find_symbol_cb) <= 0)
+ if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
return -ENOENT;

size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b31e0ae..1b65fed 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -237,11 +237,13 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
char *filename = malloc(size),
*linkname = malloc(size), *targetname, *sbuild_id;
int len, err = -1;
+ bool is_kallsyms = self->kernel && self->long_name[0] != '/';

if (filename == NULL || linkname == NULL)
goto out_free;

- len = snprintf(filename, size, "%s%s", debugdir, self->long_name);
+ len = snprintf(filename, size, "%s%s%s",
+ debugdir, is_kallsyms ? "/" : "", self->long_name);
if (mkdir_p(filename, 0755))
goto out_free;

@@ -249,9 +251,14 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
sbuild_id = filename + len;
build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);

- if (access(filename, F_OK) && link(self->long_name, filename) &&
- copyfile(self->long_name, filename))
- goto out_free;
+ if (access(filename, F_OK)) {
+ if (is_kallsyms) {
+ if (copyfile("/proc/kallsyms", filename))
+ goto out_free;
+ } else if (link(self->long_name, filename) &&
+ copyfile(self->long_name, filename))
+ goto out_free;
+ }

len = snprintf(linkname, size, "%s/.build-id/%.2s",
debugdir, sbuild_id);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 71d23e1..ae61e9f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -383,13 +383,14 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
return ret;
}

-int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name,
+int kallsyms__parse(const char *filename, void *arg,
+ int (*process_symbol)(void *arg, const char *name,
char type, u64 start))
{
char *line = NULL;
size_t n;
int err = 0;
- FILE *file = fopen("/proc/kallsyms", "r");
+ FILE *file = fopen(filename, "r");

if (file == NULL)
goto out_failure;
@@ -466,10 +467,11 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
* so that we can in the next step set the symbol ->end address and then
* call kernel_maps__split_kallsyms.
*/
-static int dso__load_all_kallsyms(struct dso *self, struct map *map)
+static int dso__load_all_kallsyms(struct dso *self, const char *filename,
+ struct map *map)
{
struct process_kallsyms_args args = { .map = map, .dso = self, };
- return kallsyms__parse(&args, map__process_kallsym_symbol);
+ return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
}

/*
@@ -556,10 +558,10 @@ discard_symbol: rb_erase(&pos->rb_node, root);
}


-static int dso__load_kallsyms(struct dso *self, struct map *map,
+static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
struct perf_session *session, symbol_filter_t filter)
{
- if (dso__load_all_kallsyms(self, map) < 0)
+ if (dso__load_all_kallsyms(self, filename, map) < 0)
return -1;

symbols__fixup_end(&self->symbols[map->type]);
@@ -1580,7 +1582,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
struct perf_session *session, symbol_filter_t filter)
{
int err;
- bool is_kallsyms;
+ const char *kallsyms_filename = NULL;
+ char *kallsyms_allocated_filename = NULL;

if (vmlinux_path != NULL) {
int i;
@@ -1606,19 +1609,37 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
*/
if (self->has_build_id) {
u8 kallsyms_build_id[BUILD_ID_SIZE];
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];

if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
sizeof(kallsyms_build_id)) == 0) {
- is_kallsyms = dso__build_id_equal(self, kallsyms_build_id);
- if (is_kallsyms)
+ if (dso__build_id_equal(self, kallsyms_build_id)) {
+ kallsyms_filename = "/proc/kallsyms";
goto do_kallsyms;
+ }
}
+
+ build_id__sprintf(self->build_id, sizeof(self->build_id),
+ sbuild_id);
+
+ if (asprintf(&kallsyms_allocated_filename,
+ "%s/.debug/[kernel.kallsyms]/%s",
+ getenv("HOME"), sbuild_id) != -1) {
+ if (access(kallsyms_filename, F_OK)) {
+ kallsyms_filename = kallsyms_allocated_filename;
+ goto do_kallsyms;
+ }
+ free(kallsyms_allocated_filename);
+ kallsyms_allocated_filename = NULL;
+ }
+
goto do_vmlinux;
}

- is_kallsyms = self->long_name[0] == '[';
- if (is_kallsyms)
+ if (self->long_name[0] == '[') {
+ kallsyms_filename = "/proc/kallsyms";
goto do_kallsyms;
+ }

do_vmlinux:
err = dso__load_vmlinux(self, map, session, self->long_name, filter);
@@ -1629,9 +1650,10 @@ do_vmlinux:
pr_info("The file %s cannot be used, "
"trying to use /proc/kallsyms...", self->long_name);
do_kallsyms:
- err = dso__load_kallsyms(self, map, session, filter);
- if (err > 0 && !is_kallsyms)
+ err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter);
+ if (err > 0 && kallsyms_filename == NULL)
dso__set_long_name(self, strdup("[kernel.kallsyms]"));
+ free(kallsyms_allocated_filename);
}

if (err > 0) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 594156e..36b7c71 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -144,8 +144,9 @@ 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);
bool dsos__read_build_ids(void);
int build_id__sprintf(u8 *self, int len, char *bf);
-int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name,
- char type, u64 start));
+int kallsyms__parse(const char *filename, void *arg,
+ int (*process_symbol)(void *arg, const char *name,
+ char type, u64 start));

int symbol__init(void);
bool symbol_type__is_a(char symbol_type, enum map_type map_type);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index f3c0798..f068584 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -32,6 +32,33 @@ int mkdir_p(char *path, mode_t mode)
return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
}

+static int slow_copyfile(const char *from, const char *to)
+{
+ int err = 0;
+ char *line = NULL;
+ size_t n;
+ FILE *from_fp = fopen(from, "r"), *to_fp;
+
+ if (from_fp == NULL)
+ goto out;
+
+ to_fp = fopen(to, "w");
+ if (to_fp == NULL)
+ goto out_fclose_from;
+
+ while (getline(&line, &n, from_fp) > 0)
+ if (fputs(line, to_fp) == EOF)
+ goto out_fclose_to;
+ err = 0;
+out_fclose_to:
+ fclose(to_fp);
+ free(line);
+out_fclose_from:
+ fclose(from_fp);
+out:
+ return err;
+}
+
int copyfile(const char *from, const char *to)
{
int fromfd, tofd;
@@ -42,6 +69,9 @@ int copyfile(const char *from, const char *to)
if (stat(from, &st))
goto out;

+ if (st.st_size == 0) /* /proc? do it slowly... */
+ return slow_copyfile(from, to);
+
fromfd = open(from, O_RDONLY);
if (fromfd < 0)
goto out;
--
1.6.2.5