2010-01-07 22:01:00

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/6] perf buildid-list: No need to process the header sections again

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

As it is already processed by:

perf_session__new
perf_session__open
perf_session__read

This was harmless, because we use dsos__findnew, that would already find
it, but is unnecessary work and removing it makes builtin-buildid-list.c
even shorter.

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/builtin-buildid-list.c | 25 +------------------------
1 files changed, 1 insertions(+), 24 deletions(-)

diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 1e99ac8..4229c2c 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -31,26 +31,6 @@ static const struct option options[] = {
OPT_END()
};

-static int perf_file_section__process_buildids(struct perf_file_section *self,
- int feat, int fd)
-{
- if (feat != HEADER_BUILD_ID)
- return 0;
-
- if (lseek(fd, self->offset, SEEK_SET) < 0) {
- pr_warning("Failed to lseek to %Ld offset for buildids!\n",
- self->offset);
- return -1;
- }
-
- if (perf_header__read_build_ids(fd, self->offset, self->size)) {
- pr_warning("Failed to read buildids!\n");
- return -1;
- }
-
- return 0;
-}
-
static int __cmd_buildid_list(void)
{
int err = -1;
@@ -60,10 +40,7 @@ static int __cmd_buildid_list(void)
if (session == NULL)
return -1;

- err = perf_header__process_sections(&session->header, session->fd,
- perf_file_section__process_buildids);
- if (err >= 0)
- dsos__fprintf_buildid(stdout);
+ dsos__fprintf_buildid(stdout);

perf_session__delete(session);
return err;
--
1.6.2.5


2010-01-07 21:59:56

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/6] perf symbols: Record the domain of DSOs in HEADER_BUILD_ID header table

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

So that we can restore them to the right DSO list (either dsos__kernel
or dsos__user).

We do that just like the kernel does for the other events, encoding
PERF_RECORD_MISC_{KERNEL,USER} in perf_event_header.

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/header.c | 9 ++++++---
tools/perf/util/session.c | 6 +++++-
tools/perf/util/symbol.c | 6 +++---
tools/perf/util/symbol.h | 11 +++++++++--
4 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 942f7da..ec96321 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -193,7 +193,7 @@ static int write_padded(int fd, const void *bf, size_t count,
continue; \
else

-static int __dsos__write_buildid_table(struct list_head *head, int fd)
+static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
{
struct dso *pos;

@@ -205,6 +205,7 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
len = ALIGN(len, NAME_ALIGN);
memset(&b, 0, sizeof(b));
memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
+ b.header.misc = misc;
b.header.size = sizeof(b) + len;
err = do_write(fd, &b, sizeof(b));
if (err < 0)
@@ -220,9 +221,11 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)

static int dsos__write_buildid_table(int fd)
{
- int err = __dsos__write_buildid_table(&dsos__kernel, fd);
+ int err = __dsos__write_buildid_table(&dsos__kernel,
+ PERF_RECORD_MISC_KERNEL, fd);
if (err == 0)
- err = __dsos__write_buildid_table(&dsos__user, fd);
+ err = __dsos__write_buildid_table(&dsos__user,
+ PERF_RECORD_MISC_USER, fd);
return err;
}

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e0e6a07..378ac54 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -255,6 +255,7 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size)
while (offset < limit) {
struct dso *dso;
ssize_t len;
+ struct list_head *head = &dsos__user;

if (read(input, &bev, sizeof(bev)) != sizeof(bev))
goto out;
@@ -263,7 +264,10 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size)
if (read(input, filename, len) != len)
goto out;

- dso = dsos__findnew(filename);
+ if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
+ head = &dsos__kernel;
+
+ dso = __dsos__findnew(head, filename);
if (dso != NULL)
dso__set_build_id(dso, &bev.build_id);

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index da2f07f..8e6627e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1615,14 +1615,14 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
return NULL;
}

-struct dso *dsos__findnew(const char *name)
+struct dso *__dsos__findnew(struct list_head *head, const char *name)
{
- struct dso *dso = dsos__find(&dsos__user, name);
+ struct dso *dso = dsos__find(head, name);

if (!dso) {
dso = dso__new(name);
if (dso != NULL) {
- dsos__add(&dsos__user, dso);
+ dsos__add(head, dso);
dso__set_basename(dso);
}
}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b2b5330..ee0b459 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -115,9 +115,17 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type);

void dso__sort_by_name(struct dso *self, enum map_type type);

+extern struct list_head dsos__user, dsos__kernel;
+
+struct dso *__dsos__findnew(struct list_head *head, const char *name);
+
+static inline struct dso *dsos__findnew(const char *name)
+{
+ return __dsos__findnew(&dsos__user, name);
+}
+
struct perf_session;

-struct dso *dsos__findnew(const char *name);
int dso__load(struct dso *self, struct map *map, struct perf_session *session,
symbol_filter_t filter);
void dsos__fprintf(FILE *fp);
@@ -143,6 +151,5 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);

int perf_session__create_kernel_maps(struct perf_session *self);

-extern struct list_head dsos__user, dsos__kernel;
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
--
1.6.2.5

2010-01-07 22:00:08

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 6/6] perf tools: Encode kernel module mappings in perf.data

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

We were always looking at the running machine /proc/modules, even when
processing a perf.data file, which only makes sense when we're doing
'perf record' and 'perf report' on the same machine, and in close
sucession, or if we don't use modules at all, right Peter? ;-)

Now, at 'perf record' time we read /proc/modules, find the long path for
modules, and put them as PERF_MMAP events, just like we did to encode
the reloc reference symbol for vmlinux. Talking about that now it is
encoded in .pgoff, so that we can use .{start,len} to store the address
boundaries for the kernel so that when we reconstruct the kmaps tree we
can do lookups right away, without having to fixup the end of the kernel
maps like we did in the past (and now only in perf record).

One more step in the 'perf archive' direction when we'll finally be able
to collect data in one machine and analyse in another.

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/builtin-kmem.c | 5 ++
tools/perf/builtin-record.c | 11 ++++
tools/perf/builtin-top.c | 5 ++
tools/perf/util/event.c | 104 ++++++++++++++++++++++++++++++++++-----
tools/perf/util/event.h | 2 +
tools/perf/util/session.c | 8 ++--
tools/perf/util/session.h | 4 ++
tools/perf/util/symbol.c | 116 +++++++++++++++++++++++++++++++------------
tools/perf/util/symbol.h | 3 +
tools/perf/util/thread.h | 4 ++
10 files changed, 214 insertions(+), 48 deletions(-)

diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 2d2990d..3e3acc4 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -492,6 +492,11 @@ static int __cmd_kmem(void)
if (!perf_session__has_traces(session, "kmem record"))
goto out_delete;

+ if (perf_session__create_kernel_maps(session) < 0) {
+ pr_err("Problems creating kernel maps\n");
+ return -1;
+ }
+
setup_pager();
err = perf_session__process_events(session, &event_ops);
if (err != 0)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8f88420..c130df2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -465,6 +465,11 @@ static int __cmd_record(int argc, const char **argv)
return -1;
}

+ if (perf_session__create_kernel_maps(session) < 0) {
+ pr_err("Problems creating kernel maps\n");
+ return -1;
+ }
+
if (!file_new) {
err = perf_header__read(&session->header, output);
if (err < 0)
@@ -558,6 +563,12 @@ static int __cmd_record(int argc, const char **argv)
return err;
}

+ err = event__synthesize_modules(process_synthesized_event, session);
+ if (err < 0) {
+ pr_err("Couldn't record kernel reference relocation symbol.\n");
+ return err;
+ }
+
if (!system_wide && profile_cpu == -1)
event__synthesize_thread(pid, process_synthesized_event,
session);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8f0c837..4786857 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1161,6 +1161,11 @@ static int __cmd_top(void)
if (session == NULL)
return -ENOMEM;

+ if (perf_session__create_kernel_maps(session) < 0) {
+ pr_err("Problems creating kernel maps\n");
+ return -1;
+ }
+
if (target_pid != -1)
event__synthesize_thread(target_pid, event__process, session);
else
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bfb3d87..73e8dd9 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -154,6 +154,34 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
return 0;
}

+int event__synthesize_modules(event__handler_t process,
+ struct perf_session *session)
+{
+ struct rb_node *nd;
+ struct map *pos;
+
+ perf_session__for_each_module_map(session, pos, nd) {
+ size_t size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+ event_t ev = {
+ .mmap = {
+ .header = {
+ .type = PERF_RECORD_MMAP,
+ .size = (sizeof(ev.mmap) -
+ (sizeof(ev.mmap.filename) - size)),
+ },
+ .start = pos->start,
+ .len = pos->end - pos->start,
+ },
+ };
+
+ memcpy(ev.mmap.filename, pos->dso->long_name,
+ pos->dso->long_name_len + 1);
+ process(&ev, session);
+ }
+
+ return 0;
+}
+
int event__synthesize_thread(pid_t pid, event__handler_t process,
struct perf_session *session)
{
@@ -222,7 +250,9 @@ int event__synthesize_kernel_mmap(event__handler_t process,
"[kernel.kallsyms.%s]", symbol_name) + 1;
size = ALIGN(size, sizeof(u64));
ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
- ev.mmap.start = args.start;
+ ev.mmap.pgoff = args.start;
+ ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
+ ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;

return process(&ev, session);
}
@@ -280,7 +310,6 @@ int event__process_mmap(event_t *self, struct perf_session *session)
{
struct thread *thread;
struct map *map;
- static const char kmmap_prefix[] = "[kernel.kallsyms.";

dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
self->mmap.pid, self->mmap.tid,
@@ -289,13 +318,61 @@ int event__process_mmap(event_t *self, struct perf_session *session)
(void *)(long)self->mmap.pgoff,
self->mmap.filename);

