perf events, x86/stacktrace: Fix performance/softlockup by providing a special frame...
Frederic Weisbecker [Thu, 17 Dec 2009 04:40:34 +0000 (05:40 +0100)]
It's just wasteful for stacktrace users like perf to walk
through every entries on the stack whereas these only accept
reliable ones, ie: that the frame pointer validates.

Since perf requires pure reliable stacktraces, it needs a stack
walker based on frame pointers-only to optimize the stacktrace
processing.

This might solve some near-lockup scenarios that can be triggered
by call-graph tracing timer events.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1261024834-5336-2-git-send-regression-fweisbec@gmail.com>
[ v2: fix for modular builds and small detail tidyup ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>

arch/x86/include/asm/stacktrace.h
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/dumpstack.c

index 6c75151..35e8912 100644 (file)
@@ -22,6 +22,12 @@ print_context_stack(struct thread_info *tinfo,
                    const struct stacktrace_ops *ops, void *data,
                    unsigned long *end, int *graph);
 
+extern unsigned long
+print_context_stack_bp(struct thread_info *tinfo,
+                      unsigned long *stack, unsigned long bp,
+                      const struct stacktrace_ops *ops, void *data,
+                      unsigned long *end, int *graph);
+
 /* Generic stack tracer with callbacks */
 
 struct stacktrace_ops {
index d3802ee..c223b7e 100644 (file)
@@ -2336,7 +2336,7 @@ static const struct stacktrace_ops backtrace_ops = {
        .warning_symbol         = backtrace_warning_symbol,
        .stack                  = backtrace_stack,
        .address                = backtrace_address,
-       .walk_stack             = print_context_stack,
+       .walk_stack             = print_context_stack_bp,
 };
 
 #include "../dumpstack.h"
index 8aaa119..c56bc28 100644 (file)
@@ -109,6 +109,30 @@ print_context_stack(struct thread_info *tinfo,
        }
        return bp;
 }
+EXPORT_SYMBOL_GPL(print_context_stack);
+
+unsigned long
+print_context_stack_bp(struct thread_info *tinfo,
+                      unsigned long *stack, unsigned long bp,
+                      const struct stacktrace_ops *ops, void *data,
+                      unsigned long *end, int *graph)
+{
+       struct stack_frame *frame = (struct stack_frame *)bp;
+       unsigned long *ret_addr = &frame->return_address;
+
+       while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) {
+               unsigned long addr = *ret_addr;
+
+               if (__kernel_text_address(addr)) {
+                       ops->address(data, addr, 1);
+                       frame = frame->next_frame;
+                       ret_addr = &frame->return_address;
+                       print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
+               }
+       }
+       return (unsigned long)frame;
+}
+EXPORT_SYMBOL_GPL(print_context_stack_bp);
 
 
 static void
@@ -143,8 +167,8 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
 static const struct stacktrace_ops print_trace_ops = {
        .warning                = print_trace_warning,
        .warning_symbol         = print_trace_warning_symbol,
-       .stack                  = print_trace_stack,
-       .address                = print_trace_address,
+       .stack                  = print_trace_stack,
+       .address                = print_trace_address,
        .walk_stack             = print_context_stack,
 };