aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-11-23 05:37:29 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-23 05:49:57 -0500
commit4ed7c92d68a5387ba5f7030dc76eab03558e27f5 (patch)
tree38d758819c41261275c2dbd6f64976f824c5fd27
parentf67218c3e93abaf0f480bb94b53d234853ffe4de (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>
-rw-r--r--include/linux/perf_event.h8
-rw-r--r--include/trace/ftrace.h17
-rw-r--r--kernel/perf_event.c71
-rw-r--r--kernel/trace/trace_kprobe.c14
-rw-r--r--kernel/trace/trace_syscalls.c14
5 files changed, 61 insertions, 63 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 74e98b1d3391..43adbd7f0010 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -874,8 +874,8 @@ extern int perf_output_begin(struct perf_output_handle *handle,
874extern void perf_output_end(struct perf_output_handle *handle); 874extern void perf_output_end(struct perf_output_handle *handle);
875extern void perf_output_copy(struct perf_output_handle *handle, 875extern void perf_output_copy(struct perf_output_handle *handle,
876 const void *buf, unsigned int len); 876 const void *buf, unsigned int len);
877extern int perf_swevent_get_recursion_context(int **recursion); 877extern int perf_swevent_get_recursion_context(void);
878extern void perf_swevent_put_recursion_context(int *recursion); 878extern void perf_swevent_put_recursion_context(int rctx);
879#else 879#else
880static inline void 880static inline void
881perf_event_task_sched_in(struct task_struct *task, int cpu) { } 881perf_event_task_sched_in(struct task_struct *task, int cpu) { }
@@ -904,8 +904,8 @@ static inline void perf_event_mmap(struct vm_area_struct *vma) { }
904static inline void perf_event_comm(struct task_struct *tsk) { } 904static inline void perf_event_comm(struct task_struct *tsk) { }
905static inline void perf_event_fork(struct task_struct *tsk) { } 905static inline void perf_event_fork(struct task_struct *tsk) { }
906static inline void perf_event_init(void) { } 906static inline void perf_event_init(void) { }
907static int perf_swevent_get_recursion_context(int **recursion) { return -1; } 907static inline int perf_swevent_get_recursion_context(void) { return -1; }
908static void perf_swevent_put_recursion_context(int *recursion) { } 908static inline void perf_swevent_put_recursion_context(int rctx) { }
909 909
910#endif 910#endif
911 911
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index c222ef5238bf..c3417c13e3ed 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -724,8 +724,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
724static void ftrace_profile_##call(proto) \ 724static void ftrace_profile_##call(proto) \
725{ \ 725{ \
726 struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ 726 struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
727 extern int perf_swevent_get_recursion_context(int **recursion); \ 727 extern int perf_swevent_get_recursion_context(void); \
728 extern void perf_swevent_put_recursion_context(int *recursion); \ 728 extern void perf_swevent_put_recursion_context(int rctx); \
729 struct ftrace_event_call *event_call = &event_##call; \ 729 struct ftrace_event_call *event_call = &event_##call; \
730 extern void perf_tp_event(int, u64, u64, void *, int); \ 730 extern void perf_tp_event(int, u64, u64, void *, int); \
731 struct ftrace_raw_##call *entry; \ 731 struct ftrace_raw_##call *entry; \
@@ -736,8 +736,8 @@ static void ftrace_profile_##call(proto) \
736 int __data_size; \ 736 int __data_size; \
737 char *trace_buf; \ 737 char *trace_buf; \
738 char *raw_data; \ 738 char *raw_data; \
739 int *recursion; \
740 int __cpu; \ 739 int __cpu; \
740 int rctx; \
741 int pc; \ 741 int pc; \
742 \ 742 \
743 pc = preempt_count(); \ 743 pc = preempt_count(); \
@@ -753,8 +753,9 @@ static void ftrace_profile_##call(proto) \
753 \ 753 \
754 local_irq_save(irq_flags); \ 754 local_irq_save(irq_flags); \
755 \ 755 \
756 if (perf_swevent_get_recursion_context(&recursion)) \ 756 rctx = perf_swevent_get_recursion_context(); \
757 goto end_recursion; \ 757 if (rctx < 0) \
758 goto end_recursion; \
758 \ 759 \
759 __cpu = smp_processor_id(); \ 760 __cpu = smp_processor_id(); \
760 \ 761 \
@@ -781,9 +782,9 @@ static void ftrace_profile_##call(proto) \
781 perf_tp_event(event_call->id, __addr, __count, entry, \ 782 perf_tp_event(event_call->id, __addr, __count, entry, \
782 __entry_size); \ 783 __entry_size); \
783 \ 784 \
784end: \ 785end: \
785 perf_swevent_put_recursion_context(recursion); \ 786 perf_swevent_put_recursion_context(rctx); \
786end_recursion: \ 787end_recursion: \
787 local_irq_restore(irq_flags); \ 788 local_irq_restore(irq_flags); \
788 \ 789 \
789} 790}
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/* 3872int perf_swevent_get_recursion_context(void)
3873 * Must be called with preemption disabled
3874 */
3875int 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}
3895EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); 3896EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
3896 3897
3897void perf_swevent_put_recursion_context(int *recursion) 3898void 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}
3901EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); 3905EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
3902 3906
3903static void __do_perf_sw_event(enum perf_type_id type, u32 event_id, 3907static 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
3924static 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);
3939out:
3940 preempt_enable();
3941}
3942
3943void __perf_sw_event(u32 event_id, u64 nr, int nmi, 3929void __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
3954static void perf_swevent_read(struct perf_event *event) 3947static 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}
4178EXPORT_SYMBOL_GPL(perf_tp_event); 4171EXPORT_SYMBOL_GPL(perf_tp_event);
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 22e6f68b05b3..79ce6a2bd74f 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1213,7 +1213,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
1213 unsigned long irq_flags; 1213 unsigned long irq_flags;
1214 char *trace_buf; 1214 char *trace_buf;
1215 char *raw_data; 1215 char *raw_data;
1216 int *recursion; 1216 int rctx;
1217 1217
1218 pc = preempt_count(); 1218 pc = preempt_count();
1219 __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); 1219 __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
@@ -1229,7 +1229,8 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
1229 */ 1229 */
1230 local_irq_save(irq_flags); 1230 local_irq_save(irq_flags);
1231 1231
1232 if (perf_swevent_get_recursion_context(&recursion)) 1232 rctx = perf_swevent_get_recursion_context();
1233 if (rctx < 0)
1233 goto end_recursion; 1234 goto end_recursion;
1234 1235
1235 __cpu = smp_processor_id(); 1236 __cpu = smp_processor_id();
@@ -1258,7 +1259,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
1258 perf_tp_event(call->id, entry->ip, 1, entry, size); 1259 perf_tp_event(call->id, entry->ip, 1, entry, size);
1259 1260
1260end: 1261end:
1261 perf_swevent_put_recursion_context(recursion); 1262 perf_swevent_put_recursion_context(rctx);
1262end_recursion: 1263end_recursion:
1263 local_irq_restore(irq_flags); 1264 local_irq_restore(irq_flags);
1264 1265
@@ -1276,8 +1277,8 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
1276 int size, __size, i, pc, __cpu; 1277 int size, __size, i, pc, __cpu;
1277 unsigned long irq_flags; 1278 unsigned long irq_flags;
1278 char *trace_buf; 1279 char *trace_buf;
1279 int *recursion;
1280 char *raw_data; 1280 char *raw_data;
1281 int rctx;
1281 1282
1282 pc = preempt_count(); 1283 pc = preempt_count();
1283 __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); 1284 __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
@@ -1293,7 +1294,8 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
1293 */ 1294 */
1294 local_irq_save(irq_flags); 1295 local_irq_save(irq_flags);
1295 1296
1296 if (perf_swevent_get_recursion_context(&recursion)) 1297 rctx = perf_swevent_get_recursion_context();
1298 if (rctx < 0)
1297 goto end_recursion; 1299 goto end_recursion;
1298 1300
1299 __cpu = smp_processor_id(); 1301 __cpu = smp_processor_id();
@@ -1323,7 +1325,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
1323 perf_tp_event(call->id, entry->ret_ip, 1, entry, size); 1325 perf_tp_event(call->id, entry->ret_ip, 1, entry, size);
1324 1326
1325end: 1327end:
1326 perf_swevent_put_recursion_context(recursion); 1328 perf_swevent_put_recursion_context(rctx);
1327end_recursion: 1329end_recursion:
1328 local_irq_restore(irq_flags); 1330 local_irq_restore(irq_flags);
1329 1331
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 41b6dd963daa..9189cbe86079 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -481,8 +481,8 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
481 unsigned long flags; 481 unsigned long flags;
482 char *trace_buf; 482 char *trace_buf;
483 char *raw_data; 483 char *raw_data;
484 int *recursion;
485 int syscall_nr; 484 int syscall_nr;
485 int rctx;
486 int size; 486 int size;
487 int cpu; 487 int cpu;
488 488
@@ -506,7 +506,8 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
506 /* Protect the per cpu buffer, begin the rcu read side */ 506 /* Protect the per cpu buffer, begin the rcu read side */
507 local_irq_save(flags); 507 local_irq_save(flags);
508 508
509 if (perf_swevent_get_recursion_context(&recursion)) 509 rctx = perf_swevent_get_recursion_context();
510 if (rctx < 0)
510 goto end_recursion; 511 goto end_recursion;
511 512
512 cpu = smp_processor_id(); 513 cpu = smp_processor_id();
@@ -530,7 +531,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
530 perf_tp_event(sys_data->enter_id, 0, 1, rec, size); 531 perf_tp_event(sys_data->enter_id, 0, 1, rec, size);
531 532
532end: 533end:
533 perf_swevent_put_recursion_context(recursion); 534 perf_swevent_put_recursion_context(rctx);
534end_recursion: 535end_recursion:
535 local_irq_restore(flags); 536 local_irq_restore(flags);
536} 537}
@@ -582,7 +583,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
582 int syscall_nr; 583 int syscall_nr;
583 char *trace_buf; 584 char *trace_buf;
584 char *raw_data; 585 char *raw_data;
585 int *recursion; 586 int rctx;
586 int size; 587 int size;
587 int cpu; 588 int cpu;
588 589
@@ -609,7 +610,8 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
609 /* Protect the per cpu buffer, begin the rcu read side */ 610 /* Protect the per cpu buffer, begin the rcu read side */
610 local_irq_save(flags); 611 local_irq_save(flags);
611 612
612 if (perf_swevent_get_recursion_context(&recursion)) 613 rctx = perf_swevent_get_recursion_context();
614 if (rctx < 0)
613 goto end_recursion; 615 goto end_recursion;
614 616
615 cpu = smp_processor_id(); 617 cpu = smp_processor_id();
@@ -634,7 +636,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
634 perf_tp_event(sys_data->exit_id, 0, 1, rec, size); 636 perf_tp_event(sys_data->exit_id, 0, 1, rec, size);
635 637
636end: 638end:
637 perf_swevent_put_recursion_context(recursion); 639 perf_swevent_put_recursion_context(rctx);
638end_recursion: 640end_recursion:
639 local_irq_restore(flags); 641 local_irq_restore(flags);
640} 642}