- if (self->mmap.pid == 0 &&
- memcmp(self->mmap.filename, kmmap_prefix,
- sizeof(kmmap_prefix) - 1) == 0) {
- const char *symbol_name = (self->mmap.filename +
- sizeof(kmmap_prefix) - 1);
- perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
- self->mmap.start);
+ if (self->mmap.pid == 0) {
+ static const char kmmap_prefix[] = "[kernel.kallsyms.";
+
+ if (self->mmap.filename[0] == '/') {
+ char short_module_name[1024];
+ char *name = strrchr(self->mmap.filename, '/'), *dot;
+
+ if (name == NULL)
+ goto out_problem;
+
+ ++name; /* skip / */
+ dot = strrchr(name, '.');
+ if (dot == NULL)
+ goto out_problem;
+
+ snprintf(short_module_name, sizeof(short_module_name),
+ "[%.*s]", (int)(dot - name), name);
+ strxfrchar(short_module_name, '-', '_');
+
+ map = perf_session__new_module_map(session,
+ self->mmap.start,
+ short_module_name);
+ if (map == NULL)
+ goto out_problem;
+
+ name = strdup(self->mmap.filename);
+ if (name == NULL)
+ goto out_problem;
+
+ dso__set_long_name(map->dso, name);
+ map->end = map->start + self->mmap.len;
+ } else if (memcmp(self->mmap.filename, kmmap_prefix,
+ sizeof(kmmap_prefix) - 1) == 0) {
+ const char *symbol_name = (self->mmap.filename +
+ sizeof(kmmap_prefix) - 1);
+ /*
+ * Should be there already, from the build-id table in
+ * the header.
+ */
+ struct dso *kernel = __dsos__findnew(&dsos__kernel,
+ "[kernel.kallsyms]");
+ if (kernel == NULL)
+ goto out_problem;
+
+ if (__map_groups__create_kernel_maps(&session->kmaps,
+ session->vmlinux_maps,
+ kernel) < 0)
+ goto out_problem;
+
+ session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
+ session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
+
+ perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
+ self->mmap.pgoff);
+ }
return 0;
}

@@ -304,10 +381,13 @@ int event__process_mmap(event_t *self, struct perf_session *session)
session->cwd, session->cwdlen);

if (thread == NULL || map == NULL)
- dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
- else
- thread__insert_map(thread, map);
+ goto out_problem;
+
+ thread__insert_map(thread, map);
+ return 0;

+out_problem:
+ dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
return 0;
}

diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 80356da..50a7132 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -112,6 +112,8 @@ void event__synthesize_threads(event__handler_t process,
int event__synthesize_kernel_mmap(event__handler_t process,
struct perf_session *session,
const char *symbol_name);
+int event__synthesize_modules(event__handler_t process,
+ struct perf_session *session);

int event__process_comm(event_t *self, struct perf_session *session);
int event__process_lost(event_t *self, struct perf_session *session);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 378ac54..fd1c5a3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -69,9 +69,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
self->unknown_events = 0;
map_groups__init(&self->kmaps);

- if (perf_session__create_kernel_maps(self) < 0)
- goto out_delete;
-
if (mode == O_RDONLY && perf_session__open(self, force) < 0)
goto out_delete;

@@ -268,8 +265,11 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size)
head = &dsos__kernel;

dso = __dsos__findnew(head, filename);
- if (dso != NULL)
+ if (dso != NULL) {
dso__set_build_id(dso, &bev.build_id);
+ if (head == &dsos__kernel && filename[0] == '[')
+ dso->kernel = 1;
+ }

offset += bev.header.size;
}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index d4a9d20..4446d60 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -69,4 +69,8 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
void perf_session__reloc_vmlinux_maps(struct perf_session *self,
u64 unrelocated_addr);

+#define perf_session__for_each_module_map(self, pos, nd) \
+ rb_for_each_entry(pos, nd, &self->kmaps.maps[MAP__FUNCTION], rb_node) \
+ if (pos->dso->kernel) continue; else
+
#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 85b96ea..9df9833 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -161,7 +161,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
self->start, self->end, self->name);
}

-static void dso__set_long_name(struct dso *self, char *name)
+void dso__set_long_name(struct dso *self, char *name)
{
if (name == NULL)
return;
@@ -176,7 +176,7 @@ static void dso__set_basename(struct dso *self)

struct dso *dso__new(const char *name)
{
- struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
+ struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);

if (self != NULL) {
int i;
@@ -498,13 +498,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,

*module++ = '\0';

- if (strcmp(self->name, module)) {
+ if (strcmp(curr_map->dso->short_name, module)) {
curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
if (curr_map == NULL) {
pr_debug("/proc/{kallsyms,modules} "
- "inconsistency!\n");
+ "inconsistency while looking "
+ "for \"%s\" module!\n", module);
return -1;
}
+
+ if (curr_map->dso->loaded)
+ goto discard_symbol;
}
/*
* So that we look just like we get from .ko files,
@@ -1340,12 +1344,32 @@ struct map *map_groups__find_by_name(struct map_groups *self,
struct map *map;

rb_for_each_entry(map, nd, &self->maps[type], rb_node)
- if (map->dso && strcmp(map->dso->name, name) == 0)
+ if (map->dso && strcmp(map->dso->short_name, name) == 0)
return map;

return NULL;
}

+static int dso__kernel_module_get_build_id(struct dso *self)
+{
+ char filename[PATH_MAX];
+ /*
+ * kernel module short names are of the form "[module]" and
+ * we need just "module" here.
+ */
+ const char *name = self->short_name + 1;
+
+ snprintf(filename, sizeof(filename),
+ "/sys/module/%.*s/notes/.note.gnu.build-id",
+ (int)strlen(name - 1), name);
+
+ if (sysfs__read_build_id(filename, self->build_id,
+ sizeof(self->build_id)) == 0)
+ self->has_build_id = true;
+
+ return 0;
+}
+
static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
{
struct dirent *dent;
@@ -1391,6 +1415,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
if (long_name == NULL)
goto failure;
dso__set_long_name(map->dso, long_name);
+ dso__kernel_module_get_build_id(map->dso);
}
}

@@ -1433,6 +1458,24 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
return self;
}

+struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
+ const char *filename)
+{
+ struct map *map;
+ struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
+
+ if (dso == NULL)
+ return NULL;
+
+ map = map__new2(start, dso, MAP__FUNCTION);
+ if (map == NULL)
+ return NULL;
+
+ dso->origin = DSO__ORIG_KMODULE;
+ map_groups__insert(&self->kmaps, map);
+ return map;
+}
+
static int perf_session__create_module_maps(struct perf_session *self)
{
char *line = NULL;
@@ -1446,7 +1489,6 @@ static int perf_session__create_module_maps(struct perf_session *self)
while (!feof(file)) {
char name[PATH_MAX];
u64 start;
- struct dso *dso;
char *sep;
int line_len;

@@ -1472,26 +1514,10 @@ static int perf_session__create_module_maps(struct perf_session *self)
*sep = '\0';

snprintf(name, sizeof(name), "[%s]", line);
- dso = dso__new(name);
-
- if (dso == NULL)
- goto out_delete_line;
-
- map = map__new2(start, dso, MAP__FUNCTION);
- if (map == NULL) {
- dso__delete(dso);
+ map = perf_session__new_module_map(self, start, name);
+ if (map == NULL)
goto out_delete_line;
- }
-
- snprintf(name, sizeof(name),
- "/sys/module/%s/notes/.note.gnu.build-id", line);
- if (sysfs__read_build_id(name, dso->build_id,
- sizeof(dso->build_id)) == 0)
- dso->has_build_id = true;
-
- dso->origin = DSO__ORIG_KMODULE;
- map_groups__insert(&self->kmaps, map);
- dsos__add(&dsos__kernel, dso);
+ dso__kernel_module_get_build_id(map->dso);
}

free(line);
@@ -1569,10 +1595,28 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
}
}

+ /*
+ * 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,
+ * using it if it is.
+ */
+ if (self->has_build_id) {
+ 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;
+ goto do_vmlinux;
+ }
+
is_kallsyms = self->long_name[0] == '[';
if (is_kallsyms)
goto do_kallsyms;

