diff options
author | Tim Moore <timoore@redhat.com> | 2009-02-02 15:58:53 +0100 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2009-02-11 18:20:20 +0100 |
commit | bbc46bf643491173b9086907cf0820b3fd2c1fe3 (patch) | |
tree | 9b74716911ed9deb015b1f12c4e2f31ed90a8339 | |
parent | 89dd03e34c2f890e9fbb065c74a60036aa480827 (diff) | |
download | systemtap-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/ChangeLog | 9 | ||||
-rw-r--r-- | runtime/stack-i386.c | 2 | ||||
-rw-r--r-- | runtime/stack-x86_64.c | 6 | ||||
-rw-r--r-- | runtime/stack.c | 87 | ||||
-rw-r--r-- | testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | testsuite/systemtap.examples/profiling/latencytap.stp | 7 |
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) |