Commit 439d473b authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by Ingo Molnar

perf tools: Rewrite and improve support for kernel modules

Representing modules as struct map entries, backed by a DSO, etc,
using /proc/modules to find where the module is loaded.

DSOs now can have a short and long name, so that in verbose mode we
can show exactly which .ko or vmlinux image was used.

As kernel modules now are a DSO separate from the kernel, we can
ask for just the hits for a particular set of kernel modules, just
like we can do with shared libraries:

[root@doppio linux-2.6-tip]# perf report -n --vmlinux
/home/acme/git/build/tip-recvmmsg/vmlinux --modules --dsos \[drm\] | head -15
    84.58%      13266             Xorg  [k] drm_clflush_pages
     4.02%        630             Xorg  [k] trace_kmalloc.clone.0
     3.95%        619             Xorg  [k] drm_ioctl
     2.07%        324             Xorg  [k] drm_addbufs
     1.68%        263             Xorg  [k] drm_gem_close_ioctl
     0.77%        120             Xorg  [k] drm_setmaster_ioctl
     0.70%        110             Xorg  [k] drm_lastclose
     0.68%        106             Xorg  [k] drm_open
     0.54%         85             Xorg  [k] drm_mm_search_free
[root@doppio linux-2.6-tip]#

Specifying --dsos /lib/modules/2.6.31-tip/kernel/drivers/gpu/drm/drm.ko
would have the same effect. Allowing specifying just 'drm.ko' is left
for another patch.

Processing kallsyms so that per kernel module struct map are
instantiated was also left for another patch. That will allow
removing the module name from each of its symbols.

struct symbol was reduced by removing the ->module backpointer and
moving it (well now the map) to struct symbol_entry in perf top,
that is its only user right now.