+do_vmlinux:
err = dso__load_vmlinux(self, map, session, self->long_name, filter);
if (err <= 0) {
pr_info("The file %s cannot be used, "
@@ -1690,16 +1734,12 @@ out_delete_kernel_dso:
return NULL;
}

-static int map_groups__create_kernel_maps(struct map_groups *self,
- struct map *vmlinux_maps[MAP__NR_TYPES],
- const char *vmlinux)
+int __map_groups__create_kernel_maps(struct map_groups *self,
+ struct map *vmlinux_maps[MAP__NR_TYPES],
+ struct dso *kernel)
{
- struct dso *kernel = dsos__create_kernel(vmlinux);
enum map_type type;

- if (kernel == NULL)
- return -1;
-
for (type = 0; type < MAP__NR_TYPES; ++type) {
vmlinux_maps[type] = map__new2(0, kernel, type);
if (vmlinux_maps[type] == NULL)
@@ -1713,6 +1753,18 @@ static int map_groups__create_kernel_maps(struct map_groups *self,
return 0;
}

+static int map_groups__create_kernel_maps(struct map_groups *self,
+ struct map *vmlinux_maps[MAP__NR_TYPES],
+ const char *vmlinux)
+{
+ struct dso *kernel = dsos__create_kernel(vmlinux);
+
+ if (kernel == NULL)
+ return -1;
+
+ return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel);
+}
+
static void vmlinux_path__exit(void)
{
while (--vmlinux_path__nr_entries >= 0) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ee0b459..594156e 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -134,6 +134,7 @@ size_t dsos__fprintf_buildid(FILE *fp);
size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
char dso__symtab_origin(const struct dso *self);
+void dso__set_long_name(struct dso *self, char *name);
void dso__set_build_id(struct dso *self, void *build_id);
struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
@@ -151,5 +152,7 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);

int perf_session__create_kernel_maps(struct perf_session *self);

+struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
+ const char *filename);
extern struct dso *vdso;
#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72..c06c135 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -67,4 +67,8 @@ map_groups__find_function(struct map_groups *self, struct perf_session *session,

struct map *map_groups__find_by_name(struct map_groups *self,
enum map_type type, const char *name);
+
+int __map_groups__create_kernel_maps(struct map_groups *self,
+ struct map *vmlinux_maps[MAP__NR_TYPES],
+ struct dso *kernel);
#endif /* __PERF_THREAD_H */
--
1.6.2.5

2010-01-07 22:00:31

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 5/6] perf tools: Use rb_for_each_entry

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

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/builtin-annotate.c | 19 ++++++-------------
tools/perf/builtin-diff.c | 5 ++---
tools/perf/builtin-kmem.c | 12 +++++-------
tools/perf/builtin-sched.c | 10 ++--------
tools/perf/builtin-top.c | 10 +++-------
tools/perf/util/symbol.c | 16 ++++++----------
6 files changed, 24 insertions(+), 48 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 117bbae..61b644e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -349,19 +349,12 @@ static void print_summary(const char *filename)
return;
}

- node = rb_first(&root_sym_ext);
- while (node) {
- double percent;
- const char *color;
- char *path;
-
- sym_ext = rb_entry(node, struct sym_ext, node);
- percent = sym_ext->percent;
- color = get_percent_color(percent);
- path = sym_ext->path;
+ rb_for_each_entry(sym_ext, node, &root_sym_ext, node) {
+ double percent = sym_ext->percent;
+ const char *color = get_percent_color(percent);
+ char *path = sym_ext->path;

color_fprintf(stdout, color, " %7.2f %s", percent, path);
- node = rb_next(node);
}
}

