Skip to content

Commit

Permalink
perf tools: Encode kernel module mappings in perf.data
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1263396139-4798-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Arnaldo Carvalho de Melo authored and Ingo Molnar committed Jan 13, 2010
1 parent ff314d3 commit b7cece7
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 48 deletions.
5 changes: 5 additions & 0 deletions tools/perf/builtin-kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,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)
Expand Down
11 changes: 11 additions & 0 deletions tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,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
Expand Down
106 changes: 94 additions & 12 deletions tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,36 @@ 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;

for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
nd; nd = rb_next(nd)) {
event_t ev;
size_t size;
struct map *pos = rb_entry(nd, struct map, rb_node);

if (pos->dso->kernel)
continue;

size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
memset(&ev, 0, sizeof(ev));
ev.mmap.header.type = PERF_RECORD_MMAP;
ev.mmap.header.size = (sizeof(ev.mmap) -
(sizeof(ev.mmap.filename) - size));
ev.mmap.start = pos->start;
ev.mmap.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)
{
Expand Down Expand Up @@ -222,7 +252,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);
}
Expand Down Expand Up @@ -280,7 +312,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,
Expand All @@ -289,13 +320,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;
}

Expand All @@ -304,10 +383,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;
}

Expand Down
2 changes: 2 additions & 0 deletions tools/perf/util/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit b7cece7

Please sign in to comment.