The total linecount went down by ~500 lines.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Avi Kivity <avi@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 2ccdc450
...@@ -336,7 +336,6 @@ LIB_H += util/strlist.h ...@@ -336,7 +336,6 @@ LIB_H += util/strlist.h
LIB_H += util/run-command.h LIB_H += util/run-command.h
LIB_H += util/sigchain.h LIB_H += util/sigchain.h
LIB_H += util/symbol.h LIB_H += util/symbol.h
LIB_H += util/module.h
LIB_H += util/color.h LIB_H += util/color.h
LIB_H += util/values.h LIB_H += util/values.h
LIB_H += util/sort.h LIB_H += util/sort.h
...@@ -364,7 +363,6 @@ LIB_OBJS += util/usage.o ...@@ -364,7 +363,6 @@ LIB_OBJS += util/usage.o
LIB_OBJS += util/wrapper.o LIB_OBJS += util/wrapper.o
LIB_OBJS += util/sigchain.o LIB_OBJS += util/sigchain.o
LIB_OBJS += util/symbol.o LIB_OBJS += util/symbol.o
LIB_OBJS += util/module.o
LIB_OBJS += util/color.o LIB_OBJS += util/color.o
LIB_OBJS += util/pager.o LIB_OBJS += util/pager.o
LIB_OBJS += util/header.o LIB_OBJS += util/header.o
......
...@@ -63,6 +63,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) ...@@ -63,6 +63,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
return; return;
sym_size = sym->end - sym->start; sym_size = sym->end - sym->start;
ip = he->map->map_ip(he->map, ip);
offset = ip - sym->start; offset = ip - sym->start;
if (offset >= sym_size) if (offset >= sym_size)
...@@ -80,7 +81,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) ...@@ -80,7 +81,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
} }
static int static int
hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, hist_entry__add(struct thread *thread, struct map *map,
struct symbol *sym, u64 ip, char level) struct symbol *sym, u64 ip, char level)
{ {
struct rb_node **p = &hist.rb_node; struct rb_node **p = &hist.rb_node;
...@@ -89,7 +90,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, ...@@ -89,7 +90,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
struct hist_entry entry = { struct hist_entry entry = {
.thread = thread, .thread = thread,
.map = map, .map = map,
.dso = dso,
.sym = sym, .sym = sym,
.ip = ip, .ip = ip,
.level = level, .level = level,
...@@ -130,10 +130,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -130,10 +130,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{ {
char level; char level;
int show = 0; int show = 0;
struct dso *dso = NULL;
struct thread *thread; struct thread *thread;
u64 ip = event->ip.ip; u64 ip = event->ip.ip;
struct map *map = NULL; struct map *map = NULL;
struct symbol *sym = NULL;
thread = threads__findnew(event->ip.pid, &threads, &last_match); thread = threads__findnew(event->ip.pid, &threads, &last_match);
...@@ -155,32 +155,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -155,32 +155,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
if (event->header.misc & PERF_RECORD_MISC_KERNEL) { if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
show = SHOW_KERNEL; show = SHOW_KERNEL;
level = 'k'; level = 'k';
sym = kernel_maps__find_symbol(ip, &map);
dso = kernel_dso; dump_printf(" ...... dso: %s\n",
map ? map->dso->long_name : "<not found>");
dump_printf(" ...... dso: %s\n", dso->name);
} else if (event->header.misc & PERF_RECORD_MISC_USER) { } else if (event->header.misc & PERF_RECORD_MISC_USER) {
show = SHOW_USER; show = SHOW_USER;
level = '.'; level = '.';
map = thread__find_map(thread, ip); map = thread__find_map(thread, ip);
if (map != NULL) { if (map != NULL) {
got_map:
ip = map->map_ip(map, ip); ip = map->map_ip(map, ip);
dso = map->dso; sym = map->dso->find_symbol(map->dso, ip);
} else { } else {
/* /*
* If this is outside of all known maps, * If this is outside of all known maps,
* and is a negative address, try to look it * and is a negative address, try to look it
* up in the kernel dso, as it might be a * up in the kernel dso, as it might be a
* vsyscall (which executes in user-mode): * vsyscall or vdso (which executes in user-mode).
*
* XXX This is nasty, we should have a symbol list in
* the "[vdso]" dso, but for now lets use the old
* trick of looking in the whole kernel symbol list.
*/ */
if ((long long)ip < 0) if ((long long)ip < 0) {
dso = kernel_dso; map = kernel_map;
goto got_map;
}
} }
dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); dump_printf(" ...... dso: %s\n",
map ? map->dso->long_name : "<not found>");
} else { } else {
show = SHOW_HV; show = SHOW_HV;
level = 'H'; level = 'H';
...@@ -188,12 +191,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -188,12 +191,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
} }
if (show & show_mask) { if (show & show_mask) {
struct symbol *sym = NULL; if (hist_entry__add(thread, map, sym, ip, level)) {
if (dso)
sym = dso->find_symbol(dso, ip);
if (hist_entry__add(thread, map, dso, sym, ip, level)) {
fprintf(stderr, fprintf(stderr,
"problem incrementing symbol count, skipping event\n"); "problem incrementing symbol count, skipping event\n");
return -1; return -1;
...@@ -313,7 +311,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -313,7 +311,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
} }
static int static int
parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) parse_line(FILE *file, struct symbol *sym, u64 len)
{ {
char *line = NULL, *tmp, *tmp2; char *line = NULL, *tmp, *tmp2;
static const char *prev_line; static const char *prev_line;
...@@ -363,7 +361,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) ...@@ -363,7 +361,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
const char *color; const char *color;
struct sym_ext *sym_ext = sym->priv; struct sym_ext *sym_ext = sym->priv;
offset = line_ip - start; offset = line_ip - sym->start;
if (offset < len) if (offset < len)
hits = sym->hist[offset]; hits = sym->hist[offset];
...@@ -442,7 +440,7 @@ static void free_source_line(struct symbol *sym, int len) ...@@ -442,7 +440,7 @@ static void free_source_line(struct symbol *sym, int len)
/* Get the filename:line for the colored entries */ /* Get the filename:line for the colored entries */
static void static void
get_source_line(struct symbol *sym, u64 start, int len, const char *filename) get_source_line(struct symbol *sym, int len, const char *filename)
{ {
int i; int i;
char cmd[PATH_MAX * 2]; char cmd[PATH_MAX * 2];
...@@ -467,7 +465,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename) ...@@ -467,7 +465,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
if (sym_ext[i].percent <= 0.5) if (sym_ext[i].percent <= 0.5)
continue; continue;
offset = start + i; offset = sym->start + i;
sprintf(cmd, "addr2line -e %s %016llx", filename, offset); sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
fp = popen(cmd, "r"); fp = popen(cmd, "r");
if (!fp) if (!fp)
...@@ -519,31 +517,23 @@ static void print_summary(const char *filename) ...@@ -519,31 +517,23 @@ static void print_summary(const char *filename)
static void annotate_sym(struct dso *dso, struct symbol *sym) static void annotate_sym(struct dso *dso, struct symbol *sym)
{ {
const char *filename = dso->name, *d_filename; const char *filename = dso->long_name, *d_filename;
u64 start, end, len; u64 len;
char command[PATH_MAX*2]; char command[PATH_MAX*2];
FILE *file; FILE *file;
if (!filename) if (!filename)
return; return;
if (sym->module)
filename = sym->module->path;
else if (dso == kernel_dso)
filename = vmlinux_name;
start = sym->obj_start;
if (!start)
start = sym->start;
if (full_paths) if (full_paths)
d_filename = filename; d_filename = filename;
else else
d_filename = basename(filename); d_filename = basename(filename);
end = start + sym->end - sym->start + 1;
len = sym->end - sym->start; len = sym->end - sym->start;
if (print_line) { if (print_line) {
get_source_line(sym, start, len, filename); get_source_line(sym, len, filename);
print_summary(filename); print_summary(filename);
} }
...@@ -552,10 +542,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) ...@@ -552,10 +542,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
printf("------------------------------------------------\n"); printf("------------------------------------------------\n");
if (verbose >= 2) if (verbose >= 2)
printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); printf("annotating [%p] %30s : [%p] %30s\n",
dso, dso->long_name, sym, sym->name);
sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
(u64)start, (u64)end, filename, filename); sym->start, sym->end, filename, filename);
if (verbose >= 3) if (verbose >= 3)
printf("doing: %s\n", command); printf("doing: %s\n", command);
...@@ -565,7 +556,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) ...@@ -565,7 +556,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
return; return;
while (!feof(file)) { while (!feof(file)) {
if (parse_line(file, sym, start, len) < 0) if (parse_line(file, sym, len) < 0)
break; break;
} }
......
...@@ -349,22 +349,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm) ...@@ -349,22 +349,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
static struct symbol * static struct symbol *
resolve_symbol(struct thread *thread, struct map **mapp, resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
struct dso **dsop, u64 *ipp)
{ {
struct dso *dso = dsop ? *dsop : NULL;
struct map *map = mapp ? *mapp : NULL; struct map *map = mapp ? *mapp : NULL;
u64 ip = *ipp; u64 ip = *ipp;
if (!thread)
return NULL;
if (dso)
goto got_dso;
if (map) if (map)
goto got_map; goto got_map;
if (!thread)
return NULL;
map = thread__find_map(thread, ip); map = thread__find_map(thread, ip);
if (map != NULL) { if (map != NULL) {
/* /*
...@@ -379,29 +374,29 @@ resolve_symbol(struct thread *thread, struct map **mapp, ...@@ -379,29 +374,29 @@ resolve_symbol(struct thread *thread, struct map **mapp,
*mapp = map; *mapp = map;
got_map: got_map:
ip = map->map_ip(map, ip); ip = map->map_ip(map, ip);
dso = map->dso;
} else { } else {
/* /*
* If this is outside of all known maps, * If this is outside of all known maps,
* and is a negative address, try to look it * and is a negative address, try to look it
* up in the kernel dso, as it might be a * up in the kernel dso, as it might be a
* vsyscall (which executes in user-mode): * vsyscall or vdso (which executes in user-mode).
*
* XXX This is nasty, we should have a symbol list in
* the "[vdso]" dso, but for now lets use the old
* trick of looking in the whole kernel symbol list.
*/ */
if ((long long)ip < 0) if ((long long)ip < 0) {
dso = kernel_dso; map = kernel_map;
if (mapp)
*mapp = map;
}
} }
dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); dump_printf(" ...... dso: %s\n",
map ? map->dso->long_name : "<not found>");
dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
*ipp = ip; *ipp = ip;
if (dsop) return map ? map->dso->find_symbol(map->dso, ip) : NULL;
*dsop = dso;
if (!dso)
return NULL;
got_dso:
return dso->find_symbol(dso, ip);
} }
static int call__match(struct symbol *sym) static int call__match(struct symbol *sym)
...@@ -413,7 +408,7 @@ static int call__match(struct symbol *sym) ...@@ -413,7 +408,7 @@ static int call__match(struct symbol *sym)
} }
static struct symbol ** static struct symbol **
resolve_callchain(struct thread *thread, struct map *map __used, resolve_callchain(struct thread *thread, struct map *map,
struct ip_callchain *chain, struct hist_entry *entry) struct ip_callchain *chain, struct hist_entry *entry)
{ {
u64 context = PERF_CONTEXT_MAX; u64 context = PERF_CONTEXT_MAX;
...@@ -430,8 +425,7 @@ resolve_callchain(struct thread *thread, struct map *map __used, ...@@ -430,8 +425,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
for (i = 0; i < chain->nr; i++) { for (i = 0; i < chain->nr; i++) {
u64 ip = chain->ips[i]; u64 ip = chain->ips[i];
struct dso *dso = NULL; struct symbol *sym = NULL;
struct symbol *sym;
if (ip >= PERF_CONTEXT_MAX) { if (ip >= PERF_CONTEXT_MAX) {
context = ip; context = ip;
...@@ -440,17 +434,15 @@ resolve_callchain(struct thread *thread, struct map *map __used, ...@@ -440,17 +434,15 @@ resolve_callchain(struct thread *thread, struct map *map __used,
switch (context) { switch (context) {
case PERF_CONTEXT_HV: case PERF_CONTEXT_HV:
dso = hypervisor_dso;
break; break;
case PERF_CONTEXT_KERNEL: case PERF_CONTEXT_KERNEL:
dso = kernel_dso; sym = kernel_maps__find_symbol(ip, &map);
break; break;
default: default:
sym = resolve_symbol(thread, &map, &ip);
break; break;
} }
sym = resolve_symbol(thread, NULL, &dso, &ip);
if (sym) { if (sym) {
if (sort__has_parent && call__match(sym) && if (sort__has_parent && call__match(sym) &&
!entry->parent) !entry->parent)
...@@ -469,7 +461,7 @@ resolve_callchain(struct thread *thread, struct map *map __used, ...@@ -469,7 +461,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
*/ */
static int static int
hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, hist_entry__add(struct thread *thread, struct map *map,
struct symbol *sym, u64 ip, struct ip_callchain *chain, struct symbol *sym, u64 ip, struct ip_callchain *chain,
char level, u64 count) char level, u64 count)
{ {
...@@ -480,7 +472,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, ...@@ -480,7 +472,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
struct hist_entry entry = { struct hist_entry entry = {
.thread = thread, .thread = thread,
.map = map, .map = map,
.dso = dso,
.sym = sym, .sym = sym,
.ip = ip, .ip = ip,
.level = level, .level = level,
...@@ -641,7 +632,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -641,7 +632,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{ {
char level; char level;
int show = 0; int show = 0;
struct dso *dso = NULL; struct symbol *sym = NULL;
struct thread *thread; struct thread *thread;
u64 ip = event->ip.ip; u64 ip = event->ip.ip;
u64 period = 1; u64 period = 1;
...@@ -700,35 +691,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -700,35 +691,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
show = SHOW_KERNEL; show = SHOW_KERNEL;
level = 'k'; level = 'k';
dso = kernel_dso; sym = kernel_maps__find_symbol(ip, &map);
dump_printf(" ...... dso: %s\n",
dump_printf(" ...... dso: %s\n", dso->name); map ? map->dso->long_name : "<not found>");
} else if (cpumode == PERF_RECORD_MISC_USER) { } else if (cpumode == PERF_RECORD_MISC_USER) {
show = SHOW_USER; show = SHOW_USER;
level = '.'; level = '.';
sym = resolve_symbol(thread, &map, &ip);
} else { } else {
show = SHOW_HV; show = SHOW_HV;
level = 'H'; level = 'H';
dso = hypervisor_dso;
dump_printf(" ...... dso: [hypervisor]\n"); dump_printf(" ...... dso: [hypervisor]\n");
} }
if (show & show_mask) { if (show & show_mask) {
struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); if (dso_list &&
(!map || !map->dso ||
if (dso_list && (!dso || !dso->name || !(strlist__has_entry(dso_list, map->dso->short_name) ||
!strlist__has_entry(dso_list, dso->name))) (map->dso->short_name != map->dso->long_name &&
strlist__has_entry(dso_list, map->dso->long_name)))))
return 0; return 0;
if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
return 0; return 0;
if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { if (hist_entry__add(thread, map, sym, ip,
chain, level, period)) {
eprintf("problem incrementing symbol count, skipping event\n"); eprintf("problem incrementing symbol count, skipping event\n");
return -1; return -1;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "util/symbol.h" #include "util/symbol.h"
#include "util/color.h" #include "util/color.h"
#include "util/thread.h"
#include "util/util.h" #include "util/util.h"
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include "util/parse-options.h" #include "util/parse-options.h"
...@@ -103,6 +104,7 @@ struct sym_entry { ...@@ -103,6 +104,7 @@ struct sym_entry {
unsigned long snap_count; unsigned long snap_count;
double weight; double weight;
int skip; int skip;
struct map *map;
struct source_line *source; struct source_line *source;
struct source_line *lines; struct source_line *lines;
struct source_line **lines_tail; struct source_line **lines_tail;
...@@ -116,12 +118,11 @@ struct sym_entry { ...@@ -116,12 +118,11 @@ struct sym_entry {
static void parse_source(struct sym_entry *syme) static void parse_source(struct sym_entry *syme)
{ {
struct symbol *sym; struct symbol *sym;
struct module *module; struct map *map;
struct section *section = NULL;
FILE *file; FILE *file;
char command[PATH_MAX*2]; char command[PATH_MAX*2];
const char *path = vmlinux_name; const char *path;
u64 start, end, len; u64 len;
if (!syme) if (!syme)
return; return;
...@@ -132,27 +133,15 @@ static void parse_source(struct sym_entry *syme) ...@@ -132,27 +133,15 @@ static void parse_source(struct sym_entry *syme)
} }
sym = (struct symbol *)(syme + 1); sym = (struct symbol *)(syme + 1);
module = sym->module; map = syme->map;
path = map->dso->long_name;
if (module)
path = module->path;
if (!path)
return;
start = sym->obj_start;
if (!start)
start = sym->start;
if (module) {
section = module->sections->find_section(module->sections, ".text");
if (section)
start -= section->vma;
}
end = start + sym->end - sym->start + 1;
len = sym->end - sym->start; len = sym->end - sym->start;
sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); sprintf(command,
"objdump --start-address=0x%016Lx "
"--stop-address=0x%016Lx -dS %s",
sym->start, sym->end, path);
file = popen(command, "r"); file = popen(command, "r");
if (!file) if (!file)
...@@ -184,13 +173,11 @@ static void parse_source(struct sym_entry *syme) ...@@ -184,13 +173,11 @@ static void parse_source(struct sym_entry *syme)
if (strlen(src->line)>8 && src->line[8] == ':') { if (strlen(src->line)>8 && src->line[8] == ':') {
src->eip = strtoull(src->line, NULL, 16); src->eip = strtoull(src->line, NULL, 16);
if (section) src->eip += map->start;
src->eip += section->vma;
} }
if (strlen(src->line)>8 && src->line[16] == ':') { if (strlen(src->line)>8 && src->line[16] == ':') {
src->eip = strtoull(src->line, NULL, 16); src->eip = strtoull(src->line, NULL, 16);
if (section) src->eip += map->start;
src->eip += section->vma;
} }
} }
pclose(file); pclose(file);
...@@ -242,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme) ...@@ -242,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme)
struct symbol *symbol = (struct symbol *)(syme + 1); struct symbol *symbol = (struct symbol *)(syme + 1);
struct source_line *line; struct source_line *line;
char pattern[PATH_MAX]; char pattern[PATH_MAX];
char *idx;
sprintf(pattern, "<%s>:", symbol->name); sprintf(pattern, "<%s>:", symbol->name);
if (symbol->module) {
idx = strstr(pattern, "\t");
if (idx)
*idx = 0;
}
pthread_mutex_lock(&syme->source_lock); pthread_mutex_lock(&syme->source_lock);
for (line = syme->lines; line; line = line->next) { for (line = syme->lines; line; line = line->next) {
if (strstr(line->line, pattern)) { if (strstr(line->line, pattern)) {
...@@ -513,8 +493,8 @@ static void print_sym_table(void) ...@@ -513,8 +493,8 @@ static void print_sym_table(void)
if (verbose) if (verbose)
printf(" - %016llx", sym->start); printf(" - %016llx", sym->start);
printf(" : %s", sym->name); printf(" : %s", sym->name);
if (sym->module) if (syme->map->dso->name[0] == '[')
printf("\t[%s]", sym->module->name); printf(" \t%s", syme->map->dso->name);
printf("\n"); printf("\n");
} }
} }
...@@ -784,7 +764,7 @@ static const char *skip_symbols[] = { ...@@ -784,7 +764,7 @@ static const char *skip_symbols[] = {
NULL NULL
}; };
static int symbol_filter(struct dso *self, struct symbol *sym) static int symbol_filter(struct map *map, struct symbol *sym)
{ {
struct sym_entry *syme; struct sym_entry *syme;
const char *name = sym->name; const char *name = sym->name;
...@@ -806,7 +786,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym) ...@@ -806,7 +786,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
strstr(name, "_text_end")) strstr(name, "_text_end"))
return 1; return 1;
syme = dso__sym_priv(self, sym); syme = dso__sym_priv(map->dso, sym);
syme->map = map;
pthread_mutex_init(&syme->source_lock, NULL); pthread_mutex_init(&syme->source_lock, NULL);
if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
sym_filter_entry = syme; sym_filter_entry = syme;
...@@ -825,22 +806,14 @@ static int parse_symbols(void) ...@@ -825,22 +806,14 @@ static int parse_symbols(void)
{ {
int use_modules = vmlinux_name ? 1 : 0; int use_modules = vmlinux_name ? 1 : 0;
kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
if (kernel_dso == NULL) symbol_filter, verbose, use_modules) <= 0)
return -1; return -1;
if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
goto out_delete_dso;
if (dump_symtab) if (dump_symtab)
dso__fprintf(kernel_dso, stderr); dsos__fprintf(stderr);
return 0; return 0;
out_delete_dso:
dso__delete(kernel_dso);
kernel_dso = NULL;
return -1;
} }
/* /*
...@@ -848,10 +821,11 @@ static int parse_symbols(void) ...@@ -848,10 +821,11 @@ static int parse_symbols(void)
*/ */
static void record_ip(u64 ip, int counter) static void record_ip(u64 ip, int counter)
{ {
struct symbol *sym = dso__find_symbol(kernel_dso, ip); struct map *map;
struct symbol *sym = kernel_maps__find_symbol(ip, &map);
if (sym != NULL) { if (sym != NULL) {
struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); struct sym_entry *syme = dso__sym_priv(map->dso, sym);
if (!syme->skip) { if (!syme->skip) {
syme->count[counter]++; syme->count[counter]++;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "../perf.h" #include "../perf.h"
#include "util.h" #include "util.h"
#include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
enum { enum {
...@@ -79,7 +80,10 @@ typedef union event_union { ...@@ -79,7 +80,10 @@ typedef union event_union {
} event_t; } event_t;
struct map { struct map {
struct rb_node rb_node; union {
struct rb_node rb_node;
struct list_head node;
};
u64 start; u64 start;
u64 end; u64 end;
u64 pgoff; u64 pgoff;
......
This diff is collapsed.
#ifndef __PERF_MODULE_
#define __PERF_MODULE_ 1
#include <linux/types.h>
#include "../types.h"
#include <linux/list.h>
#include <linux/rbtree.h>
struct section {
struct rb_node rb_node;
u64 hash;
u64 vma;
char *name;
char *path;
};
struct sec_dso {
struct list_head node;
struct rb_root secs;
struct section *(*find_section)(struct sec_dso *, const char *name);
char name[0];
};
struct module {
struct rb_node rb_node;
u64 hash;
char *name;
char *path;
struct sec_dso *sections;
int active;
};
struct mod_dso {
struct list_head node;
struct rb_root mods;
struct module *(*find_module)(struct mod_dso *, const char *name);
char name[0];
};
struct sec_dso *sec_dso__new_dso(const char *name);
void sec_dso__delete_sections(struct sec_dso *self);
void sec_dso__delete_self(struct sec_dso *self);
size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
struct mod_dso *mod_dso__new_dso(const char *name);
void mod_dso__delete_modules(struct mod_dso *self);
void mod_dso__delete_self(struct mod_dso *self);
size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
int mod_dso__load_modules(struct mod_dso *dso);
#endif /* __PERF_MODULE_ */
...@@ -129,20 +129,32 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) ...@@ -129,20 +129,32 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
int64_t int64_t
sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
struct dso *dso_l = left->dso; struct dso *dso_l = left->map ? left->map->dso : NULL;
struct dso *dso_r = right->dso; struct dso *dso_r = right->map ? right->map->dso : NULL;
const char *dso_name_l, *dso_name_r;
if (!dso_l || !dso_r) if (!dso_l || !dso_r)
return cmp_null(dso_l, dso_r); return cmp_null(dso_l, dso_r);
return strcmp(dso_l->name, dso_r->name); if (verbose) {
dso_name_l = dso_l->long_name;
dso_name_r = dso_r->long_name;
} else {
dso_name_l = dso_l->short_name;
dso_name_r = dso_r->short_name;
}
return strcmp(dso_name_l, dso_name_r);
} }
size_t size_t
sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
{ {
if (self->dso) if (self->map && self->map->dso) {
return repsep_fprintf(fp, "%-*s", width, self->dso->name); const char *dso_name = !verbose ? self->map->dso->short_name :
self->map->dso->long_name;
return repsep_fprintf(fp, "%-*s", width, dso_name);
}
return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
} }
...@@ -169,20 +181,16 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) ...@@ -169,20 +181,16 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
{ {
size_t ret = 0; size_t ret = 0;
if (verbose) if (verbose) {
ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
dso__symtab_origin(self->dso)); ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
}
ret += repsep_fprintf(fp, "[%c] ", self->level); ret += repsep_fprintf(fp, "[%c] ", self->level);
if (self->sym) { if (self->sym)
ret += repsep_fprintf(fp, "%s", self->sym->name); ret += repsep_fprintf(fp, "%s", self->sym->name);
else
if (self->sym->module)
ret += repsep_fprintf(fp, "\t[%s]",
self->sym->module->name);
} else {
ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
}
return ret; return ret;
} }
......
...@@ -42,18 +42,15 @@ extern unsigned int threads__col_width; ...@@ -42,18 +42,15 @@ extern unsigned int threads__col_width;
struct hist_entry { struct hist_entry {
struct rb_node rb_node; struct rb_node rb_node;
u64 count;
struct thread *thread; struct thread *thread;
struct map *map; struct map *map;
struct dso *dso;
struct symbol *sym; struct symbol *sym;
struct symbol *parent;
u64 ip; u64 ip;
char level; char level;
struct symbol *parent;
struct callchain_node callchain; struct callchain_node callchain;
struct rb_root sorted_chain; struct rb_root sorted_chain;
u64 count;
}; };
/* /*
......
This diff is collapsed.
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "types.h" #include "types.h"
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include "module.h"
#include "event.h" #include "event.h"
#ifdef HAVE_CPLUS_DEMANGLE #ifdef HAVE_CPLUS_DEMANGLE
...@@ -36,10 +35,8 @@ struct symbol { ...@@ -36,10 +35,8 @@ struct symbol {
struct rb_node rb_node; struct rb_node rb_node;
u64 start; u64 start;
u64 end; u64 end;
u64 obj_start;
u64 hist_sum; u64 hist_sum;
u64 *hist; u64 *hist;
struct module *module;
void *priv; void *priv;
char name[0]; char name[0];
}; };
...@@ -52,12 +49,14 @@ struct dso { ...@@ -52,12 +49,14 @@ struct dso {
unsigned char adjust_symbols; unsigned char adjust_symbols;
unsigned char slen_calculated; unsigned char slen_calculated;
unsigned char origin; unsigned char origin;
const char *short_name;
char *long_name;
char name[0]; char name[0];
}; };
extern const char *sym_hist_filter; extern const char *sym_hist_filter;
typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
struct dso *dso__new(const char *name, unsigned int sym_priv_size); struct dso *dso__new(const char *name, unsigned int sym_priv_size);
void dso__delete(struct dso *self); void dso__delete(struct dso *self);
...@@ -69,10 +68,12 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) ...@@ -69,10 +68,12 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
struct symbol *dso__find_symbol(struct dso *self, u64 ip); struct symbol *dso__find_symbol(struct dso *self, u64 ip);
int dso__load_kernel(struct dso *self, const char *vmlinux, int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
symbol_filter_t filter, int verbose, int modules); symbol_filter_t filter, int verbose, int modules);
int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter,
int dso__load(struct dso *self, symbol_filter_t filter, int verbose); int verbose);
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
int verbose);
struct dso *dsos__findnew(const char *name); struct dso *dsos__findnew(const char *name);
void dsos__fprintf(FILE *fp); void dsos__fprintf(FILE *fp);
...@@ -84,9 +85,8 @@ int load_kernel(void); ...@@ -84,9 +85,8 @@ int load_kernel(void);
void symbol__init(void); void symbol__init(void);
extern struct list_head dsos; extern struct list_head dsos;
extern struct dso *kernel_dso; extern struct map *kernel_map;
extern struct dso *vdso; extern struct dso *vdso;
extern struct dso *hypervisor_dso;
extern const char *vmlinux_name; extern const char *vmlinux_name;
extern int modules; extern int modules;
#endif /* __PERF_SYMBOL */ #endif /* __PERF_SYMBOL */
...@@ -16,6 +16,7 @@ static struct thread *thread__new(pid_t pid) ...@@ -16,6 +16,7 @@ static struct thread *thread__new(pid_t pid)
if (self->comm) if (self->comm)
snprintf(self->comm, 32, ":%d", self->pid); snprintf(self->comm, 32, ":%d", self->pid);
self->maps = RB_ROOT; self->maps = RB_ROOT;
INIT_LIST_HEAD(&self->removed_maps);
} }
return self; return self;
...@@ -32,13 +33,20 @@ int thread__set_comm(struct thread *self, const char *comm) ...@@ -32,13 +33,20 @@ int thread__set_comm(struct thread *self, const char *comm)
static size_t thread__fprintf(struct thread *self, FILE *fp) static size_t thread__fprintf(struct thread *self, FILE *fp)
{ {
struct rb_node *nd; struct rb_node *nd;
size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); struct map *pos;
size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
self->pid, self->comm);
for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node); pos = rb_entry(nd, struct map, rb_node);
ret += map__fprintf(pos, fp); ret += map__fprintf(pos, fp);
} }
ret = fprintf(fp, "Removed maps:\n");
list_for_each_entry(pos, &self->removed_maps, node)
ret += map__fprintf(pos, fp);
return ret; return ret;
} }
...@@ -112,21 +120,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) ...@@ -112,21 +120,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map)
map__fprintf(pos, stdout); map__fprintf(pos, stdout);
} }
if (map->start <= pos->start && map->end > pos->start) rb_erase(&pos->rb_node, &self->maps);
pos->start = map->end; /*
* We may have references to this map, for instance in some
if (map->end >= pos->end && map->start < pos->end) * hist_entry instances, so just move them to a separate
pos->end = map->start; * list.
*/
if (verbose >= 2) { list_add_tail(&pos->node, &self->removed_maps);
printf("after collision:\n");
map__fprintf(pos, stdout);
}
if (pos->start >= pos->end) {
rb_erase(&pos->rb_node, &self->maps);
free(pos);
}
} }
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
struct thread { struct thread {
struct rb_node rb_node; struct rb_node rb_node;
struct rb_root maps; struct rb_root maps;
struct list_head removed_maps;
pid_t pid; pid_t pid;
char shortname[3]; char shortname[3];
char *comm; char *comm;
...@@ -25,6 +26,9 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads); ...@@ -25,6 +26,9 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads);
void maps__insert(struct rb_root *maps, struct map *map); void maps__insert(struct rb_root *maps, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 ip); struct map *maps__find(struct rb_root *maps, u64 ip);
struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
struct map *kernel_maps__find_by_dso_name(const char *name);
static inline struct map *thread__find_map(struct thread *self, u64 ip) static inline struct map *thread__find_map(struct thread *self, u64 ip)
{ {
return self ? maps__find(&self->maps, ip) : NULL; return self ? maps__find(&self->maps, ip) : NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment