diff options
author | Soren Sandmann <sandmann@redhat.com> | 2008-03-20 09:49:46 +0000 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@src.gnome.org> | 2008-03-20 09:49:46 +0000 |
commit | c2de993836bd39cf921440d10a1b1a84c9367b20 (patch) | |
tree | 23932d6060ae940f605671f19186b83352f53f2b | |
parent | 83fd2bbc3167b8c60dd922fda9a0707003ec12f2 (diff) |
Use kernel builtin tracer instead of copying everything ourselves.
2008-03-20 Soren Sandmann <sandmann@redhat.com>
* module/sysprof-module.c (trace_kernel): Use kernel builtin
tracer instead of copying everything ourselves.
svn path=/trunk/; revision=401
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | collector.c | 22 | ||||
-rw-r--r-- | module/sysprof-module.c | 97 | ||||
-rw-r--r-- | module/sysprof-module.h | 4 | ||||
-rw-r--r-- | process.c | 8 |
5 files changed, 106 insertions, 30 deletions
@@ -1,5 +1,10 @@ 2008-03-20 Soren Sandmann <sandmann@redhat.com> + * module/sysprof-module.c (trace_kernel): Use kernel builtin + tracer instead of copying everything ourselves. + +2008-03-20 Soren Sandmann <sandmann@redhat.com> + * module/sysprof-module.c: Support for 2.6.24 and newer 2008-02-23 Soren Sandmann <sandmann@redhat.com> diff --git a/collector.c b/collector.c index 9c4c62f..86f49ca 100644 --- a/collector.c +++ b/collector.c @@ -143,8 +143,7 @@ add_trace_to_stash (const SysprofStackTrace *trace, g_assert (a == n_addresses); #endif - stack_stash_add_trace ( - stash, addrs, a, 1); + stack_stash_add_trace (stash, addrs, a, 1); if (addrs != addrs_stack) g_free (addrs); @@ -195,6 +194,15 @@ collect_traces (Collector *collector) g_print ("-=-\n"); } #endif +#if 0 + { + int i; + g_print ("pid: %d (%d)\n", trace->pid, trace->n_addresses); + for (i=0; i < trace->n_kernel_words; ++i) + g_print ("rd: %08x\n", trace->kernel_stack[i]); + g_print ("-=-\n"); + } +#endif add_trace_to_stash (trace, collector->stash); @@ -403,7 +411,12 @@ lookup_symbol (Process *process, gpointer address, * legitimately be at offset 0. */ if (offset == 0 && !first_addr) + { +#if 0 + g_print ("rejecting callback: %s (%p)\n", sym, address); +#endif sym = NULL; + } /* If offset is greater than 4096, then what happened is most * likely that it is the address of something in the gap between the @@ -414,7 +427,12 @@ lookup_symbol (Process *process, gpointer address, * is, and act accordingly. Actually, we should look at /proc/modules */ if (offset > 4096) + { +#if 0 + g_print ("offset\n"); +#endif sym = NULL; + } } else { diff --git a/module/sysprof-module.c b/module/sysprof-module.c index 97b11b1..aac5155 100644 --- a/module/sysprof-module.c +++ b/module/sysprof-module.c @@ -30,6 +30,7 @@ #include <linux/proc_fs.h> #include <asm/uaccess.h> +#include <asm/stacktrace.h> #include <linux/poll.h> #include <linux/highmem.h> #include <linux/pagemap.h> @@ -151,40 +152,84 @@ nt_memcpy (void *dst, void *src, int n_bytes) #endif } +/* + * The functions backtrace_* are based on oprofile's backtrace.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * @author David Smith + */ +static void backtrace_warning_symbol(void *data, char *msg, + unsigned long symbol) +{ + /* Ignore warnings */ +} + +static void backtrace_warning(void *data, char *msg) +{ + /* Ignore warnings */ +} + +struct backtrace_info_t +{ + SysprofStackTrace *trace; + int pos; +}; + +static int backtrace_stack(void *data, char *name) +{ + /* Don't bother with IRQ stacks for now */ + return -1; +} + +static void backtrace_address(void *data, unsigned long addr, int reliable) +{ + struct backtrace_info_t *info = data; + + if (info->pos < SYSPROF_MAX_ADDRESSES && reliable) + info->trace->kernel_stack[info->pos++] = (void *)addr; +} + +const static struct stacktrace_ops backtrace_ops = { + .warning = backtrace_warning, + .warning_symbol = backtrace_warning_symbol, + .stack = backtrace_stack, + .address = backtrace_address, +}; + static struct pt_regs * -copy_kernel_stack (struct pt_regs *regs, - SysprofStackTrace *trace) +trace_kernel (struct pt_regs *regs, + SysprofStackTrace *trace) { - int n_bytes; - char *esp; + struct backtrace_info_t info; char *eos; - + unsigned long stack; + unsigned long bp; + trace->kernel_stack[0] = (void *)regs->REG_INS_PTR; - trace->n_kernel_words = 1; - /* The timer interrupt happened in kernel mode. When this - * happens the registers are pushed on the stack, _except_ - * esp. So we can't use regs->esp to copy the stack pointer. - * Instead we use the fact that the regs pointer itself - * points to the stack. + info.trace = trace; + info.pos = 1; + + stack = (unsigned long) ((char *)regs + sizeof (struct pt_regs)); +#ifdef CONFIG_FRAME_POINTER + /* We can't set it to 0, because then the stack trace will + * contain the stack of the timer interrupt */ - esp = (char *)regs + sizeof (struct pt_regs); - eos = (char *)current->thread.REG_STACK_PTR0 - - sizeof (struct pt_regs); - - n_bytes = minimum ((char *)eos - esp, - sizeof (trace->kernel_stack)); - - if (n_bytes > 0) { -#if 0 - nt_memcpy (&(trace->kernel_stack[1]), esp, n_bytes); + bp = regs->REG_FRAME_PTR; +#else + bp = 0; #endif - memcpy (&(trace->kernel_stack[1]), esp, n_bytes); - - trace->n_kernel_words += (n_bytes) / sizeof (void *); - } + + dump_trace(NULL, regs, stack, bp, &backtrace_ops, &info); + + trace->n_kernel_words = info.pos; /* Now trace the user stack */ + eos = (char *)current->thread.REG_STACK_PTR0 - sizeof (struct pt_regs); + return (struct pt_regs *)eos; } @@ -318,7 +363,7 @@ timer_notify (struct pt_regs *regs) trace->n_addresses = 0; if (!is_user) - regs = copy_kernel_stack (regs, trace); + regs = trace_kernel (regs, trace); trace->addresses[0] = (void *)regs->REG_INS_PTR; trace->n_addresses = 1; diff --git a/module/sysprof-module.h b/module/sysprof-module.h index d92886d..40bbade 100644 --- a/module/sysprof-module.h +++ b/module/sysprof-module.h @@ -25,11 +25,11 @@ typedef struct SysprofStackInfo SysprofStackInfo; typedef struct SysprofMmapArea SysprofMmapArea; #define SYSPROF_N_TRACES 64 -#define SYSPROF_MAX_ADDRESSES 1020 /* to make it three pages wide */ +#define SYSPROF_MAX_ADDRESSES 126 struct SysprofStackTrace { - void *kernel_stack[1024]; + void *kernel_stack[SYSPROF_MAX_ADDRESSES]; void *addresses[SYSPROF_MAX_ADDRESSES]; int n_kernel_words; int n_addresses; /* note: this can be 1 if the process was compiled @@ -662,6 +662,14 @@ process_lookup_kernel_symbol (gulong address, GArray *ksyms = get_kernel_symbols (); KernelSymbol *result; + if (offset) + { + /* If we don't have any offset, just return 1, so it doesn't + * look like a callback + */ + *offset = 1; + } + if (ksyms->len == 0) return NULL; |