summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2009-02-02 15:58:53 +0100
committerTim Moore <timoore@redhat.com>2009-02-11 18:20:20 +0100
commitbbc46bf643491173b9086907cf0820b3fd2c1fe3 (patch)
tree9b74716911ed9deb015b1f12c4e2f31ed90a8339
parent89dd03e34c2f890e9fbb065c74a60036aa480827 (diff)
downloadsystemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.tar.gz
systemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.tar.xz
systemtap-steved-bbc46bf643491173b9086907cf0820b3fd2c1fe3.zip
Use kernel stack backtrace support when available
Define new functions that use the kernel support to do a backtrace of other tasks than current.
-rw-r--r--runtime/ChangeLog9
-rw-r--r--runtime/stack-i386.c2
-rw-r--r--runtime/stack-x86_64.c6
-rw-r--r--runtime/stack.c87
-rw-r--r--testsuite/ChangeLog4
-rw-r--r--testsuite/systemtap.examples/profiling/latencytap.stp7
6 files changed, 113 insertions, 2 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 2eb1cdaf..35ce7c79 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,12 @@
+2009-02-11 Tim Moore <timoore@redhat.com>
+
+ * stack.c (_stp_stack_print_fallback): Implementation that uses kernel
+ stacktrace support if available.
+ (_stp_stack_print_tsk, _stp_stack_snprint_tsk): New functions.
+ * stack-x86_64.c (_stp_stack_print_fallback): Use our own fallback if
+ no kernel stacktrace support.
+ * stack-x86_64.c (_stp_stack_print_fallback): ditto.
+
2009-02-11 David Smith <dsmith@redhat.com>
* task_finder.c (__stp_utrace_attach): Still checks for mm after
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index ed7e2ce1..2d3ac53c 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -14,6 +14,7 @@ static int _stp_valid_stack_ptr(unsigned long context, unsigned long p)
}
/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */
+#ifndef CONFIG_STACKTRACE
static void _stp_stack_print_fallback(unsigned long context, unsigned long stack, int verbose, int levels)
{
unsigned long addr;
@@ -27,6 +28,7 @@ static void _stp_stack_print_fallback(unsigned long context, unsigned long stack
stack++;
}
}
+#endif
static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
{
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index d3ec91cf..060f370d 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -9,6 +9,8 @@
*/
/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */
+
+#ifndef CONFIG_STACKTRACE
static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels)
{
unsigned long addr;
@@ -22,6 +24,8 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
stack++;
}
}
+#endif
+
static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
{
@@ -48,3 +52,5 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
_stp_stack_print_fallback(REG_SP(regs), verbose, levels);
#endif
}
+
+
diff --git a/runtime/stack.c b/runtime/stack.c
index 7ca0e316..25d0817d 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -27,6 +27,11 @@
#define MAXBACKTRACE 20
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+
+static void _stp_stack_print_fallback(unsigned long, int, int);
+
#if defined (__x86_64__)
#include "stack-x86_64.c"
#elif defined (__ia64__)
@@ -43,6 +48,53 @@
#error "Unsupported architecture"
#endif
+#ifdef CONFIG_STACKTRACE
+
+struct print_stack_data
+{
+ int verbose;
+ int max_level;
+ int level;
+};
+
+static void print_stack_warning(void *data, char *msg)
+{
+}
+
+static void
+print_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+}
+
+static int print_stack_stack(void *data, char *name)
+{
+ return -1;
+}
+
+static void print_stack_address(void *data, unsigned long addr, int reliable)
+{
+ struct print_stack_data *sdata = data;
+ if (sdata->level++ < sdata->max_level)
+ _stp_func_print(addr,sdata->verbose, 0);
+}
+
+static const struct stacktrace_ops print_stack_ops = {
+ .warning = print_stack_warning,
+ .warning_symbol = print_stack_warning_symbol,
+ .stack = print_stack_stack,
+ .address = print_stack_address,
+};
+
+static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels)
+{
+ struct print_stack_data print_data;
+ print_data.verbose = verbose;
+ print_data.max_level = levels;
+ print_data.level = 0;
+ dump_trace(current, NULL, (long *)stack, 0, &print_stack_ops,
+ &print_data);
+}
+#endif
/** Prints the stack backtrace
* @param regs A pointer to the struct pt_regs.
*/
@@ -103,4 +155,39 @@ static void _stp_ustack_print(char *str)
#endif /* 0 */
/** @} */
+
+void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
+{
+#ifdef CONFIG_STACKTRACE
+ int i;
+ unsigned long backtrace[MAXBACKTRACE];
+ struct stack_trace trace;
+ int maxLevels = min(levels, MAXBACKTRACE);
+ memset(&trace, 0, sizeof(trace));
+ trace.entries = &backtrace[0];
+ trace.max_entries = maxLevels;
+ trace.skip = 0;
+ save_stack_trace_tsk(tsk, &trace);
+ for (i = 0; i < maxLevels; ++i) {
+ if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
+ break;
+ _stp_printf("%lx ", backtrace[i]);
+ }
+#endif
+}
+
+/** Writes a task stack backtrace to a string
+ *
+ * @param str string
+ * @param tsk A pointer to the task_struct
+ * @returns void
+ */
+void _stp_stack_snprint_tsk(char *str, int size, struct task_struct *tsk, int verbose, int levels)
+{
+ _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
+ _stp_print_flush();
+ _stp_stack_print_tsk(tsk, verbose, levels);
+ strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
+ pb->len = 0;
+}
#endif /* _STACK_C_ */
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index c2b1bb89..6afd1df8 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2009-02-11 Tim Moore <timoore@redhat.com>
+
+ * systemtap.examples/profiling/latencytap.stp: Use _stp_stack_snprint_tsk.
+
2009-02-10 Will Cohen <wcohen@redhat.com>
* systemtap.samples/profile.exp:
diff --git a/testsuite/systemtap.examples/profiling/latencytap.stp b/testsuite/systemtap.examples/profiling/latencytap.stp
index 96944858..28956129 100644
--- a/testsuite/systemtap.examples/profiling/latencytap.stp
+++ b/testsuite/systemtap.examples/profiling/latencytap.stp
@@ -22,8 +22,8 @@ function _get_sleep_time:long(rq_param:long, p_param:long)
# Get the backtrace from an arbitrary task
function task_backtrace:string (task:long)
%{
- _stp_stack_snprint(THIS->__retvalue, MAXSTRINGLEN,
- task_pt_regs((struct task_struct *)THIS->task), 0, 0, MAXTRACE);
+ _stp_stack_snprint_tsk(THIS->__retvalue, MAXSTRINGLEN,
+ (struct task_struct *)THIS->task, 0, MAXTRACE);
%}
probe kernel.function("enqueue_task_fair") {
@@ -41,6 +41,9 @@ global pid_sleep
probe timer.ms(1000) {
foreach ([pid, backtrace] in sleep_time) {
pid_sleep[pid] += sleep_time[pid, backtrace]
+ printf("%s %d:\n", process_names[pid], pid)
+ print_stack(backtrace)
+ printf("\n")
}
foreach ([pid+] in pid_sleep) {
printf("%s %d %d\n", process_names[pid], @max(sleep_agg[pid]) / 1000000, @avg(sleep_agg[pid]) / 1000000)