diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-11-21 08:07:23 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-21 08:07:23 -0500 |
commit | 96200591a34f8ecb98481c626125df43a2463b55 (patch) | |
tree | 314c376b01f254d04f9aaf449b1f9147ad177fa6 /include | |
parent | 7031281e02bf951a2259849217193fb9d75a9762 (diff) | |
parent | 68efa37df779b3e04280598e8b5b3a1919b65fee (diff) |
Merge branch 'tracing/hw-breakpoints' into perf/core
Conflicts:
arch/x86/kernel/kprobes.c
kernel/trace/Makefile
Merge reason: hw-breakpoints perf integration is looking
good in testing and in reviews, plus conflicts
are mounting up - so merge & resolve.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/hw_breakpoint.h | 137 | ||||
-rw-r--r-- | include/linux/perf_event.h | 37 |
2 files changed, 173 insertions, 1 deletions
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h new file mode 100644 index 000000000000..0b98cbf76da7 --- /dev/null +++ b/include/linux/hw_breakpoint.h | |||
@@ -0,0 +1,137 @@ | |||
1 | #ifndef _LINUX_HW_BREAKPOINT_H | ||
2 | #define _LINUX_HW_BREAKPOINT_H | ||
3 | |||
4 | #include <linux/perf_event.h> | ||
5 | |||
6 | enum { | ||
7 | HW_BREAKPOINT_LEN_1 = 1, | ||
8 | HW_BREAKPOINT_LEN_2 = 2, | ||
9 | HW_BREAKPOINT_LEN_4 = 4, | ||
10 | HW_BREAKPOINT_LEN_8 = 8, | ||
11 | }; | ||
12 | |||
13 | enum { | ||
14 | HW_BREAKPOINT_R = 1, | ||
15 | HW_BREAKPOINT_W = 2, | ||
16 | HW_BREAKPOINT_X = 4, | ||
17 | }; | ||
18 | |||
19 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
20 | |||
21 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) | ||
22 | { | ||
23 | return bp->attr.bp_addr; | ||
24 | } | ||
25 | |||
26 | static inline int hw_breakpoint_type(struct perf_event *bp) | ||
27 | { | ||
28 | return bp->attr.bp_type; | ||
29 | } | ||
30 | |||
31 | static inline int hw_breakpoint_len(struct perf_event *bp) | ||
32 | { | ||
33 | return bp->attr.bp_len; | ||
34 | } | ||
35 | |||
36 | extern struct perf_event * | ||
37 | register_user_hw_breakpoint(unsigned long addr, | ||
38 | int len, | ||
39 | int type, | ||
40 | perf_callback_t triggered, | ||
41 | struct task_struct *tsk, | ||
42 | bool active); | ||
43 | |||
44 | /* FIXME: only change from the attr, and don't unregister */ | ||
45 | extern struct perf_event * | ||
46 | modify_user_hw_breakpoint(struct perf_event *bp, | ||
47 | unsigned long addr, | ||
48 | int len, | ||
49 | int type, | ||
50 | perf_callback_t triggered, | ||
51 | struct task_struct *tsk, | ||
52 | bool active); | ||
53 | |||
54 | /* | ||
55 | * Kernel breakpoints are not associated with any particular thread. | ||
56 | */ | ||
57 | extern struct perf_event * | ||
58 | register_wide_hw_breakpoint_cpu(unsigned long addr, | ||
59 | int len, | ||
60 | int type, | ||
61 | perf_callback_t triggered, | ||
62 | int cpu, | ||
63 | bool active); | ||
64 | |||
65 | extern struct perf_event ** | ||
66 | register_wide_hw_breakpoint(unsigned long addr, | ||
67 | int len, | ||
68 | int type, | ||
69 | perf_callback_t triggered, | ||
70 | bool active); | ||
71 | |||
72 | extern int register_perf_hw_breakpoint(struct perf_event *bp); | ||
73 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); | ||
74 | extern void unregister_hw_breakpoint(struct perf_event *bp); | ||
75 | extern void unregister_wide_hw_breakpoint(struct perf_event **cpu_events); | ||
76 | |||
77 | extern int reserve_bp_slot(struct perf_event *bp); | ||
78 | extern void release_bp_slot(struct perf_event *bp); | ||
79 | |||
80 | extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); | ||
81 | |||
82 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) | ||
83 | { | ||
84 | return &bp->hw.info; | ||
85 | } | ||
86 | |||
87 | #else /* !CONFIG_HAVE_HW_BREAKPOINT */ | ||
88 | |||
89 | static inline struct perf_event * | ||
90 | register_user_hw_breakpoint(unsigned long addr, | ||
91 | int len, | ||
92 | int type, | ||
93 | perf_callback_t triggered, | ||
94 | struct task_struct *tsk, | ||
95 | bool active) { return NULL; } | ||
96 | static inline struct perf_event * | ||
97 | modify_user_hw_breakpoint(struct perf_event *bp, | ||
98 | unsigned long addr, | ||
99 | int len, | ||
100 | int type, | ||
101 | perf_callback_t triggered, | ||
102 | struct task_struct *tsk, | ||
103 | bool active) { return NULL; } | ||
104 | static inline struct perf_event * | ||
105 | register_wide_hw_breakpoint_cpu(unsigned long addr, | ||
106 | int len, | ||
107 | int type, | ||
108 | perf_callback_t triggered, | ||
109 | int cpu, | ||
110 | bool active) { return NULL; } | ||
111 | static inline struct perf_event ** | ||
112 | register_wide_hw_breakpoint(unsigned long addr, | ||
113 | int len, | ||
114 | int type, | ||
115 | perf_callback_t triggered, | ||
116 | bool active) { return NULL; } | ||
117 | static inline int | ||
118 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | ||
119 | static inline int | ||
120 | __register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | ||
121 | static inline void unregister_hw_breakpoint(struct perf_event *bp) { } | ||
122 | static inline void | ||
123 | unregister_wide_hw_breakpoint(struct perf_event **cpu_events) { } | ||
124 | static inline int | ||
125 | reserve_bp_slot(struct perf_event *bp) {return -ENOSYS; } | ||
126 | static inline void release_bp_slot(struct perf_event *bp) { } | ||
127 | |||
128 | static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } | ||
129 | |||
130 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) | ||
131 | { | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
135 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
136 | |||
137 | #endif /* _LINUX_HW_BREAKPOINT_H */ | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 7f87563c8485..b5cdac0de370 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -18,6 +18,10 @@ | |||
18 | #include <linux/ioctl.h> | 18 | #include <linux/ioctl.h> |
19 | #include <asm/byteorder.h> | 19 | #include <asm/byteorder.h> |
20 | 20 | ||
21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
22 | #include <asm/hw_breakpoint.h> | ||
23 | #endif | ||
24 | |||
21 | /* | 25 | /* |
22 | * User-space ABI bits: | 26 | * User-space ABI bits: |
23 | */ | 27 | */ |
@@ -31,6 +35,7 @@ enum perf_type_id { | |||
31 | PERF_TYPE_TRACEPOINT = 2, | 35 | PERF_TYPE_TRACEPOINT = 2, |
32 | PERF_TYPE_HW_CACHE = 3, | 36 | PERF_TYPE_HW_CACHE = 3, |
33 | PERF_TYPE_RAW = 4, | 37 | PERF_TYPE_RAW = 4, |
38 | PERF_TYPE_BREAKPOINT = 5, | ||
34 | 39 | ||
35 | PERF_TYPE_MAX, /* non-ABI */ | 40 | PERF_TYPE_MAX, /* non-ABI */ |
36 | }; | 41 | }; |
@@ -209,6 +214,15 @@ struct perf_event_attr { | |||
209 | __u32 wakeup_events; /* wakeup every n events */ | 214 | __u32 wakeup_events; /* wakeup every n events */ |
210 | __u32 wakeup_watermark; /* bytes before wakeup */ | 215 | __u32 wakeup_watermark; /* bytes before wakeup */ |
211 | }; | 216 | }; |
217 | |||
218 | union { | ||
219 | struct { /* Hardware breakpoint info */ | ||
220 | __u64 bp_addr; | ||
221 | __u32 bp_type; | ||
222 | __u32 bp_len; | ||
223 | }; | ||
224 | }; | ||
225 | |||
212 | __u32 __reserved_2; | 226 | __u32 __reserved_2; |
213 | 227 | ||
214 | __u64 __reserved_3; | 228 | __u64 __reserved_3; |
@@ -478,6 +492,11 @@ struct hw_perf_event { | |||
478 | s64 remaining; | 492 | s64 remaining; |
479 | struct hrtimer hrtimer; | 493 | struct hrtimer hrtimer; |
480 | }; | 494 | }; |
495 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
496 | union { /* breakpoint */ | ||
497 | struct arch_hw_breakpoint info; | ||
498 | }; | ||
499 | #endif | ||
481 | }; | 500 | }; |
482 | atomic64_t prev_count; | 501 | atomic64_t prev_count; |
483 | u64 sample_period; | 502 | u64 sample_period; |
@@ -546,6 +565,8 @@ struct perf_pending_entry { | |||
546 | void (*func)(struct perf_pending_entry *); | 565 | void (*func)(struct perf_pending_entry *); |
547 | }; | 566 | }; |
548 | 567 | ||
568 | typedef void (*perf_callback_t)(struct perf_event *, void *); | ||
569 | |||
549 | /** | 570 | /** |
550 | * struct perf_event - performance event kernel representation: | 571 | * struct perf_event - performance event kernel representation: |
551 | */ | 572 | */ |
@@ -588,7 +609,7 @@ struct perf_event { | |||
588 | u64 tstamp_running; | 609 | u64 tstamp_running; |
589 | u64 tstamp_stopped; | 610 | u64 tstamp_stopped; |
590 | 611 | ||
591 | struct perf_event_attr attr; | 612 | struct perf_event_attr attr; |
592 | struct hw_perf_event hw; | 613 | struct hw_perf_event hw; |
593 | 614 | ||
594 | struct perf_event_context *ctx; | 615 | struct perf_event_context *ctx; |
@@ -641,6 +662,10 @@ struct perf_event { | |||
641 | struct event_filter *filter; | 662 | struct event_filter *filter; |
642 | #endif | 663 | #endif |
643 | 664 | ||
665 | perf_callback_t callback; | ||
666 | |||
667 | perf_callback_t event_callback; | ||
668 | |||
644 | #endif /* CONFIG_PERF_EVENTS */ | 669 | #endif /* CONFIG_PERF_EVENTS */ |
645 | }; | 670 | }; |
646 | 671 | ||
@@ -745,6 +770,13 @@ extern int hw_perf_group_sched_in(struct perf_event *group_leader, | |||
745 | struct perf_cpu_context *cpuctx, | 770 | struct perf_cpu_context *cpuctx, |
746 | struct perf_event_context *ctx, int cpu); | 771 | struct perf_event_context *ctx, int cpu); |
747 | extern void perf_event_update_userpage(struct perf_event *event); | 772 | extern void perf_event_update_userpage(struct perf_event *event); |
773 | extern int perf_event_release_kernel(struct perf_event *event); | ||
774 | extern struct perf_event * | ||
775 | perf_event_create_kernel_counter(struct perf_event_attr *attr, | ||
776 | int cpu, | ||
777 | pid_t pid, | ||
778 | perf_callback_t callback); | ||
779 | extern u64 perf_event_read_value(struct perf_event *event); | ||
748 | 780 | ||
749 | struct perf_sample_data { | 781 | struct perf_sample_data { |
750 | u64 type; | 782 | u64 type; |
@@ -821,6 +853,7 @@ extern int sysctl_perf_event_sample_rate; | |||
821 | extern void perf_event_init(void); | 853 | extern void perf_event_init(void); |
822 | extern void perf_tp_event(int event_id, u64 addr, u64 count, | 854 | extern void perf_tp_event(int event_id, u64 addr, u64 count, |
823 | void *record, int entry_size); | 855 | void *record, int entry_size); |
856 | extern void perf_bp_event(struct perf_event *event, void *data); | ||
824 | 857 | ||
825 | #ifndef perf_misc_flags | 858 | #ifndef perf_misc_flags |
826 | #define perf_misc_flags(regs) (user_mode(regs) ? PERF_RECORD_MISC_USER : \ | 859 | #define perf_misc_flags(regs) (user_mode(regs) ? PERF_RECORD_MISC_USER : \ |
@@ -855,6 +888,8 @@ static inline int perf_event_task_enable(void) { return -EINVAL; } | |||
855 | static inline void | 888 | static inline void |
856 | perf_sw_event(u32 event_id, u64 nr, int nmi, | 889 | perf_sw_event(u32 event_id, u64 nr, int nmi, |
857 | struct pt_regs *regs, u64 addr) { } | 890 | struct pt_regs *regs, u64 addr) { } |
891 | static inline void | ||
892 | perf_bp_event(struct perf_event *event, void *data) { } | ||
858 | 893 | ||
859 | static inline void perf_event_mmap(struct vm_area_struct *vma) { } | 894 | static inline void perf_event_mmap(struct vm_area_struct *vma) { } |
860 | static inline void perf_event_comm(struct task_struct *tsk) { } | 895 | static inline void perf_event_comm(struct task_struct *tsk) { } |