perf_counter tools: Enable kernel module symbol loading in tools
Add the -m/--modules option to perf report and perf annotate, which enables live module symbol/image loading. To be used with -k/--vmlinux. (Also give perf annotate a -P/--full-paths option.) Signed-off-by: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1246514986.13293.48.camel@marge.simson.net> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
6cfcc53ed4
commit
429764873c
|
@ -43,6 +43,10 @@ static int dump_trace = 0;
|
||||||
|
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
|
||||||
|
static int modules;
|
||||||
|
|
||||||
|
static int full_paths;
|
||||||
|
|
||||||
static int print_line;
|
static int print_line;
|
||||||
|
|
||||||
static unsigned long page_size;
|
static unsigned long page_size;
|
||||||
|
@ -171,7 +175,7 @@ static int load_kernel(void)
|
||||||
if (!kernel_dso)
|
if (!kernel_dso)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, 0);
|
err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
|
||||||
if (err <= 0) {
|
if (err <= 0) {
|
||||||
dso__delete(kernel_dso);
|
dso__delete(kernel_dso);
|
||||||
kernel_dso = NULL;
|
kernel_dso = NULL;
|
||||||
|
@ -1268,19 +1272,25 @@ static void print_summary(char *filename)
|
||||||
|
|
||||||
static void annotate_sym(struct dso *dso, struct symbol *sym)
|
static void annotate_sym(struct dso *dso, struct symbol *sym)
|
||||||
{
|
{
|
||||||
char *filename = dso->name;
|
char *filename = dso->name, *d_filename;
|
||||||
u64 start, end, len;
|
u64 start, end, len;
|
||||||
char command[PATH_MAX*2];
|
char command[PATH_MAX*2];
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
if (!filename)
|
if (!filename)
|
||||||
return;
|
return;
|
||||||
if (dso == kernel_dso)
|
if (sym->module)
|
||||||
|
filename = sym->module->path;
|
||||||
|
else if (dso == kernel_dso)
|
||||||
filename = vmlinux;
|
filename = vmlinux;
|
||||||
|
|
||||||
start = sym->obj_start;
|
start = sym->obj_start;
|
||||||
if (!start)
|
if (!start)
|
||||||
start = sym->start;
|
start = sym->start;
|
||||||
|
if (full_paths)
|
||||||
|
d_filename = filename;
|
||||||
|
else
|
||||||
|
d_filename = basename(filename);
|
||||||
|
|
||||||
end = start + sym->end - sym->start + 1;
|
end = start + sym->end - sym->start + 1;
|
||||||
len = sym->end - sym->start;
|
len = sym->end - sym->start;
|
||||||
|
@ -1291,13 +1301,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n\n------------------------------------------------\n");
|
printf("\n\n------------------------------------------------\n");
|
||||||
printf(" Percent | Source code & Disassembly of %s\n", filename);
|
printf(" Percent | Source code & Disassembly of %s\n", d_filename);
|
||||||
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->name, sym, sym->name);
|
||||||
|
|
||||||
sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
|
sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
|
||||||
|
(u64)start, (u64)end, filename, filename);
|
||||||
|
|
||||||
if (verbose >= 3)
|
if (verbose >= 3)
|
||||||
printf("doing: %s\n", command);
|
printf("doing: %s\n", command);
|
||||||
|
@ -1472,8 +1483,12 @@ static const struct option options[] = {
|
||||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||||
"dump raw trace in ASCII"),
|
"dump raw trace in ASCII"),
|
||||||
OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
|
OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
|
||||||
|
OPT_BOOLEAN('m', "modules", &modules,
|
||||||
|
"load module symbols - WARNING: use only with -k and LIVE kernel"),
|
||||||
OPT_BOOLEAN('l', "print-line", &print_line,
|
OPT_BOOLEAN('l', "print-line", &print_line,
|
||||||
"print matching source lines (may be slow)"),
|
"print matching source lines (may be slow)"),
|
||||||
|
OPT_BOOLEAN('P', "full-paths", &full_paths,
|
||||||
|
"Don't shorten the displayed pathnames"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ static int dump_trace = 0;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
|
#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
|
||||||
|
|
||||||
|
static int modules;
|
||||||
|
|
||||||
static int full_paths;
|
static int full_paths;
|
||||||
|
|
||||||
static unsigned long page_size;
|
static unsigned long page_size;
|
||||||
|
@ -188,7 +190,7 @@ static int load_kernel(void)
|
||||||
if (!kernel_dso)
|
if (!kernel_dso)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, 0);
|
err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
|
||||||
if (err <= 0) {
|
if (err <= 0) {
|
||||||
dso__delete(kernel_dso);
|
dso__delete(kernel_dso);
|
||||||
kernel_dso = NULL;
|
kernel_dso = NULL;
|
||||||
|
@ -648,6 +650,9 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
|
||||||
ret += fprintf(fp, "[%c] %s",
|
ret += fprintf(fp, "[%c] %s",
|
||||||
self->dso == kernel_dso ? 'k' :
|
self->dso == kernel_dso ? 'k' :
|
||||||
self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
|
self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
|
||||||
|
|
||||||
|
if (self->sym->module)
|
||||||
|
ret += fprintf(fp, "\t[%s]", self->sym->module->name);
|
||||||
} else {
|
} else {
|
||||||
ret += fprintf(fp, "%#016llx", (u64)self->ip);
|
ret += fprintf(fp, "%#016llx", (u64)self->ip);
|
||||||
}
|
}
|
||||||
|
@ -1710,6 +1715,8 @@ static const struct option options[] = {
|
||||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||||
"dump raw trace in ASCII"),
|
"dump raw trace in ASCII"),
|
||||||
OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
|
OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
|
||||||
|
OPT_BOOLEAN('m', "modules", &modules,
|
||||||
|
"load module symbols - WARNING: use only with -k and LIVE kernel"),
|
||||||
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
||||||
"sort by key(s): pid, comm, dso, symbol, parent"),
|
"sort by key(s): pid, comm, dso, symbol, parent"),
|
||||||
OPT_BOOLEAN('P', "full-paths", &full_paths,
|
OPT_BOOLEAN('P', "full-paths", &full_paths,
|
||||||
|
|
|
@ -66,6 +66,7 @@ static unsigned int page_size;
|
||||||
static unsigned int mmap_pages = 16;
|
static unsigned int mmap_pages = 16;
|
||||||
static int freq = 0;
|
static int freq = 0;
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
|
static char *vmlinux = NULL;
|
||||||
|
|
||||||
static char *sym_filter;
|
static char *sym_filter;
|
||||||
static unsigned long filter_start;
|
static unsigned long filter_start;
|
||||||
|
@ -265,7 +266,10 @@ static void print_sym_table(void)
|
||||||
printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
|
printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
|
||||||
|
|
||||||
color_fprintf(stdout, color, "%4.1f%%", pcnt);
|
color_fprintf(stdout, color, "%4.1f%%", pcnt);
|
||||||
printf(" - %016llx : %s\n", sym->start, sym->name);
|
printf(" - %016llx : %s", sym->start, sym->name);
|
||||||
|
if (sym->module)
|
||||||
|
printf("\t[%s]", sym->module->name);
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,12 +363,13 @@ static int parse_symbols(void)
|
||||||
{
|
{
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
|
int modules = vmlinux ? 1 : 0;
|
||||||
|
|
||||||
kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
|
kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
|
||||||
if (kernel_dso == NULL)
|
if (kernel_dso == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1, 0) <= 0)
|
if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
|
||||||
goto out_delete_dso;
|
goto out_delete_dso;
|
||||||
|
|
||||||
node = rb_first(&kernel_dso->syms);
|
node = rb_first(&kernel_dso->syms);
|
||||||
|
@ -680,6 +685,7 @@ static const struct option options[] = {
|
||||||
"system-wide collection from all CPUs"),
|
"system-wide collection from all CPUs"),
|
||||||
OPT_INTEGER('C', "CPU", &profile_cpu,
|
OPT_INTEGER('C', "CPU", &profile_cpu,
|
||||||
"CPU to profile on"),
|
"CPU to profile on"),
|
||||||
|
OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
|
||||||
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
||||||
"number of mmap data pages"),
|
"number of mmap data pages"),
|
||||||
OPT_INTEGER('r', "realtime", &realtime_prio,
|
OPT_INTEGER('r', "realtime", &realtime_prio,
|
||||||
|
@ -709,6 +715,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
{
|
{
|
||||||
int counter;
|
int counter;
|
||||||
|
|
||||||
|
symbol__init();
|
||||||
|
|
||||||
page_size = sysconf(_SC_PAGE_SIZE);
|
page_size = sysconf(_SC_PAGE_SIZE);
|
||||||
|
|
||||||
argc = parse_options(argc, argv, options, top_usage, 0);
|
argc = parse_options(argc, argv, options, top_usage, 0);
|
||||||
|
|
Loading…
Reference in New Issue