diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-12-16 23:40:34 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-17 04:42:52 -0500 |
commit | 06d65bda75341485d32f33da474b0664819ad497 (patch) | |
tree | 3b5edc58b9c5a6a9b5cff4b5886f54929b12863a /arch | |
parent | 61c1917f47f73c968e92d04d15370b1dc3ec4592 (diff) |
perf events, x86/stacktrace: Fix performance/softlockup by providing a special frame pointer-only stack walker
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/stacktrace.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 28 |
3 files changed, 33 insertions, 3 deletions
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 6c75151a3cca..35e89122a42f 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h | |||
@@ -22,6 +22,12 @@ print_context_stack(struct thread_info *tinfo, | |||
22 | const struct stacktrace_ops *ops, void *data, | 22 | const struct stacktrace_ops *ops, void *data, |
23 | unsigned long *end, int *graph); | 23 | unsigned long *end, int *graph); |
24 | 24 | ||
25 | extern unsigned long | ||
26 | print_context_stack_bp(struct thread_info *tinfo, | ||
27 | unsigned long *stack, unsigned long bp, | ||
28 | const struct stacktrace_ops *ops, void *data, | ||
29 | unsigned long *end, int *graph); | ||
30 | |||
25 | /* Generic stack tracer with callbacks */ | 31 | /* Generic stack tracer with callbacks */ |
26 | 32 | ||
27 | struct stacktrace_ops { | 33 | struct stacktrace_ops { |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index d3802ee5a416..c223b7e895d9 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -2336,7 +2336,7 @@ static const struct stacktrace_ops backtrace_ops = { | |||
2336 | .warning_symbol = backtrace_warning_symbol, | 2336 | .warning_symbol = backtrace_warning_symbol, |
2337 | .stack = backtrace_stack, | 2337 | .stack = backtrace_stack, |
2338 | .address = backtrace_address, | 2338 | .address = backtrace_address, |
2339 | .walk_stack = print_context_stack, | 2339 | .walk_stack = print_context_stack_bp, |
2340 | }; | 2340 | }; |
2341 | 2341 | ||
2342 | #include "../dumpstack.h" | 2342 | #include "../dumpstack.h" |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 8aaa119b7cad..c56bc2873030 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -109,6 +109,30 @@ print_context_stack(struct thread_info *tinfo, | |||
109 | } | 109 | } |
110 | return bp; | 110 | return bp; |
111 | } | 111 | } |
112 | EXPORT_SYMBOL_GPL(print_context_stack); | ||
113 | |||
114 | unsigned long | ||
115 | print_context_stack_bp(struct thread_info *tinfo, | ||
116 | unsigned long *stack, unsigned long bp, | ||
117 | const struct stacktrace_ops *ops, void *data, | ||
118 | unsigned long *end, int *graph) | ||
119 | { | ||
120 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
121 | unsigned long *ret_addr = &frame->return_address; | ||
122 | |||
123 | while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) { | ||
124 | unsigned long addr = *ret_addr; | ||
125 | |||
126 | if (__kernel_text_address(addr)) { | ||
127 | ops->address(data, addr, 1); | ||
128 | frame = frame->next_frame; | ||
129 | ret_addr = &frame->return_address; | ||
130 | print_ftrace_graph_addr(addr, data, ops, tinfo, graph); | ||
131 | } | ||
132 | } | ||
133 | return (unsigned long)frame; | ||
134 | } | ||
135 | EXPORT_SYMBOL_GPL(print_context_stack_bp); | ||
112 | 136 | ||
113 | 137 | ||
114 | static void | 138 | static void |
@@ -143,8 +167,8 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) | |||
143 | static const struct stacktrace_ops print_trace_ops = { | 167 | static const struct stacktrace_ops print_trace_ops = { |
144 | .warning = print_trace_warning, | 168 | .warning = print_trace_warning, |
145 | .warning_symbol = print_trace_warning_symbol, | 169 | .warning_symbol = print_trace_warning_symbol, |
146 | .stack = print_trace_stack, | 170 | .stack = print_trace_stack, |
147 | .address = print_trace_address, | 171 | .address = print_trace_address, |
148 | .walk_stack = print_context_stack, | 172 | .walk_stack = print_context_stack, |
149 | }; | 173 | }; |
150 | 174 | ||