sysprof r401 - in trunk: . module



Author: ssp
Date: Thu Mar 20 09:49:46 2008
New Revision: 401
URL: http://svn.gnome.org/viewvc/sysprof?rev=401&view=rev

Log:
 2008-03-20  Soren Sandmann <sandmann redhat com>
 
       * module/sysprof-module.c (trace_kernel): Use kernel builtin
       tracer instead of copying everything ourselves.



Modified:
   trunk/ChangeLog
   trunk/collector.c
   trunk/module/sysprof-module.c
   trunk/module/sysprof-module.h
   trunk/process.c

Modified: trunk/collector.c
==============================================================================
--- trunk/collector.c	(original)
+++ trunk/collector.c	Thu Mar 20 09:49:46 2008
@@ -143,8 +143,7 @@
     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 @@
 	    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 @@
 	 * 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 @@
 	 * is, and act accordingly. Actually, we should look at /proc/modules
 	 */
 	if (offset > 4096)
+	{
+#if 0
+	    g_print ("offset\n");
+#endif
 	    sym = NULL;
+	}
     }
     else
     {

Modified: trunk/module/sysprof-module.c
==============================================================================
--- trunk/module/sysprof-module.c	(original)
+++ trunk/module/sysprof-module.c	Thu Mar 20 09:49:46 2008
@@ -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 @@
 #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 @@
 	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;

Modified: trunk/module/sysprof-module.h
==============================================================================
--- trunk/module/sysprof-module.h	(original)
+++ trunk/module/sysprof-module.h	Thu Mar 20 09:49:46 2008
@@ -25,11 +25,11 @@
 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

Modified: trunk/process.c
==============================================================================
--- trunk/process.c	(original)
+++ trunk/process.c	Thu Mar 20 09:49:46 2008
@@ -662,6 +662,14 @@
     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;
     



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]