aboutsummaryrefslogtreecommitdiffstats
path: root/include/trace
diff options
context:
space:
mode:
authorPeter Zijlstra (Intel) <peterz@infradead.org>2014-12-16 06:47:34 -0500
committerIngo Molnar <mingo@kernel.org>2015-01-14 09:11:45 -0500
commit86038c5ea81b519a8a1fcfcd5e4599aab0cdd119 (patch)
tree52885be83b5062b95923e16c02f7137c45609a61 /include/trace
parent188c901941efd43cbf21e8f4f9e9a276536b989c (diff)
perf: Avoid horrible stack usage
Both Linus (most recent) and Steve (a while ago) reported that perf related callbacks have massive stack bloat. The problem is that software events need a pt_regs in order to properly report the event location and unwind stack. And because we could not assume one was present we allocated one on stack and filled it with minimal bits required for operation. Now, pt_regs is quite large, so this is undesirable. Furthermore it turns out that most sites actually have a pt_regs pointer available, making this even more onerous, as the stack space is pointless waste. This patch addresses the problem by observing that software events have well defined nesting semantics, therefore we can use static per-cpu storage instead of on-stack. Linus made the further observation that all but the scheduler callers of perf_sw_event() have a pt_regs available, so we change the regular perf_sw_event() to require a valid pt_regs (where it used to be optional) and add perf_sw_event_sched() for the scheduler. We have a scheduler specific call instead of a more generic _noregs() like construct because we can assume non-recursion from the scheduler and thereby simplify the code further (_noregs would have to put the recursion context call inline in order to assertain which __perf_regs element to use). One last note on the implementation of perf_trace_buf_prepare(); we allow .regs = NULL for those cases where we already have a pt_regs pointer available and do not need another. Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Reported-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Javi Merino <javi.merino@arm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Petr Mladek <pmladek@suse.cz> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tom.zanussi@linux.intel.com> Cc: Vaibhav Nagarnaik <vnagarnaik@google.com> Link: http://lkml.kernel.org/r/20141216115041.GW3337@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/trace')
-rw-r--r--include/trace/ftrace.h7
1 files changed, 4 insertions, 3 deletions
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 139b5067345b..27609dfcce25 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -763,7 +763,7 @@ perf_trace_##call(void *__data, proto) \
763 struct ftrace_event_call *event_call = __data; \ 763 struct ftrace_event_call *event_call = __data; \
764 struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ 764 struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
765 struct ftrace_raw_##call *entry; \ 765 struct ftrace_raw_##call *entry; \
766 struct pt_regs __regs; \ 766 struct pt_regs *__regs; \
767 u64 __addr = 0, __count = 1; \ 767 u64 __addr = 0, __count = 1; \
768 struct task_struct *__task = NULL; \ 768 struct task_struct *__task = NULL; \
769 struct hlist_head *head; \ 769 struct hlist_head *head; \
@@ -782,18 +782,19 @@ perf_trace_##call(void *__data, proto) \
782 sizeof(u64)); \ 782 sizeof(u64)); \
783 __entry_size -= sizeof(u32); \ 783 __entry_size -= sizeof(u32); \
784 \ 784 \
785 perf_fetch_caller_regs(&__regs); \
786 entry = perf_trace_buf_prepare(__entry_size, \ 785 entry = perf_trace_buf_prepare(__entry_size, \
787 event_call->event.type, &__regs, &rctx); \ 786 event_call->event.type, &__regs, &rctx); \
788 if (!entry) \ 787 if (!entry) \
789 return; \ 788 return; \
790 \ 789 \
790 perf_fetch_caller_regs(__regs); \
791 \
791 tstruct \ 792 tstruct \
792 \ 793 \
793 { assign; } \ 794 { assign; } \
794 \ 795 \
795 perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ 796 perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
796 __count, &__regs, head, __task); \ 797 __count, __regs, head, __task); \
797} 798}
798 799
799/* 800/*