@@ -428,9 +421,9 @@ static void annotate_sym(struct hist_entry *he)
static void perf_session__find_annotations(struct perf_session *self)
{
struct rb_node *nd;
+ struct hist_entry *he;

- for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
- struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+ rb_for_each_entry(he, nd, &self->hists, rb_node) {
struct sym_priv *priv;

if (he->sym == NULL)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 924bfb7..48a1e61 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -143,11 +143,10 @@ static void perf_session__match_hists(struct perf_session *old_session,
struct perf_session *new_session)
{
struct rb_node *nd;
+ struct hist_entry *pos;

- for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
- struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
+ rb_for_each_entry(pos, nd, &new_session->hists, rb_node)
pos->pair = perf_session__find_hist_entry(old_session, pos);
- }
}

static int __cmd_diff(void)
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 88c570c..2d2990d 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -354,21 +354,21 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
int n_lines, int is_caller)
{
struct rb_node *next;
+ struct alloc_stat *data;

printf("%.102s\n", graph_dotted_line);
printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
printf("%.102s\n", graph_dotted_line);

- next = rb_first(root);
-
- while (next && n_lines--) {
- struct alloc_stat *data = rb_entry(next, struct alloc_stat,
- node);
+ rb_for_each_entry(data, next, root, node) {
struct symbol *sym = NULL;
char buf[BUFSIZ];
u64 addr;

+ if (n_lines--)
+ break;
+
if (is_caller) {
addr = data->call_site;
if (!raw_ip)
@@ -391,8 +391,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
(unsigned long)data->hit,
(unsigned long)data->pingpong,
fragmentation(data->bytes_req, data->bytes_alloc));
-
- next = rb_next(next);
}

if (n_lines == -1)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 702322f..88be245 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1706,6 +1706,7 @@ static void print_bad_events(void)
static void __cmd_lat(void)
{
struct rb_node *next;
+ struct work_atoms *work_list;

setup_pager();
read_events();
@@ -1715,15 +1716,8 @@ static void __cmd_lat(void)
printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
printf(" ---------------------------------------------------------------------------------------------------------------\n");

- next = rb_first(&sorted_atom_root);
-
- while (next) {
- struct work_atoms *work_list;
-
- work_list = rb_entry(next, struct work_atoms, node);
+ rb_for_each_entry(work_list, next, &sorted_atom_root, node)
output_lat_thread(work_list);
- next = rb_next(next);
- }

printf(" -----------------------------------------------------------------------------------------\n");
printf(" TOTAL: |%11.3f ms |%9Ld |\n",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ddc584b..8f0c837 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -532,8 +532,7 @@ static void print_sym_table(void)
/*
* Find the longest symbol name that will be displayed
*/
- for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
- syme = rb_entry(nd, struct sym_entry, rb_node);
+ rb_for_each_entry(syme, nd, &tmp, rb_node) {
if (++printed > print_entries ||
(int)syme->snap_count < count_filter)
continue;
@@ -567,13 +566,10 @@ static void print_sym_table(void)
printf(" %-*.*s", dso_width, dso_width, graph_line);
puts("\n");

- for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
- struct symbol *sym;
+ rb_for_each_entry(syme, nd, &tmp, rb_node) {
+ struct symbol *sym = sym_entry__symbol(syme);
double pcnt;

- syme = rb_entry(nd, struct sym_entry, rb_node);
- sym = sym_entry__symbol(syme);
-
if (++printed > print_entries || (int)syme->snap_count < count_filter)
continue;

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8e6627e..85b96ea 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -292,11 +292,10 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
{
struct rb_node *nd;
+ struct symbol *pos;

- for (nd = rb_first(source); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ rb_for_each_entry(pos, nd, source, rb_node)
symbols__insert_by_name(self, pos);
- }
}

static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
@@ -371,14 +370,13 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
{
struct rb_node *nd;
+ struct symbol *pos;
size_t ret = fprintf(fp, "dso: %s (", self->short_name);

ret += dso__fprintf_buildid(self, fp);
ret += fprintf(fp, ")\n");
- for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ rb_for_each_entry(pos, nd, &self->symbols[type], rb_node)
ret += symbol__fprintf(pos, fp);
- }

return ret;
}
@@ -1339,13 +1337,11 @@ struct map *map_groups__find_by_name(struct map_groups *self,
enum map_type type, const char *name)
{
struct rb_node *nd;
+ struct map *map;

- for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
- struct map *map = rb_entry(nd, struct map, rb_node);
-
+ rb_for_each_entry(map, nd, &self->maps[type], rb_node)
if (map->dso && strcmp(map->dso->name, name) == 0)
return map;
- }

return NULL;
}
--
1.6.2.5

2010-01-07 22:01:10

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 4/6] rbtree: Introduce rb_for_each_entry

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

Similar to list_for_each_entry, helps reducing boilerplate in many
places and makes rbtrees closer to list.h macros.

First conversion will be in the tools/perf.

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]>
---
include/linux/rbtree.h | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 9c29541..044b150 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -158,4 +158,16 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
*rb_link = node;
}

+/**
+ * rb_for_each_entry - iterate over rbtree of given type
+ * @pos: the type * to hold the current entry being traversed
+ * @node: the rb_node to hold the current entry being traversed
+ * @root: the root for your tree.
+ * @member: the name of the rb_node within the struct.
+ */
+#define rb_for_each_entry(pos, node, root, member) \
+ for (node = rb_first(root); \
+ node && (pos = rb_entry(node, typeof(*pos), member)); \
+ node = rb_next(node))
+
#endif /* _LINUX_RBTREE_H */
--
1.6.2.5

2010-01-07 22:01:40

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/6] perf tools: Create typedef for common event synthesizing callback

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

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 | 16 +++++-----------
tools/perf/util/event.h | 12 +++++-------
2 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1a31feb..bfb3d87 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -8,8 +8,7 @@
#include "thread.h"

