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
This commit is contained in:
Soren Sandmann
2008-03-20 09:49:46 +00:00
committed by Søren Sandmann Pedersen
parent 83fd2bbc31
commit c2de993836
5 changed files with 107 additions and 31 deletions

View File

@ -1,3 +1,8 @@
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> 2008-03-20 Soren Sandmann <sandmann@redhat.com>
* module/sysprof-module.c: Support for 2.6.24 and newer * module/sysprof-module.c: Support for 2.6.24 and newer

View File

@ -143,8 +143,7 @@ add_trace_to_stash (const SysprofStackTrace *trace,
g_assert (a == n_addresses); g_assert (a == n_addresses);
#endif #endif
stack_stash_add_trace ( stack_stash_add_trace (stash, addrs, a, 1);
stash, addrs, a, 1);
if (addrs != addrs_stack) if (addrs != addrs_stack)
g_free (addrs); g_free (addrs);
@ -195,6 +194,15 @@ collect_traces (Collector *collector)
g_print ("-=-\n"); g_print ("-=-\n");
} }
#endif #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); add_trace_to_stash (trace, collector->stash);
@ -403,7 +411,12 @@ lookup_symbol (Process *process, gpointer address,
* legitimately be at offset 0. * legitimately be at offset 0.
*/ */
if (offset == 0 && !first_addr) if (offset == 0 && !first_addr)
{
#if 0
g_print ("rejecting callback: %s (%p)\n", sym, address);
#endif
sym = NULL; sym = NULL;
}
/* If offset is greater than 4096, then what happened is most /* If offset is greater than 4096, then what happened is most
* likely that it is the address of something in the gap between the * 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 * is, and act accordingly. Actually, we should look at /proc/modules
*/ */
if (offset > 4096) if (offset > 4096)
{
#if 0
g_print ("offset\n");
#endif
sym = NULL; sym = NULL;
}
} }
else else
{ {

View File

@ -30,6 +30,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/stacktrace.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
@ -151,40 +152,84 @@ nt_memcpy (void *dst, void *src, int n_bytes)
#endif #endif
} }
static struct pt_regs * /*
copy_kernel_stack (struct pt_regs *regs, * The functions backtrace_* are based on oprofile's backtrace.c
SysprofStackTrace *trace) *
* @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)
{ {
int n_bytes; /* Ignore warnings */
char *esp; }
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 *
trace_kernel (struct pt_regs *regs,
SysprofStackTrace *trace)
{
struct backtrace_info_t info;
char *eos; char *eos;
unsigned long stack;
unsigned long bp;
trace->kernel_stack[0] = (void *)regs->REG_INS_PTR; trace->kernel_stack[0] = (void *)regs->REG_INS_PTR;
trace->n_kernel_words = 1;
/* The timer interrupt happened in kernel mode. When this info.trace = trace;
* happens the registers are pushed on the stack, _except_ info.pos = 1;
* esp. So we can't use regs->esp to copy the stack pointer.
* Instead we use the fact that the regs pointer itself stack = (unsigned long) ((char *)regs + sizeof (struct pt_regs));
* points to the stack. #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); bp = regs->REG_FRAME_PTR;
eos = (char *)current->thread.REG_STACK_PTR0 - #else
sizeof (struct pt_regs); bp = 0;
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);
#endif #endif
memcpy (&(trace->kernel_stack[1]), esp, n_bytes);
dump_trace(NULL, regs, stack, bp, &backtrace_ops, &info);
trace->n_kernel_words += (n_bytes) / sizeof (void *);
} trace->n_kernel_words = info.pos;
/* Now trace the user stack */ /* Now trace the user stack */
eos = (char *)current->thread.REG_STACK_PTR0 - sizeof (struct pt_regs);
return (struct pt_regs *)eos; return (struct pt_regs *)eos;
} }
@ -318,7 +363,7 @@ timer_notify (struct pt_regs *regs)
trace->n_addresses = 0; trace->n_addresses = 0;
if (!is_user) if (!is_user)
regs = copy_kernel_stack (regs, trace); regs = trace_kernel (regs, trace);
trace->addresses[0] = (void *)regs->REG_INS_PTR; trace->addresses[0] = (void *)regs->REG_INS_PTR;
trace->n_addresses = 1; trace->n_addresses = 1;

View File

@ -25,11 +25,11 @@ typedef struct SysprofStackInfo SysprofStackInfo;
typedef struct SysprofMmapArea SysprofMmapArea; typedef struct SysprofMmapArea SysprofMmapArea;
#define SYSPROF_N_TRACES 64 #define SYSPROF_N_TRACES 64
#define SYSPROF_MAX_ADDRESSES 1020 /* to make it three pages wide */ #define SYSPROF_MAX_ADDRESSES 126
struct SysprofStackTrace struct SysprofStackTrace
{ {
void *kernel_stack[1024]; void *kernel_stack[SYSPROF_MAX_ADDRESSES];
void *addresses[SYSPROF_MAX_ADDRESSES]; void *addresses[SYSPROF_MAX_ADDRESSES];
int n_kernel_words; int n_kernel_words;
int n_addresses; /* note: this can be 1 if the process was compiled int n_addresses; /* note: this can be 1 if the process was compiled

View File

@ -662,6 +662,14 @@ process_lookup_kernel_symbol (gulong address,
GArray *ksyms = get_kernel_symbols (); GArray *ksyms = get_kernel_symbols ();
KernelSymbol *result; 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) if (ksyms->len == 0)
return NULL; return NULL;