perf session: Move kmaps to perf_session

There is still some more work to do to disentangle map creation
from DSO loading, but this happens only for the kernel, and for
the early adopters of perf diff, where this disentanglement
matters most, we'll be testing different kernels, so no problem
here.

Further clarification: right now we create the kernel maps for
the various modules and discontiguous kernel text maps when
loading the DSO, we should do it as a two step process, first
creating the maps, for multiple mappings with the same DSO
store, then doing the dso load just once, for the first hit on
one of the maps sharing this DSO backing store.

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: <1260741029-4430-6-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Arnaldo Carvalho de Melo 2009-12-13 19:50:29 -02:00 committed by Ingo Molnar
parent b3165f4144
commit 4aa6563641
18 changed files with 136 additions and 120 deletions

View file

@ -463,7 +463,7 @@ static struct perf_event_ops event_ops = {
static int __cmd_annotate(void) static int __cmd_annotate(void)
{ {
struct perf_session *session = perf_session__new(input_name, O_RDONLY, struct perf_session *session = perf_session__new(input_name, O_RDONLY,
force); force, &symbol_conf);
int ret; int ret;
if (session == NULL) if (session == NULL)

View file

@ -54,8 +54,8 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
static int __cmd_buildid_list(void) static int __cmd_buildid_list(void)
{ {
int err = -1; int err = -1;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, force); struct perf_session *session = perf_session__new(input_name, O_RDONLY,
force, NULL);
if (session == NULL) if (session == NULL)
return -1; return -1;

View file

@ -364,19 +364,6 @@ static struct perf_event_ops event_ops = {
.sample_type_check = sample_type_check, .sample_type_check = sample_type_check,
}; };
static int read_events(void)
{
int err;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
if (session == NULL)
return -ENOMEM;
err = perf_session__process_events(session, &event_ops);
perf_session__delete(session);
return err;
}
static double fragmentation(unsigned long n_req, unsigned long n_alloc) static double fragmentation(unsigned long n_req, unsigned long n_alloc)
{ {
if (n_alloc == 0) if (n_alloc == 0)
@ -385,7 +372,8 @@ static double fragmentation(unsigned long n_req, unsigned long n_alloc)
return 100.0 - (100.0 * n_req / n_alloc); return 100.0 - (100.0 * n_req / n_alloc);
} }
static void __print_result(struct rb_root *root, int n_lines, int is_caller) static void __print_result(struct rb_root *root, struct perf_session *session,
int n_lines, int is_caller)
{ {
struct rb_node *next; struct rb_node *next;
@ -406,7 +394,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
if (is_caller) { if (is_caller) {
addr = data->call_site; addr = data->call_site;
if (!raw_ip) if (!raw_ip)
sym = map_groups__find_function(kmaps, addr, NULL); sym = map_groups__find_function(&session->kmaps, session, addr, NULL);
} else } else
addr = data->ptr; addr = data->ptr;
@ -447,12 +435,12 @@ static void print_summary(void)
printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
} }
static void print_result(void) static void print_result(struct perf_session *session)
{ {
if (caller_flag) if (caller_flag)
__print_result(&root_caller_sorted, caller_lines, 1); __print_result(&root_caller_sorted, session, caller_lines, 1);
if (alloc_flag) if (alloc_flag)
__print_result(&root_alloc_sorted, alloc_lines, 0); __print_result(&root_alloc_sorted, session, alloc_lines, 0);
print_summary(); print_summary();
} }
@ -520,12 +508,21 @@ static void sort_result(void)
static int __cmd_kmem(void) static int __cmd_kmem(void)
{ {
setup_pager(); int err;
read_events(); struct perf_session *session = perf_session__new(input_name, O_RDONLY,
sort_result(); 0, NULL);
print_result(); if (session == NULL)
return -ENOMEM;
return 0; setup_pager();
err = perf_session__process_events(session, &event_ops);
if (err != 0)
goto out_delete;
sort_result();
print_result(session);
out_delete:
perf_session__delete(session);
return err;
} }
static const char * const kmem_usage[] = { static const char * const kmem_usage[] = {

View file

@ -442,7 +442,7 @@ static int __cmd_record(int argc, const char **argv)
exit(-1); exit(-1);
} }
session = perf_session__new(output_name, O_WRONLY, force); session = perf_session__new(output_name, O_WRONLY, force, NULL);
if (session == NULL) { if (session == NULL) {
pr_err("Not enough memory for reading perf file header\n"); pr_err("Not enough memory for reading perf file header\n");
return -1; return -1;

View file

@ -414,6 +414,7 @@ static int call__match(struct symbol *sym)
} }
static struct symbol **resolve_callchain(struct thread *thread, static struct symbol **resolve_callchain(struct thread *thread,
struct perf_session *session,
struct ip_callchain *chain, struct ip_callchain *chain,
struct symbol **parent) struct symbol **parent)
{ {
@ -447,8 +448,8 @@ static struct symbol **resolve_callchain(struct thread *thread,
continue; continue;
} }
thread__find_addr_location(thread, cpumode, MAP__FUNCTION, thread__find_addr_location(thread, session, cpumode,
ip, &al, NULL); MAP__FUNCTION, ip, &al, NULL);
if (al.sym != NULL) { if (al.sym != NULL) {
if (sort__has_parent && !*parent && if (sort__has_parent && !*parent &&
call__match(al.sym)) call__match(al.sym))
@ -467,6 +468,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
*/ */
static int hist_entry__add(struct addr_location *al, static int hist_entry__add(struct addr_location *al,
struct perf_session *session,
struct ip_callchain *chain, u64 count) struct ip_callchain *chain, u64 count)
{ {
struct symbol **syms = NULL, *parent = NULL; struct symbol **syms = NULL, *parent = NULL;
@ -474,7 +476,7 @@ static int hist_entry__add(struct addr_location *al,
struct hist_entry *he; struct hist_entry *he;
if ((sort__has_parent || callchain) && chain) if ((sort__has_parent || callchain) && chain)
syms = resolve_callchain(al->thread, chain, &parent); syms = resolve_callchain(al->thread, session, chain, &parent);
he = __hist_entry__add(al, parent, count, &hit); he = __hist_entry__add(al, parent, count, &hit);
if (he == NULL) if (he == NULL)
@ -650,7 +652,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
thread__find_addr_location(thread, cpumode, thread__find_addr_location(thread, session, cpumode,
MAP__FUNCTION, data.ip, &al, NULL); MAP__FUNCTION, data.ip, &al, NULL);
/* /*
* We have to do this here as we may have a dso with no symbol hit that * We have to do this here as we may have a dso with no symbol hit that
@ -669,7 +671,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
return 0; return 0;
if (hist_entry__add(&al, data.callchain, data.period)) { if (hist_entry__add(&al, session, data.callchain, data.period)) {
pr_debug("problem incrementing symbol count, skipping event\n"); pr_debug("problem incrementing symbol count, skipping event\n");
return -1; return -1;
} }
@ -763,7 +765,7 @@ static int __cmd_report(void)
int ret; int ret;
struct perf_session *session; struct perf_session *session;
session = perf_session__new(input_name, O_RDONLY, force); session = perf_session__new(input_name, O_RDONLY, force, &symbol_conf);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;

View file

@ -1679,8 +1679,8 @@ static struct perf_event_ops event_ops = {
static int read_events(void) static int read_events(void)
{ {
int err; int err;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, NULL);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;

View file

@ -1056,7 +1056,8 @@ static struct perf_event_ops event_ops = {
static int __cmd_timechart(void) static int __cmd_timechart(void)
{ {
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, NULL);
int ret; int ret;
if (session == NULL) if (session == NULL)

View file

@ -1162,8 +1162,8 @@ static int __cmd_top(void)
* FIXME: perf_session__new should allow passing a O_MMAP, so that all this * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
* mmap reading, etc is encapsulated in it. Use O_WRONLY for now. * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
*/ */
struct perf_session *session = perf_session__new(NULL, O_WRONLY, false); struct perf_session *session = perf_session__new(NULL, O_WRONLY, false,
&symbol_conf);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;

View file

@ -318,7 +318,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
setup_pager(); setup_pager();
session = perf_session__new(input_name, O_RDONLY, 0); session = perf_session__new(input_name, O_RDONLY, 0, NULL);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;

View file

@ -256,7 +256,8 @@ int event__process_task(event_t *self, struct perf_session *session)
return 0; return 0;
} }
void thread__find_addr_location(struct thread *self, u8 cpumode, void thread__find_addr_location(struct thread *self,
struct perf_session *session, u8 cpumode,
enum map_type type, u64 addr, enum map_type type, u64 addr,
struct addr_location *al, struct addr_location *al,
symbol_filter_t filter) symbol_filter_t filter)
@ -268,7 +269,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
if (cpumode & PERF_RECORD_MISC_KERNEL) { if (cpumode & PERF_RECORD_MISC_KERNEL) {
al->level = 'k'; al->level = 'k';
mg = kmaps; mg = &session->kmaps;
} else if (cpumode & PERF_RECORD_MISC_USER) } else if (cpumode & PERF_RECORD_MISC_USER)
al->level = '.'; al->level = '.';
else { else {
@ -289,14 +290,14 @@ try_again:
* "[vdso]" dso, but for now lets use the old trick of looking * "[vdso]" dso, but for now lets use the old trick of looking
* in the whole kernel symbol list. * in the whole kernel symbol list.
*/ */
if ((long long)al->addr < 0 && mg != kmaps) { if ((long long)al->addr < 0 && mg != &session->kmaps) {
mg = kmaps; mg = &session->kmaps;
goto try_again; goto try_again;
} }
al->sym = NULL; al->sym = NULL;
} else { } else {
al->addr = al->map->map_ip(al->map, al->addr); al->addr = al->map->map_ip(al->map, al->addr);
al->sym = map__find_symbol(al->map, al->addr, filter); al->sym = map__find_symbol(al->map, session, al->addr, filter);
} }
} }
@ -311,7 +312,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
thread__find_addr_location(thread, cpumode, MAP__FUNCTION, thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
self->ip.ip, al, filter); self->ip.ip, al, filter);
dump_printf(" ...... dso: %s\n", dump_printf(" ...... dso: %s\n",
al->map ? al->map->dso->long_name : al->map ? al->map->dso->long_name :

View file

@ -149,15 +149,17 @@ void map__delete(struct map *self);
struct map *map__clone(struct map *self); struct map *map__clone(struct map *self);
int map__overlap(struct map *l, struct map *r); int map__overlap(struct map *l, struct map *r);
size_t map__fprintf(struct map *self, FILE *fp); size_t map__fprintf(struct map *self, FILE *fp);
struct symbol *map__find_symbol(struct map *self, u64 addr,
symbol_filter_t filter); struct perf_session;
struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
u64 addr, symbol_filter_t filter);
struct symbol *map__find_symbol_by_name(struct map *self, const char *name, struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
struct perf_session *session,
symbol_filter_t filter); symbol_filter_t filter);
void map__fixup_start(struct map *self); void map__fixup_start(struct map *self);
void map__fixup_end(struct map *self); void map__fixup_end(struct map *self);
struct perf_session;
int event__synthesize_thread(pid_t pid, int event__synthesize_thread(pid_t pid,
int (*process)(event_t *event, int (*process)(event_t *event,
struct perf_session *session), struct perf_session *session),

View file

@ -104,10 +104,11 @@ void map__fixup_end(struct map *self)
#define DSO__DELETED "(deleted)" #define DSO__DELETED "(deleted)"
static int map__load(struct map *self, symbol_filter_t filter) static int map__load(struct map *self, struct perf_session *session,
symbol_filter_t filter)
{ {
const char *name = self->dso->long_name; const char *name = self->dso->long_name;
int nr = dso__load(self->dso, self, filter); int nr = dso__load(self->dso, self, session, filter);
if (nr < 0) { if (nr < 0) {
if (self->dso->has_build_id) { if (self->dso->has_build_id) {
@ -143,19 +144,20 @@ static int map__load(struct map *self, symbol_filter_t filter)
return 0; return 0;
} }
struct symbol *map__find_symbol(struct map *self, u64 addr, struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
symbol_filter_t filter) u64 addr, symbol_filter_t filter)
{ {
if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) if (!dso__loaded(self->dso, self->type) && map__load(self, session, filter) < 0)
return NULL; return NULL;
return dso__find_symbol(self->dso, self->type, addr); return dso__find_symbol(self->dso, self->type, addr);
} }
struct symbol *map__find_symbol_by_name(struct map *self, const char *name, struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
struct perf_session *session,
symbol_filter_t filter) symbol_filter_t filter)
{ {
if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) if (!dso__loaded(self->dso, self->type) && map__load(self, session, filter) < 0)
return NULL; return NULL;
if (!dso__sorted_by_name(self->dso, self->type)) if (!dso__sorted_by_name(self->dso, self->type))

View file

@ -49,7 +49,7 @@ out_close:
} }
struct perf_session *perf_session__new(const char *filename, int mode, struct perf_session *perf_session__new(const char *filename, int mode,
bool force) bool force, struct symbol_conf *conf)
{ {
size_t len = filename ? strlen(filename) + 1 : 0; size_t len = filename ? strlen(filename) + 1 : 0;
struct perf_session *self = zalloc(sizeof(*self) + len); struct perf_session *self = zalloc(sizeof(*self) + len);
@ -58,7 +58,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
goto out; goto out;
if (perf_header__init(&self->header) < 0) if (perf_header__init(&self->header) < 0)
goto out_delete; goto out_free;
memcpy(self->filename, filename, len); memcpy(self->filename, filename, len);
self->threads = RB_ROOT; self->threads = RB_ROOT;
@ -66,16 +66,21 @@ struct perf_session *perf_session__new(const char *filename, int mode,
self->mmap_window = 32; self->mmap_window = 32;
self->cwd = NULL; self->cwd = NULL;
self->cwdlen = 0; self->cwdlen = 0;
map_groups__init(&self->kmaps);
if (mode == O_RDONLY && perf_session__open(self, force) < 0) { if (perf_session__create_kernel_maps(self, conf) < 0)
perf_session__delete(self); goto out_delete;
self = NULL;
} if (mode == O_RDONLY && perf_session__open(self, force) < 0)
goto out_delete;
out: out:
return self; return self;
out_delete: out_free:
free(self); free(self);
return NULL; return NULL;
out_delete:
perf_session__delete(self);
return NULL;
} }
void perf_session__delete(struct perf_session *self) void perf_session__delete(struct perf_session *self)

View file

@ -3,19 +3,23 @@
#include "event.h" #include "event.h"
#include "header.h" #include "header.h"
#include "thread.h"
#include <linux/rbtree.h> #include <linux/rbtree.h>
struct thread; struct thread;
struct symbol_conf;
struct perf_session { struct perf_session {
struct perf_header header; struct perf_header header;
unsigned long size; unsigned long size;
unsigned long mmap_window; unsigned long mmap_window;
struct map_groups kmaps;
struct rb_root threads; struct rb_root threads;
struct thread *last_match; struct thread *last_match;
int fd; int fd;
int cwdlen; int cwdlen;
char *cwd; char *cwd;
bool use_modules;
char filename[0]; char filename[0];
}; };
@ -37,7 +41,7 @@ struct perf_event_ops {
}; };
struct perf_session *perf_session__new(const char *filename, int mode, struct perf_session *perf_session__new(const char *filename, int mode,
bool force); bool force, struct symbol_conf *conf);
void perf_session__delete(struct perf_session *self); void perf_session__delete(struct perf_session *self);
int perf_session__process_events(struct perf_session *self, int perf_session__process_events(struct perf_session *self,

View file

@ -1,5 +1,6 @@
#include "util.h" #include "util.h"
#include "../perf.h" #include "../perf.h"
#include "session.h"
#include "string.h" #include "string.h"
#include "symbol.h" #include "symbol.h"
#include "thread.h" #include "thread.h"
@ -31,7 +32,7 @@ enum dso_origin {
static void dsos__add(struct list_head *head, struct dso *dso); static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *self, struct map *map, static int dso__load_kernel_sym(struct dso *self, struct map *map,
struct map_groups *mg, symbol_filter_t filter); struct perf_session *session, symbol_filter_t filter);
unsigned int symbol__priv_size; unsigned int symbol__priv_size;
static int vmlinux_path__nr_entries; static int vmlinux_path__nr_entries;
static char **vmlinux_path; static char **vmlinux_path;
@ -41,9 +42,6 @@ static struct symbol_conf symbol_conf__defaults = {
.try_vmlinux_path = true, .try_vmlinux_path = true,
}; };
static struct map_groups kmaps_mem;
struct map_groups *kmaps = &kmaps_mem;
bool dso__loaded(const struct dso *self, enum map_type type) bool dso__loaded(const struct dso *self, enum map_type type)
{ {
return self->loaded & (1 << type); return self->loaded & (1 << type);
@ -456,7 +454,7 @@ out_failure:
* the original ELF section names vmlinux have. * the original ELF section names vmlinux have.
*/ */
static int dso__split_kallsyms(struct dso *self, struct map *map, static int dso__split_kallsyms(struct dso *self, struct map *map,
struct map_groups *mg, symbol_filter_t filter) struct perf_session *session, symbol_filter_t filter)
{ {
struct map *curr_map = map; struct map *curr_map = map;
struct symbol *pos; struct symbol *pos;
@ -473,13 +471,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
module = strchr(pos->name, '\t'); module = strchr(pos->name, '\t');
if (module) { if (module) {
if (!mg->use_modules) if (!session->use_modules)
goto discard_symbol; goto discard_symbol;
*module++ = '\0'; *module++ = '\0';
if (strcmp(self->name, module)) { if (strcmp(self->name, module)) {
curr_map = map_groups__find_by_name(mg, map->type, module); curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
if (curr_map == NULL) { if (curr_map == NULL) {
pr_debug("/proc/{kallsyms,modules} " pr_debug("/proc/{kallsyms,modules} "
"inconsistency!\n"); "inconsistency!\n");
@ -510,7 +508,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
} }
curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
map_groups__insert(mg, curr_map); map_groups__insert(&session->kmaps, curr_map);
++kernel_range; ++kernel_range;
} }
@ -531,7 +529,7 @@ 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, struct map *map,
struct map_groups *mg, symbol_filter_t filter) struct perf_session *session, symbol_filter_t filter)
{ {
if (dso__load_all_kallsyms(self, map) < 0) if (dso__load_all_kallsyms(self, map) < 0)
return -1; return -1;
@ -539,14 +537,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
symbols__fixup_end(&self->symbols[map->type]); symbols__fixup_end(&self->symbols[map->type]);
self->origin = DSO__ORIG_KERNEL; self->origin = DSO__ORIG_KERNEL;
return dso__split_kallsyms(self, map, mg, filter); return dso__split_kallsyms(self, map, session, filter);
}
size_t kernel_maps__fprintf(FILE *fp)
{
size_t printed = fprintf(fp, "Kernel maps:\n");
printed += map_groups__fprintf_maps(kmaps, fp);
return printed + fprintf(fp, "END kernel maps\n");
} }
static int dso__load_perf_map(struct dso *self, struct map *map, static int dso__load_perf_map(struct dso *self, struct map *map,
@ -873,7 +864,7 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
} }
static int dso__load_sym(struct dso *self, struct map *map, static int dso__load_sym(struct dso *self, struct map *map,
struct map_groups *mg, const char *name, int fd, struct perf_session *session, const char *name, int fd,
symbol_filter_t filter, int kernel, int kmodule) symbol_filter_t filter, int kernel, int kmodule)
{ {
struct map *curr_map = map; struct map *curr_map = map;
@ -977,7 +968,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
snprintf(dso_name, sizeof(dso_name), snprintf(dso_name, sizeof(dso_name),
"%s%s", self->short_name, section_name); "%s%s", self->short_name, section_name);
curr_map = map_groups__find_by_name(mg, map->type, dso_name); curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
if (curr_map == NULL) { if (curr_map == NULL) {
u64 start = sym.st_value; u64 start = sym.st_value;
@ -996,7 +987,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
curr_map->map_ip = identity__map_ip; curr_map->map_ip = identity__map_ip;
curr_map->unmap_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip;
curr_dso->origin = DSO__ORIG_KERNEL; curr_dso->origin = DSO__ORIG_KERNEL;
map_groups__insert(kmaps, curr_map); map_groups__insert(&session->kmaps, curr_map);
dsos__add(&dsos__kernel, curr_dso); dsos__add(&dsos__kernel, curr_dso);
} else } else
curr_dso = curr_map->dso; curr_dso = curr_map->dso;
@ -1211,7 +1202,8 @@ char dso__symtab_origin(const struct dso *self)
return origin[self->origin]; return origin[self->origin];
} }
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) int dso__load(struct dso *self, struct map *map, struct perf_session *session,
symbol_filter_t filter)
{ {
int size = PATH_MAX; int size = PATH_MAX;
char *name; char *name;
@ -1222,7 +1214,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
dso__set_loaded(self, map->type); dso__set_loaded(self, map->type);
if (self->kernel) if (self->kernel)
return dso__load_kernel_sym(self, map, kmaps, filter); return dso__load_kernel_sym(self, map, session, filter);
name = malloc(size); name = malloc(size);
if (!name) if (!name)
@ -1323,7 +1315,7 @@ struct map *map_groups__find_by_name(struct map_groups *self,
return NULL; return NULL;
} }
static int dsos__set_modules_path_dir(char *dirname) static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
{ {
struct dirent *dent; struct dirent *dent;
DIR *dir = opendir(dirname); DIR *dir = opendir(dirname);
@ -1343,7 +1335,7 @@ static int dsos__set_modules_path_dir(char *dirname)
snprintf(path, sizeof(path), "%s/%s", snprintf(path, sizeof(path), "%s/%s",
dirname, dent->d_name); dirname, dent->d_name);
if (dsos__set_modules_path_dir(path) < 0) if (perf_session__set_modules_path_dir(self, path) < 0)
goto failure; goto failure;
} else { } else {
char *dot = strrchr(dent->d_name, '.'), char *dot = strrchr(dent->d_name, '.'),
@ -1357,7 +1349,7 @@ static int dsos__set_modules_path_dir(char *dirname)
(int)(dot - dent->d_name), dent->d_name); (int)(dot - dent->d_name), dent->d_name);
strxfrchar(dso_name, '-', '_'); strxfrchar(dso_name, '-', '_');
map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
if (map == NULL) if (map == NULL)
continue; continue;
@ -1377,7 +1369,7 @@ failure:
return -1; return -1;
} }
static int dsos__set_modules_path(void) static int perf_session__set_modules_path(struct perf_session *self)
{ {
struct utsname uts; struct utsname uts;
char modules_path[PATH_MAX]; char modules_path[PATH_MAX];
@ -1388,7 +1380,7 @@ static int dsos__set_modules_path(void)
snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
uts.release); uts.release);
return dsos__set_modules_path_dir(modules_path); return perf_session__set_modules_path_dir(self, modules_path);
} }
/* /*
@ -1410,7 +1402,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
return self; return self;
} }
static int map_groups__create_module_maps(struct map_groups *self) static int perf_session__create_module_maps(struct perf_session *self)
{ {
char *line = NULL; char *line = NULL;
size_t n; size_t n;
@ -1467,14 +1459,14 @@ static int map_groups__create_module_maps(struct map_groups *self)
dso->has_build_id = true; dso->has_build_id = true;
dso->origin = DSO__ORIG_KMODULE; dso->origin = DSO__ORIG_KMODULE;
map_groups__insert(self, map); map_groups__insert(&self->kmaps, map);
dsos__add(&dsos__kernel, dso); dsos__add(&dsos__kernel, dso);
} }
free(line); free(line);
fclose(file); fclose(file);
return dsos__set_modules_path(); return perf_session__set_modules_path(self);
out_delete_line: out_delete_line:
free(line); free(line);
@ -1483,7 +1475,7 @@ out_failure:
} }
static int dso__load_vmlinux(struct dso *self, struct map *map, static int dso__load_vmlinux(struct dso *self, struct map *map,
struct map_groups *mg, struct perf_session *session,
const char *vmlinux, symbol_filter_t filter) const char *vmlinux, symbol_filter_t filter)
{ {
int err = -1, fd; int err = -1, fd;
@ -1517,14 +1509,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
return -1; return -1;
dso__set_loaded(self, map->type); dso__set_loaded(self, map->type);
err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
close(fd); close(fd);
return err; return err;
} }
static int dso__load_kernel_sym(struct dso *self, struct map *map, static int dso__load_kernel_sym(struct dso *self, struct map *map,
struct map_groups *mg, symbol_filter_t filter) struct perf_session *session, symbol_filter_t filter)
{ {
int err; int err;
bool is_kallsyms; bool is_kallsyms;
@ -1534,7 +1526,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
pr_debug("Looking at the vmlinux_path (%d entries long)\n", pr_debug("Looking at the vmlinux_path (%d entries long)\n",
vmlinux_path__nr_entries); vmlinux_path__nr_entries);
for (i = 0; i < vmlinux_path__nr_entries; ++i) { for (i = 0; i < vmlinux_path__nr_entries; ++i) {
err = dso__load_vmlinux(self, map, mg, err = dso__load_vmlinux(self, map, session,
vmlinux_path[i], filter); vmlinux_path[i], filter);
if (err > 0) { if (err > 0) {
pr_debug("Using %s for symbols\n", pr_debug("Using %s for symbols\n",
@ -1550,12 +1542,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
if (is_kallsyms) if (is_kallsyms)
goto do_kallsyms; goto do_kallsyms;
err = dso__load_vmlinux(self, map, mg, self->long_name, filter); err = dso__load_vmlinux(self, map, session, self->long_name, filter);
if (err <= 0) { if (err <= 0) {
pr_info("The file %s cannot be used, " pr_info("The file %s cannot be used, "
"trying to use /proc/kallsyms...", self->long_name); "trying to use /proc/kallsyms...", self->long_name);
do_kallsyms: do_kallsyms:
err = dso__load_kallsyms(self, map, mg, filter); err = dso__load_kallsyms(self, map, session, filter);
if (err > 0 && !is_kallsyms) if (err > 0 && !is_kallsyms)
dso__set_long_name(self, strdup("[kernel.kallsyms]")); dso__set_long_name(self, strdup("[kernel.kallsyms]"));
} }
@ -1757,23 +1749,30 @@ int symbol__init(struct symbol_conf *conf)
if (pconf->sort_by_name) if (pconf->sort_by_name)
symbol__priv_size += (sizeof(struct symbol_name_rb_node) - symbol__priv_size += (sizeof(struct symbol_name_rb_node) -
sizeof(struct symbol)); sizeof(struct symbol));
map_groups__init(kmaps);
if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
return -1; return -1;
if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { return 0;
vmlinux_path__exit(); }
return -1;
}
kmaps->use_modules = pconf->use_modules; int perf_session__create_kernel_maps(struct perf_session *self,
if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) struct symbol_conf *conf)
pr_debug("Failed to load list of modules in use, " {
"continuing...\n"); const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
if (map_groups__create_kernel_maps(&self->kmaps,
pconf->vmlinux_name) < 0)
return -1;
self->use_modules = pconf->use_modules;
if (pconf->use_modules && perf_session__create_module_maps(self) < 0)
pr_debug("Failed to load list of modules for session %s, "
"continuing...\n", self->filename);
/* /*
* Now that we have all the maps created, just set the ->end of them: * Now that we have all the maps created, just set the ->end of them:
*/ */
map_groups__fixup_end(kmaps); map_groups__fixup_end(&self->kmaps);
return 0; return 0;
} }

View file

@ -98,8 +98,11 @@ 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); void dso__sort_by_name(struct dso *self, enum map_type type);
struct perf_session;
struct dso *dsos__findnew(const char *name); struct dso *dsos__findnew(const char *name);
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); int dso__load(struct dso *self, struct map *map, struct perf_session *session,
symbol_filter_t filter);
void dsos__fprintf(FILE *fp); void dsos__fprintf(FILE *fp);
size_t dsos__fprintf_buildid(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp);
@ -116,12 +119,10 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
bool dsos__read_build_ids(void); bool dsos__read_build_ids(void);
int build_id__sprintf(u8 *self, int len, char *bf); int build_id__sprintf(u8 *self, int len, char *bf);
size_t kernel_maps__fprintf(FILE *fp);
int symbol__init(struct symbol_conf *conf); int symbol__init(struct symbol_conf *conf);
int perf_session__create_kernel_maps(struct perf_session *self,
struct symbol_conf *conf);
struct map_groups;
struct map_groups *kmaps;
extern struct list_head dsos__user, dsos__kernel; extern struct list_head dsos__user, dsos__kernel;
extern struct dso *vdso; extern struct dso *vdso;
#endif /* __PERF_SYMBOL */ #endif /* __PERF_SYMBOL */

View file

@ -282,13 +282,14 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
} }
struct symbol *map_groups__find_symbol(struct map_groups *self, struct symbol *map_groups__find_symbol(struct map_groups *self,
struct perf_session *session,
enum map_type type, u64 addr, enum map_type type, u64 addr,
symbol_filter_t filter) symbol_filter_t filter)
{ {
struct map *map = map_groups__find(self, type, addr); struct map *map = map_groups__find(self, type, addr);
if (map != NULL) if (map != NULL)
return map__find_symbol(map, map->map_ip(map, addr), filter); return map__find_symbol(map, session, map->map_ip(map, addr), filter);
return NULL; return NULL;
} }

View file

@ -8,7 +8,6 @@
struct map_groups { struct map_groups {
struct rb_root maps[MAP__NR_TYPES]; struct rb_root maps[MAP__NR_TYPES];
struct list_head removed_maps[MAP__NR_TYPES]; struct list_head removed_maps[MAP__NR_TYPES];
bool use_modules;
}; };
struct thread { struct thread {
@ -49,19 +48,21 @@ static inline struct map *thread__find_map(struct thread *self,
return self ? map_groups__find(&self->mg, type, addr) : NULL; return self ? map_groups__find(&self->mg, type, addr) : NULL;
} }
void thread__find_addr_location(struct thread *self, u8 cpumode, void thread__find_addr_location(struct thread *self,
struct perf_session *session, u8 cpumode,
enum map_type type, u64 addr, enum map_type type, u64 addr,
struct addr_location *al, struct addr_location *al,
symbol_filter_t filter); symbol_filter_t filter);
struct symbol *map_groups__find_symbol(struct map_groups *self, struct symbol *map_groups__find_symbol(struct map_groups *self,
struct perf_session *session,
enum map_type type, u64 addr, enum map_type type, u64 addr,
symbol_filter_t filter); symbol_filter_t filter);
static inline struct symbol * static inline struct symbol *
map_groups__find_function(struct map_groups *self, u64 addr, map_groups__find_function(struct map_groups *self, struct perf_session *session,
symbol_filter_t filter) u64 addr, symbol_filter_t filter)
{ {
return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
} }
struct map *map_groups__find_by_name(struct map_groups *self, struct map *map_groups__find_by_name(struct map_groups *self,