static pid_t event__synthesize_comm(pid_t pid, int full,
- int (*process)(event_t *event,
- struct perf_session *session),
+ event__handler_t process,
struct perf_session *session)
{
event_t ev;
@@ -91,8 +90,7 @@ out_failure:
}

static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
- int (*process)(event_t *event,
- struct perf_session *session),
+ event__handler_t process,
struct perf_session *session)
{
char filename[PATH_MAX];
@@ -156,9 +154,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
return 0;
}

-int event__synthesize_thread(pid_t pid,
- int (*process)(event_t *event,
- struct perf_session *session),
+int event__synthesize_thread(pid_t pid, event__handler_t process,
struct perf_session *session)
{
pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +163,7 @@ int event__synthesize_thread(pid_t pid,
return event__synthesize_mmap_events(pid, tgid, process, session);
}

-void event__synthesize_threads(int (*process)(event_t *event,
- struct perf_session *session),
+void event__synthesize_threads(event__handler_t process,
struct perf_session *session)
{
DIR *proc;
@@ -205,8 +200,7 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
return 1;
}

-int event__synthesize_kernel_mmap(int (*process)(event_t *event,
- struct perf_session *session),
+int event__synthesize_kernel_mmap(event__handler_t process,
struct perf_session *session,
const char *symbol_name)
{
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 61fc0dc..80356da 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -103,15 +103,13 @@ void event__print_totals(void);

struct perf_session;

-int event__synthesize_thread(pid_t pid,
- int (*process)(event_t *event,
- struct perf_session *session),
+typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
+
+int event__synthesize_thread(pid_t pid, event__handler_t process,
struct perf_session *session);
-void event__synthesize_threads(int (*process)(event_t *event,
- struct perf_session *session),
+void event__synthesize_threads(event__handler_t process,
struct perf_session *session);
-int event__synthesize_kernel_mmap(int (*process)(event_t *event,
- struct perf_session *session),
+int event__synthesize_kernel_mmap(event__handler_t process,
struct perf_session *session,
const char *symbol_name);

--
1.6.2.5

2010-01-13 09:11:53

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 5/6] perf tools: Use rb_for_each_entry


* Arnaldo Carvalho de Melo <[email protected]> wrote:

> From: Arnaldo Carvalho de Melo <[email protected]>
>
> 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/builtin-annotate.c | 19 ++++++-------------
> tools/perf/builtin-diff.c | 5 ++---
> tools/perf/builtin-kmem.c | 12 +++++-------
> tools/perf/builtin-sched.c | 10 ++--------
> tools/perf/builtin-top.c | 10 +++-------
> tools/perf/util/symbol.c | 16 ++++++----------
> 6 files changed, 24 insertions(+), 48 deletions(-)

hm, this one doesnt build very well:

touch .perf.dev.null
CC builtin-annotate.o
CC builtin-diff.o
CC builtin-sched.o
CC builtin-top.o
CC builtin-kmem.o
CC util/symbol.o
cc1: warnings being treated as errors
builtin-diff.c: In function 'perf_session__match_hists':
builtin-diff.c:148: error: implicit declaration of function 'rb_for_each_entry'
builtin-diff.c:148: error: nested extern declaration of 'rb_for_each_entry'
builtin-diff.c:148: error: 'rb_node' undeclared (first use in this function)
builtin-diff.c:148: error: (Each undeclared identifier is reported only once
builtin-diff.c:148: error: for each function it appears in.)
builtin-diff.c:149: error: expected ';' before 'pos'
builtin-diff.c:142: error: unused parameter 'old_session'
make: *** [builtin-diff.o] Error 1
make: *** Waiting for unfinished jobs....
cc1: warnings being treated as errors
builtin-annotate.c: In function 'print_summary':
builtin-annotate.c:352: error: implicit declaration of function 'rb_for_each_entry'
builtin-annotate.c:352: error: nested extern declaration of 'rb_for_each_entry'
builtin-annotate.c:352: error: expected ';' before '{' token
builtin-annotate.c: In function 'perf_session__find_annotations':
builtin-annotate.c:426: error: 'rb_node' undeclared (first use in this function)
builtin-annotate.c:426: error: (Each undeclared identifier is reported only once
builtin-annotate.c:426: error: for each function it appears in.)
builtin-annotate.c:426: error: expected ';' before '{' token
make: *** [builtin-annotate.o] Error 1
cc1: warnings being treated as errors
builtin-top.c: In function 'print_sym_table':
builtin-top.c:535: error: implicit declaration of function 'rb_for_each_entry'
builtin-top.c:535: error: nested extern declaration of 'rb_for_each_entry'
builtin-top.c:535: error: 'rb_node' undeclared (first use in this function)
builtin-top.c:535: error: (Each undeclared identifier is reported only once
builtin-top.c:535: error: for each function it appears in.)
builtin-top.c:535: error: expected ';' before '{' token
builtin-top.c:569: error: expected ';' before '{' token
builtin-top.c:446: error: unused variable 'printed'
cc1: warnings being treated as errors
builtin-kmem.c: In function '__print_result':
builtin-kmem.c:364: error: implicit declaration of function 'rb_for_each_entry'
builtin-kmem.c:364: error: nested extern declaration of 'rb_for_each_entry'
builtin-kmem.c:364: error: 'node' undeclared (first use in this function)
builtin-kmem.c:364: error: (Each undeclared identifier is reported only once
builtin-kmem.c:364: error: for each function it appears in.)
builtin-kmem.c:364: error: expected ';' before '{' token
builtin-kmem.c:353: error: unused parameter 'session'
builtin-kmem.c:354: error: unused parameter 'n_lines'
make: *** [builtin-kmem.o] Error 1
make: *** [builtin-top.o] Error 1
cc1: warnings being treated as errors
builtin-sched.c: In function '__cmd_lat':
builtin-sched.c:1719: error: implicit declaration of function 'rb_for_each_entry'
builtin-sched.c:1719: error: nested extern declaration of 'rb_for_each_entry'
builtin-sched.c:1719: error: 'node' undeclared (first use in this function)
builtin-sched.c:1719: error: (Each undeclared identifier is reported only once
builtin-sched.c:1719: error: for each function it appears in.)
builtin-sched.c:1720: error: expected ';' before 'output_lat_thread'
make: *** [builtin-sched.o] Error 1
cc1: warnings being treated as errors
util/symbol.c: In function 'symbols__sort_by_name':
util/symbol.c:297: error: implicit declaration of function 'rb_for_each_entry'
util/symbol.c:297: error: nested extern declaration of 'rb_for_each_entry'
util/symbol.c:297: error: 'rb_node' undeclared (first use in this function)
util/symbol.c:297: error: (Each undeclared identifier is reported only once
util/symbol.c:297: error: for each function it appears in.)
util/symbol.c:298: error: expected ';' before 'symbols__insert_by_name'
util/symbol.c:292: error: unused parameter 'self'
util/symbol.c: In function 'dso__fprintf':
util/symbol.c:378: error: 'rb_node' undeclared (first use in this function)
util/symbol.c:379: error: expected ';' before 'ret'
util/symbol.c: In function 'map_groups__find_by_name':
util/symbol.c:1342: error: 'rb_node' undeclared (first use in this function)
util/symbol.c:1343: error: expected ';' before 'if'
util/symbol.c:1337: error: unused parameter 'name'
make: *** [util/symbol.o] Error 1
rm .perf.dev.null

Ingo

2010-01-13 12:58:23

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 5/6] perf tools: Use rb_for_each_entry

Em Wed, Jan 13, 2010 at 10:11:35AM +0100, Ingo Molnar escreveu:
>
> * Arnaldo Carvalho de Melo <[email protected]> wrote:
>
> > From: Arnaldo Carvalho de Melo <[email protected]>
> >
> > 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/builtin-annotate.c | 19 ++++++-------------
> > tools/perf/builtin-diff.c | 5 ++---
> > tools/perf/builtin-kmem.c | 12 +++++-------
> > tools/perf/builtin-sched.c | 10 ++--------
> > tools/perf/builtin-top.c | 10 +++-------
> > tools/perf/util/symbol.c | 16 ++++++----------
> > 6 files changed, 24 insertions(+), 48 deletions(-)
>
> hm, this one doesnt build very well:
>
> touch .perf.dev.null
> CC builtin-annotate.o
> CC builtin-diff.o
> CC builtin-sched.o
> CC builtin-top.o
> CC builtin-kmem.o
> CC util/symbol.o
> cc1: warnings being treated as errors
> builtin-diff.c: In function 'perf_session__match_hists':
> builtin-diff.c:148: error: implicit declaration of function 'rb_for_each_entry'

Checking and will resend shortly.

- Arnaldo