diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-12-05 03:44:31 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-12-06 02:27:18 -0500 |
commit | b326e9560a28fc3e950637ef51847ed8f05c1335 (patch) | |
tree | 0804c8c4f28d4ae152d5e9205ce5a958f0d26b79 /include | |
parent | 2f0993e0fb663c49e4d1e02654f6203246be4817 (diff) |
hw-breakpoints: Use overflow handler instead of the event callback
struct perf_event::event callback was called when a breakpoint
triggers. But this is a rather opaque callback, pretty
tied-only to the breakpoint API and not really integrated into perf
as it triggers even when we don't overflow.
We prefer to use overflow_handler() as it fits into the perf events
rules, being called only when we overflow.
Reported-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: "K. Prasad" <prasad@linux.vnet.ibm.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/hw_breakpoint.h | 25 | ||||
-rw-r--r-- | include/linux/perf_event.h | 13 |
2 files changed, 18 insertions, 20 deletions
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h index d33096e0dbd4..4d14a384a01e 100644 --- a/include/linux/hw_breakpoint.h +++ b/include/linux/hw_breakpoint.h | |||
@@ -20,19 +20,16 @@ enum { | |||
20 | 20 | ||
21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
22 | 22 | ||
23 | /* As it's for in-kernel or ptrace use, we want it to be pinned */ | ||
24 | #define DEFINE_BREAKPOINT_ATTR(name) \ | ||
25 | struct perf_event_attr name = { \ | ||
26 | .type = PERF_TYPE_BREAKPOINT, \ | ||
27 | .size = sizeof(name), \ | ||
28 | .pinned = 1, \ | ||
29 | }; | ||
30 | |||
31 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) | 23 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) |
32 | { | 24 | { |
33 | attr->type = PERF_TYPE_BREAKPOINT; | 25 | attr->type = PERF_TYPE_BREAKPOINT; |
34 | attr->size = sizeof(*attr); | 26 | attr->size = sizeof(*attr); |
27 | /* | ||
28 | * As it's for in-kernel or ptrace use, we want it to be pinned | ||
29 | * and to call its callback every hits. | ||
30 | */ | ||
35 | attr->pinned = 1; | 31 | attr->pinned = 1; |
32 | attr->sample_period = 1; | ||
36 | } | 33 | } |
37 | 34 | ||
38 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) | 35 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) |
@@ -52,7 +49,7 @@ static inline int hw_breakpoint_len(struct perf_event *bp) | |||
52 | 49 | ||
53 | extern struct perf_event * | 50 | extern struct perf_event * |
54 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 51 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
55 | perf_callback_t triggered, | 52 | perf_overflow_handler_t triggered, |
56 | struct task_struct *tsk); | 53 | struct task_struct *tsk); |
57 | 54 | ||
58 | /* FIXME: only change from the attr, and don't unregister */ | 55 | /* FIXME: only change from the attr, and don't unregister */ |
@@ -64,12 +61,12 @@ modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); | |||
64 | */ | 61 | */ |
65 | extern struct perf_event * | 62 | extern struct perf_event * |
66 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, | 63 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
67 | perf_callback_t triggered, | 64 | perf_overflow_handler_t triggered, |
68 | int cpu); | 65 | int cpu); |
69 | 66 | ||
70 | extern struct perf_event ** | 67 | extern struct perf_event ** |
71 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 68 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
72 | perf_callback_t triggered); | 69 | perf_overflow_handler_t triggered); |
73 | 70 | ||
74 | extern int register_perf_hw_breakpoint(struct perf_event *bp); | 71 | extern int register_perf_hw_breakpoint(struct perf_event *bp); |
75 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); | 72 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); |
@@ -90,18 +87,18 @@ static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) | |||
90 | 87 | ||
91 | static inline struct perf_event * | 88 | static inline struct perf_event * |
92 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 89 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
93 | perf_callback_t triggered, | 90 | perf_overflow_handler_t triggered, |
94 | struct task_struct *tsk) { return NULL; } | 91 | struct task_struct *tsk) { return NULL; } |
95 | static inline struct perf_event * | 92 | static inline struct perf_event * |
96 | modify_user_hw_breakpoint(struct perf_event *bp, | 93 | modify_user_hw_breakpoint(struct perf_event *bp, |
97 | struct perf_event_attr *attr) { return NULL; } | 94 | struct perf_event_attr *attr) { return NULL; } |
98 | static inline struct perf_event * | 95 | static inline struct perf_event * |
99 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, | 96 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
100 | perf_callback_t triggered, | 97 | perf_overflow_handler_t triggered, |
101 | int cpu) { return NULL; } | 98 | int cpu) { return NULL; } |
102 | static inline struct perf_event ** | 99 | static inline struct perf_event ** |
103 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 100 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
104 | perf_callback_t triggered) { return NULL; } | 101 | perf_overflow_handler_t triggered) { return NULL; } |
105 | static inline int | 102 | static inline int |
106 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | 103 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } |
107 | static inline int | 104 | static inline int |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 84bd28a0ffab..d2f2667430da 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -565,10 +565,13 @@ struct perf_pending_entry { | |||
565 | void (*func)(struct perf_pending_entry *); | 565 | void (*func)(struct perf_pending_entry *); |
566 | }; | 566 | }; |
567 | 567 | ||
568 | typedef void (*perf_callback_t)(struct perf_event *, void *); | ||
569 | |||
570 | struct perf_sample_data; | 568 | struct perf_sample_data; |
571 | 569 | ||
570 | typedef void (*perf_callback_t)(struct perf_event *, void *); | ||
571 | typedef void (*perf_overflow_handler_t)(struct perf_event *, int, | ||
572 | struct perf_sample_data *, | ||
573 | struct pt_regs *regs); | ||
574 | |||
572 | /** | 575 | /** |
573 | * struct perf_event - performance event kernel representation: | 576 | * struct perf_event - performance event kernel representation: |
574 | */ | 577 | */ |
@@ -660,9 +663,7 @@ struct perf_event { | |||
660 | struct pid_namespace *ns; | 663 | struct pid_namespace *ns; |
661 | u64 id; | 664 | u64 id; |
662 | 665 | ||
663 | void (*overflow_handler)(struct perf_event *event, | 666 | perf_overflow_handler_t overflow_handler; |
664 | int nmi, struct perf_sample_data *data, | ||
665 | struct pt_regs *regs); | ||
666 | 667 | ||
667 | #ifdef CONFIG_EVENT_PROFILE | 668 | #ifdef CONFIG_EVENT_PROFILE |
668 | struct event_filter *filter; | 669 | struct event_filter *filter; |
@@ -779,7 +780,7 @@ extern struct perf_event * | |||
779 | perf_event_create_kernel_counter(struct perf_event_attr *attr, | 780 | perf_event_create_kernel_counter(struct perf_event_attr *attr, |
780 | int cpu, | 781 | int cpu, |
781 | pid_t pid, | 782 | pid_t pid, |
782 | perf_callback_t callback); | 783 | perf_overflow_handler_t callback); |
783 | extern u64 perf_event_read_value(struct perf_event *event, | 784 | extern u64 perf_event_read_value(struct perf_event *event, |
784 | u64 *enabled, u64 *running); | 785 | u64 *enabled, u64 *running); |
785 | 786 | ||