diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-11-23 05:37:29 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-23 05:49:57 -0500 |
commit | 4ed7c92d68a5387ba5f7030dc76eab03558e27f5 (patch) | |
tree | 38d758819c41261275c2dbd6f64976f824c5fd27 /kernel/perf_event.c | |
parent | f67218c3e93abaf0f480bb94b53d234853ffe4de (diff) |
perf_events: Undo some recursion damage
Make perf_swevent_get_recursion_context return a context number
and disable preemption.
This could be used to remove the IRQ disable from the trace bit
and index the per-cpu buffer with.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <20091123103819.993226816@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r-- | kernel/perf_event.c | 71 |
1 files changed, 32 insertions, 39 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 50f11b5f8c3d..0b0d5f72fe7d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -3869,45 +3869,50 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, | |||
3869 | } | 3869 | } |
3870 | } | 3870 | } |
3871 | 3871 | ||
3872 | /* | 3872 | int perf_swevent_get_recursion_context(void) |
3873 | * Must be called with preemption disabled | ||
3874 | */ | ||
3875 | int perf_swevent_get_recursion_context(int **recursion) | ||
3876 | { | 3873 | { |
3877 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | 3874 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); |
3875 | int rctx; | ||
3878 | 3876 | ||
3879 | if (in_nmi()) | 3877 | if (in_nmi()) |
3880 | *recursion = &cpuctx->recursion[3]; | 3878 | rctx = 3; |
3881 | else if (in_irq()) | 3879 | else if (in_irq()) |
3882 | *recursion = &cpuctx->recursion[2]; | 3880 | rctx = 2; |
3883 | else if (in_softirq()) | 3881 | else if (in_softirq()) |
3884 | *recursion = &cpuctx->recursion[1]; | 3882 | rctx = 1; |
3885 | else | 3883 | else |
3886 | *recursion = &cpuctx->recursion[0]; | 3884 | rctx = 0; |
3887 | 3885 | ||
3888 | if (**recursion) | 3886 | if (cpuctx->recursion[rctx]) { |
3887 | put_cpu_var(perf_cpu_context); | ||
3889 | return -1; | 3888 | return -1; |
3889 | } | ||
3890 | 3890 | ||
3891 | (**recursion)++; | 3891 | cpuctx->recursion[rctx]++; |
3892 | barrier(); | ||
3892 | 3893 | ||
3893 | return 0; | 3894 | return rctx; |
3894 | } | 3895 | } |
3895 | EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); | 3896 | EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); |
3896 | 3897 | ||
3897 | void perf_swevent_put_recursion_context(int *recursion) | 3898 | void perf_swevent_put_recursion_context(int rctx) |
3898 | { | 3899 | { |
3899 | (*recursion)--; | 3900 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); |
3901 | barrier(); | ||
3902 | cpuctx->recursion[rctx]++; | ||
3903 | put_cpu_var(perf_cpu_context); | ||
3900 | } | 3904 | } |
3901 | EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); | 3905 | EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); |
3902 | 3906 | ||
3903 | static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, | 3907 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, |
3904 | u64 nr, int nmi, | 3908 | u64 nr, int nmi, |
3905 | struct perf_sample_data *data, | 3909 | struct perf_sample_data *data, |
3906 | struct pt_regs *regs) | 3910 | struct pt_regs *regs) |
3907 | { | 3911 | { |
3912 | struct perf_cpu_context *cpuctx; | ||
3908 | struct perf_event_context *ctx; | 3913 | struct perf_event_context *ctx; |
3909 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3910 | 3914 | ||
3915 | cpuctx = &__get_cpu_var(perf_cpu_context); | ||
3911 | rcu_read_lock(); | 3916 | rcu_read_lock(); |
3912 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, | 3917 | perf_swevent_ctx_event(&cpuctx->ctx, type, event_id, |
3913 | nr, nmi, data, regs); | 3918 | nr, nmi, data, regs); |
@@ -3921,34 +3926,22 @@ static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, | |||
3921 | rcu_read_unlock(); | 3926 | rcu_read_unlock(); |
3922 | } | 3927 | } |
3923 | 3928 | ||
3924 | static void do_perf_sw_event(enum perf_type_id type, u32 event_id, | ||
3925 | u64 nr, int nmi, | ||
3926 | struct perf_sample_data *data, | ||
3927 | struct pt_regs *regs) | ||
3928 | { | ||
3929 | int *recursion; | ||
3930 | |||
3931 | preempt_disable(); | ||
3932 | |||
3933 | if (perf_swevent_get_recursion_context(&recursion)) | ||
3934 | goto out; | ||
3935 | |||
3936 | __do_perf_sw_event(type, event_id, nr, nmi, data, regs); | ||
3937 | |||
3938 | perf_swevent_put_recursion_context(recursion); | ||
3939 | out: | ||
3940 | preempt_enable(); | ||
3941 | } | ||
3942 | |||
3943 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, | 3929 | void __perf_sw_event(u32 event_id, u64 nr, int nmi, |
3944 | struct pt_regs *regs, u64 addr) | 3930 | struct pt_regs *regs, u64 addr) |
3945 | { | 3931 | { |
3946 | struct perf_sample_data data; | 3932 | struct perf_sample_data data; |
3933 | int rctx; | ||
3934 | |||
3935 | rctx = perf_swevent_get_recursion_context(); | ||
3936 | if (rctx < 0) | ||
3937 | return; | ||
3947 | 3938 | ||
3948 | data.addr = addr; | 3939 | data.addr = addr; |
3949 | data.raw = NULL; | 3940 | data.raw = NULL; |
3950 | 3941 | ||
3951 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); | 3942 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); |
3943 | |||
3944 | perf_swevent_put_recursion_context(rctx); | ||
3952 | } | 3945 | } |
3953 | 3946 | ||
3954 | static void perf_swevent_read(struct perf_event *event) | 3947 | static void perf_swevent_read(struct perf_event *event) |
@@ -4172,7 +4165,7 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4172 | regs = task_pt_regs(current); | 4165 | regs = task_pt_regs(current); |
4173 | 4166 | ||
4174 | /* Trace events already protected against recursion */ | 4167 | /* Trace events already protected against recursion */ |
4175 | __do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | 4168 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, |
4176 | &data, regs); | 4169 | &data, regs); |
4177 | } | 4170 | } |
4178 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4171 | EXPORT_SYMBOL_GPL(perf_tp_event); |