summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoren Sandmann <sandmann@redhat.com>2008-03-20 09:49:46 +0000
committerSøren Sandmann Pedersen <ssp@src.gnome.org>2008-03-20 09:49:46 +0000
commitc2de993836bd39cf921440d10a1b1a84c9367b20 (patch)
tree23932d6060ae940f605671f19186b83352f53f2b
parent83fd2bbc3167b8c60dd922fda9a0707003ec12f2 (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--ChangeLog5
-rw-r--r--collector.c22
-rw-r--r--module/sysprof-module.c97
-rw-r--r--module/sysprof-module.h4
-rw-r--r--process.c8
5 files changed, 106 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index d40ebf8..8add596 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/process.c b/process.c
index 0d5828c..fbb57ad 100644
--- a/process.c
+++ b/process.c
@@ -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;