diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-05-03 02:29:35 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-05-03 02:29:35 -0400 |
commit | 0806ebd974590ab24ab357d5d87db744e56bfe13 (patch) | |
tree | baf96726e3d9f8c2316e509e0a4cbc99ba5fe67a | |
parent | 090f7204dfdb5d7f18208ea81dfdba845897cedd (diff) | |
parent | feef47d0cb530e8419dfa0b48141b538b89b1b1a (diff) |
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing into perf/core
28 files changed, 243 insertions, 256 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index f06010fb4838..acda512da2e2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -137,6 +137,17 @@ config HAVE_HW_BREAKPOINT | |||
137 | bool | 137 | bool |
138 | depends on PERF_EVENTS | 138 | depends on PERF_EVENTS |
139 | 139 | ||
140 | config HAVE_MIXED_BREAKPOINTS_REGS | ||
141 | bool | ||
142 | depends on HAVE_HW_BREAKPOINT | ||
143 | help | ||
144 | Depending on the arch implementation of hardware breakpoints, | ||
145 | some of them have separate registers for data and instruction | ||
146 | breakpoints addresses, others have mixed registers to store | ||
147 | them but define the access type in a control register. | ||
148 | Select this option if your arch implements breakpoints under the | ||
149 | latter fashion. | ||
150 | |||
140 | config HAVE_USER_RETURN_NOTIFIER | 151 | config HAVE_USER_RETURN_NOTIFIER |
141 | bool | 152 | bool |
142 | 153 | ||
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 8d90564c2bcf..e6d8ab5cfa9d 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -44,6 +44,7 @@ config SUPERH32 | |||
44 | select HAVE_FUNCTION_GRAPH_TRACER | 44 | select HAVE_FUNCTION_GRAPH_TRACER |
45 | select HAVE_ARCH_KGDB | 45 | select HAVE_ARCH_KGDB |
46 | select HAVE_HW_BREAKPOINT | 46 | select HAVE_HW_BREAKPOINT |
47 | select HAVE_MIXED_BREAKPOINTS_REGS | ||
47 | select PERF_EVENTS if HAVE_HW_BREAKPOINT | 48 | select PERF_EVENTS if HAVE_HW_BREAKPOINT |
48 | select ARCH_HIBERNATION_POSSIBLE if MMU | 49 | select ARCH_HIBERNATION_POSSIBLE if MMU |
49 | 50 | ||
diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h index 965dd780d51b..e14cad96798f 100644 --- a/arch/sh/include/asm/hw_breakpoint.h +++ b/arch/sh/include/asm/hw_breakpoint.h | |||
@@ -46,10 +46,14 @@ struct pmu; | |||
46 | /* Maximum number of UBC channels */ | 46 | /* Maximum number of UBC channels */ |
47 | #define HBP_NUM 2 | 47 | #define HBP_NUM 2 |
48 | 48 | ||
49 | static inline int hw_breakpoint_slots(int type) | ||
50 | { | ||
51 | return HBP_NUM; | ||
52 | } | ||
53 | |||
49 | /* arch/sh/kernel/hw_breakpoint.c */ | 54 | /* arch/sh/kernel/hw_breakpoint.c */ |
50 | extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len); | 55 | extern int arch_check_bp_in_kernelspace(struct perf_event *bp); |
51 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp, | 56 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp); |
52 | struct task_struct *tsk); | ||
53 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | 57 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, |
54 | unsigned long val, void *data); | 58 | unsigned long val, void *data); |
55 | 59 | ||
diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c index 675eea7785d9..1f2cf6229862 100644 --- a/arch/sh/kernel/hw_breakpoint.c +++ b/arch/sh/kernel/hw_breakpoint.c | |||
@@ -120,25 +120,16 @@ static int get_hbp_len(u16 hbp_len) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | /* | 122 | /* |
123 | * Check for virtual address in user space. | ||
124 | */ | ||
125 | int arch_check_va_in_userspace(unsigned long va, u16 hbp_len) | ||
126 | { | ||
127 | unsigned int len; | ||
128 | |||
129 | len = get_hbp_len(hbp_len); | ||
130 | |||
131 | return (va <= TASK_SIZE - len); | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Check for virtual address in kernel space. | 123 | * Check for virtual address in kernel space. |
136 | */ | 124 | */ |
137 | static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len) | 125 | int arch_check_bp_in_kernelspace(struct perf_event *bp) |
138 | { | 126 | { |
139 | unsigned int len; | 127 | unsigned int len; |
128 | unsigned long va; | ||
129 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
140 | 130 | ||
141 | len = get_hbp_len(hbp_len); | 131 | va = info->address; |
132 | len = get_hbp_len(info->len); | ||
142 | 133 | ||
143 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); | 134 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); |
144 | } | 135 | } |
@@ -226,8 +217,7 @@ static int arch_build_bp_info(struct perf_event *bp) | |||
226 | /* | 217 | /* |
227 | * Validate the arch-specific HW Breakpoint register settings | 218 | * Validate the arch-specific HW Breakpoint register settings |
228 | */ | 219 | */ |
229 | int arch_validate_hwbkpt_settings(struct perf_event *bp, | 220 | int arch_validate_hwbkpt_settings(struct perf_event *bp) |
230 | struct task_struct *tsk) | ||
231 | { | 221 | { |
232 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | 222 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); |
233 | unsigned int align; | 223 | unsigned int align; |
@@ -270,15 +260,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, | |||
270 | if (info->address & align) | 260 | if (info->address & align) |
271 | return -EINVAL; | 261 | return -EINVAL; |
272 | 262 | ||
273 | /* Check that the virtual address is in the proper range */ | ||
274 | if (tsk) { | ||
275 | if (!arch_check_va_in_userspace(info->address, info->len)) | ||
276 | return -EFAULT; | ||
277 | } else { | ||
278 | if (!arch_check_va_in_kernelspace(info->address, info->len)) | ||
279 | return -EFAULT; | ||
280 | } | ||
281 | |||
282 | return 0; | 263 | return 0; |
283 | } | 264 | } |
284 | 265 | ||
@@ -363,8 +344,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
363 | perf_bp_event(bp, args->regs); | 344 | perf_bp_event(bp, args->regs); |
364 | 345 | ||
365 | /* Deliver the signal to userspace */ | 346 | /* Deliver the signal to userspace */ |
366 | if (arch_check_va_in_userspace(bp->attr.bp_addr, | 347 | if (!arch_check_bp_in_kernelspace(bp)) { |
367 | bp->attr.bp_len)) { | ||
368 | siginfo_t info; | 348 | siginfo_t info; |
369 | 349 | ||
370 | info.si_signo = args->signr; | 350 | info.si_signo = args->signr; |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 7759a9a93211..d4104ce9fe53 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -85,7 +85,7 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr) | |||
85 | 85 | ||
86 | bp = thread->ptrace_bps[0]; | 86 | bp = thread->ptrace_bps[0]; |
87 | if (!bp) { | 87 | if (!bp) { |
88 | hw_breakpoint_init(&attr); | 88 | ptrace_breakpoint_init(&attr); |
89 | 89 | ||
90 | attr.bp_addr = addr; | 90 | attr.bp_addr = addr; |
91 | attr.bp_len = HW_BREAKPOINT_LEN_2; | 91 | attr.bp_len = HW_BREAKPOINT_LEN_2; |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 97a95dfd1181..01177dcbe261 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -53,6 +53,7 @@ config X86 | |||
53 | select HAVE_KERNEL_LZMA | 53 | select HAVE_KERNEL_LZMA |
54 | select HAVE_KERNEL_LZO | 54 | select HAVE_KERNEL_LZO |
55 | select HAVE_HW_BREAKPOINT | 55 | select HAVE_HW_BREAKPOINT |
56 | select HAVE_MIXED_BREAKPOINTS_REGS | ||
56 | select PERF_EVENTS | 57 | select PERF_EVENTS |
57 | select ANON_INODES | 58 | select ANON_INODES |
58 | select HAVE_ARCH_KMEMCHECK | 59 | select HAVE_ARCH_KMEMCHECK |
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h index 2a1bd8f4f23a..942255310e6a 100644 --- a/arch/x86/include/asm/hw_breakpoint.h +++ b/arch/x86/include/asm/hw_breakpoint.h | |||
@@ -41,12 +41,16 @@ struct arch_hw_breakpoint { | |||
41 | /* Total number of available HW breakpoint registers */ | 41 | /* Total number of available HW breakpoint registers */ |
42 | #define HBP_NUM 4 | 42 | #define HBP_NUM 4 |
43 | 43 | ||
44 | static inline int hw_breakpoint_slots(int type) | ||
45 | { | ||
46 | return HBP_NUM; | ||
47 | } | ||
48 | |||
44 | struct perf_event; | 49 | struct perf_event; |
45 | struct pmu; | 50 | struct pmu; |
46 | 51 | ||
47 | extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len); | 52 | extern int arch_check_bp_in_kernelspace(struct perf_event *bp); |
48 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp, | 53 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp); |
49 | struct task_struct *tsk); | ||
50 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | 54 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, |
51 | unsigned long val, void *data); | 55 | unsigned long val, void *data); |
52 | 56 | ||
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index d6cc065f519f..a8f1b803d2fd 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c | |||
@@ -189,25 +189,16 @@ static int get_hbp_len(u8 hbp_len) | |||
189 | } | 189 | } |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * Check for virtual address in user space. | ||
193 | */ | ||
194 | int arch_check_va_in_userspace(unsigned long va, u8 hbp_len) | ||
195 | { | ||
196 | unsigned int len; | ||
197 | |||
198 | len = get_hbp_len(hbp_len); | ||
199 | |||
200 | return (va <= TASK_SIZE - len); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Check for virtual address in kernel space. | 192 | * Check for virtual address in kernel space. |
205 | */ | 193 | */ |
206 | static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len) | 194 | int arch_check_bp_in_kernelspace(struct perf_event *bp) |
207 | { | 195 | { |
208 | unsigned int len; | 196 | unsigned int len; |
197 | unsigned long va; | ||
198 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
209 | 199 | ||
210 | len = get_hbp_len(hbp_len); | 200 | va = info->address; |
201 | len = get_hbp_len(info->len); | ||
211 | 202 | ||
212 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); | 203 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); |
213 | } | 204 | } |
@@ -300,8 +291,7 @@ static int arch_build_bp_info(struct perf_event *bp) | |||
300 | /* | 291 | /* |
301 | * Validate the arch-specific HW Breakpoint register settings | 292 | * Validate the arch-specific HW Breakpoint register settings |
302 | */ | 293 | */ |
303 | int arch_validate_hwbkpt_settings(struct perf_event *bp, | 294 | int arch_validate_hwbkpt_settings(struct perf_event *bp) |
304 | struct task_struct *tsk) | ||
305 | { | 295 | { |
306 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | 296 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); |
307 | unsigned int align; | 297 | unsigned int align; |
@@ -314,16 +304,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, | |||
314 | 304 | ||
315 | ret = -EINVAL; | 305 | ret = -EINVAL; |
316 | 306 | ||
317 | if (info->type == X86_BREAKPOINT_EXECUTE) | ||
318 | /* | ||
319 | * Ptrace-refactoring code | ||
320 | * For now, we'll allow instruction breakpoint only for user-space | ||
321 | * addresses | ||
322 | */ | ||
323 | if ((!arch_check_va_in_userspace(info->address, info->len)) && | ||
324 | info->len != X86_BREAKPOINT_EXECUTE) | ||
325 | return ret; | ||
326 | |||
327 | switch (info->len) { | 307 | switch (info->len) { |
328 | case X86_BREAKPOINT_LEN_1: | 308 | case X86_BREAKPOINT_LEN_1: |
329 | align = 0; | 309 | align = 0; |
@@ -350,15 +330,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, | |||
350 | if (info->address & align) | 330 | if (info->address & align) |
351 | return -EINVAL; | 331 | return -EINVAL; |
352 | 332 | ||
353 | /* Check that the virtual address is in the proper range */ | ||
354 | if (tsk) { | ||
355 | if (!arch_check_va_in_userspace(info->address, info->len)) | ||
356 | return -EFAULT; | ||
357 | } else { | ||
358 | if (!arch_check_va_in_kernelspace(info->address, info->len)) | ||
359 | return -EFAULT; | ||
360 | } | ||
361 | |||
362 | return 0; | 333 | return 0; |
363 | } | 334 | } |
364 | 335 | ||
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 055be0afd330..70c4872cd8aa 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -688,7 +688,7 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
688 | struct perf_event_attr attr; | 688 | struct perf_event_attr attr; |
689 | 689 | ||
690 | if (!t->ptrace_bps[nr]) { | 690 | if (!t->ptrace_bps[nr]) { |
691 | hw_breakpoint_init(&attr); | 691 | ptrace_breakpoint_init(&attr); |
692 | /* | 692 | /* |
693 | * Put stub len and type to register (reserve) an inactive but | 693 | * Put stub len and type to register (reserve) an inactive but |
694 | * correct bp | 694 | * correct bp |
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h index c70d27af03f9..a2d6ea49ec56 100644 --- a/include/linux/hw_breakpoint.h +++ b/include/linux/hw_breakpoint.h | |||
@@ -9,9 +9,22 @@ enum { | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | enum { | 11 | enum { |
12 | HW_BREAKPOINT_R = 1, | 12 | HW_BREAKPOINT_EMPTY = 0, |
13 | HW_BREAKPOINT_W = 2, | 13 | HW_BREAKPOINT_R = 1, |
14 | HW_BREAKPOINT_X = 4, | 14 | HW_BREAKPOINT_W = 2, |
15 | HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W, | ||
16 | HW_BREAKPOINT_X = 4, | ||
17 | HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X, | ||
18 | }; | ||
19 | |||
20 | enum bp_type_idx { | ||
21 | TYPE_INST = 0, | ||
22 | #ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS | ||
23 | TYPE_DATA = 0, | ||
24 | #else | ||
25 | TYPE_DATA = 1, | ||
26 | #endif | ||
27 | TYPE_MAX | ||
15 | }; | 28 | }; |
16 | 29 | ||
17 | #ifdef __KERNEL__ | 30 | #ifdef __KERNEL__ |
@@ -34,6 +47,12 @@ static inline void hw_breakpoint_init(struct perf_event_attr *attr) | |||
34 | attr->sample_period = 1; | 47 | attr->sample_period = 1; |
35 | } | 48 | } |
36 | 49 | ||
50 | static inline void ptrace_breakpoint_init(struct perf_event_attr *attr) | ||
51 | { | ||
52 | hw_breakpoint_init(attr); | ||
53 | attr->exclude_kernel = 1; | ||
54 | } | ||
55 | |||
37 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) | 56 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) |
38 | { | 57 | { |
39 | return bp->attr.bp_addr; | 58 | return bp->attr.bp_addr; |
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index 03808ed342a6..684b710cbb91 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c | |||
@@ -40,23 +40,29 @@ | |||
40 | #include <linux/percpu.h> | 40 | #include <linux/percpu.h> |
41 | #include <linux/sched.h> | 41 | #include <linux/sched.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/slab.h> | ||
43 | #include <linux/cpu.h> | 44 | #include <linux/cpu.h> |
44 | #include <linux/smp.h> | 45 | #include <linux/smp.h> |
45 | 46 | ||
46 | #include <linux/hw_breakpoint.h> | 47 | #include <linux/hw_breakpoint.h> |
47 | 48 | ||
49 | |||
48 | /* | 50 | /* |
49 | * Constraints data | 51 | * Constraints data |
50 | */ | 52 | */ |
51 | 53 | ||
52 | /* Number of pinned cpu breakpoints in a cpu */ | 54 | /* Number of pinned cpu breakpoints in a cpu */ |
53 | static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned); | 55 | static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]); |
54 | 56 | ||
55 | /* Number of pinned task breakpoints in a cpu */ | 57 | /* Number of pinned task breakpoints in a cpu */ |
56 | static DEFINE_PER_CPU(unsigned int, nr_task_bp_pinned[HBP_NUM]); | 58 | static DEFINE_PER_CPU(unsigned int, *nr_task_bp_pinned[TYPE_MAX]); |
57 | 59 | ||
58 | /* Number of non-pinned cpu/task breakpoints in a cpu */ | 60 | /* Number of non-pinned cpu/task breakpoints in a cpu */ |
59 | static DEFINE_PER_CPU(unsigned int, nr_bp_flexible); | 61 | static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); |
62 | |||
63 | static int nr_slots[TYPE_MAX]; | ||
64 | |||
65 | static int constraints_initialized; | ||
60 | 66 | ||
61 | /* Gather the number of total pinned and un-pinned bp in a cpuset */ | 67 | /* Gather the number of total pinned and un-pinned bp in a cpuset */ |
62 | struct bp_busy_slots { | 68 | struct bp_busy_slots { |
@@ -67,16 +73,29 @@ struct bp_busy_slots { | |||
67 | /* Serialize accesses to the above constraints */ | 73 | /* Serialize accesses to the above constraints */ |
68 | static DEFINE_MUTEX(nr_bp_mutex); | 74 | static DEFINE_MUTEX(nr_bp_mutex); |
69 | 75 | ||
76 | __weak int hw_breakpoint_weight(struct perf_event *bp) | ||
77 | { | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | static inline enum bp_type_idx find_slot_idx(struct perf_event *bp) | ||
82 | { | ||
83 | if (bp->attr.bp_type & HW_BREAKPOINT_RW) | ||
84 | return TYPE_DATA; | ||
85 | |||
86 | return TYPE_INST; | ||
87 | } | ||
88 | |||
70 | /* | 89 | /* |
71 | * Report the maximum number of pinned breakpoints a task | 90 | * Report the maximum number of pinned breakpoints a task |
72 | * have in this cpu | 91 | * have in this cpu |
73 | */ | 92 | */ |
74 | static unsigned int max_task_bp_pinned(int cpu) | 93 | static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) |
75 | { | 94 | { |
76 | int i; | 95 | int i; |
77 | unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned, cpu); | 96 | unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); |
78 | 97 | ||
79 | for (i = HBP_NUM -1; i >= 0; i--) { | 98 | for (i = nr_slots[type] - 1; i >= 0; i--) { |
80 | if (tsk_pinned[i] > 0) | 99 | if (tsk_pinned[i] > 0) |
81 | return i + 1; | 100 | return i + 1; |
82 | } | 101 | } |
@@ -84,7 +103,7 @@ static unsigned int max_task_bp_pinned(int cpu) | |||
84 | return 0; | 103 | return 0; |
85 | } | 104 | } |
86 | 105 | ||
87 | static int task_bp_pinned(struct task_struct *tsk) | 106 | static int task_bp_pinned(struct task_struct *tsk, enum bp_type_idx type) |
88 | { | 107 | { |
89 | struct perf_event_context *ctx = tsk->perf_event_ctxp; | 108 | struct perf_event_context *ctx = tsk->perf_event_ctxp; |
90 | struct list_head *list; | 109 | struct list_head *list; |
@@ -105,7 +124,8 @@ static int task_bp_pinned(struct task_struct *tsk) | |||
105 | */ | 124 | */ |
106 | list_for_each_entry(bp, list, event_entry) { | 125 | list_for_each_entry(bp, list, event_entry) { |
107 | if (bp->attr.type == PERF_TYPE_BREAKPOINT) | 126 | if (bp->attr.type == PERF_TYPE_BREAKPOINT) |
108 | count++; | 127 | if (find_slot_idx(bp) == type) |
128 | count += hw_breakpoint_weight(bp); | ||
109 | } | 129 | } |
110 | 130 | ||
111 | raw_spin_unlock_irqrestore(&ctx->lock, flags); | 131 | raw_spin_unlock_irqrestore(&ctx->lock, flags); |
@@ -118,18 +138,19 @@ static int task_bp_pinned(struct task_struct *tsk) | |||
118 | * a given cpu (cpu > -1) or in all of them (cpu = -1). | 138 | * a given cpu (cpu > -1) or in all of them (cpu = -1). |
119 | */ | 139 | */ |
120 | static void | 140 | static void |
121 | fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp) | 141 | fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, |
142 | enum bp_type_idx type) | ||
122 | { | 143 | { |
123 | int cpu = bp->cpu; | 144 | int cpu = bp->cpu; |
124 | struct task_struct *tsk = bp->ctx->task; | 145 | struct task_struct *tsk = bp->ctx->task; |
125 | 146 | ||
126 | if (cpu >= 0) { | 147 | if (cpu >= 0) { |
127 | slots->pinned = per_cpu(nr_cpu_bp_pinned, cpu); | 148 | slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu); |
128 | if (!tsk) | 149 | if (!tsk) |
129 | slots->pinned += max_task_bp_pinned(cpu); | 150 | slots->pinned += max_task_bp_pinned(cpu, type); |
130 | else | 151 | else |
131 | slots->pinned += task_bp_pinned(tsk); | 152 | slots->pinned += task_bp_pinned(tsk, type); |
132 | slots->flexible = per_cpu(nr_bp_flexible, cpu); | 153 | slots->flexible = per_cpu(nr_bp_flexible[type], cpu); |
133 | 154 | ||
134 | return; | 155 | return; |
135 | } | 156 | } |
@@ -137,16 +158,16 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp) | |||
137 | for_each_online_cpu(cpu) { | 158 | for_each_online_cpu(cpu) { |
138 | unsigned int nr; | 159 | unsigned int nr; |
139 | 160 | ||
140 | nr = per_cpu(nr_cpu_bp_pinned, cpu); | 161 | nr = per_cpu(nr_cpu_bp_pinned[type], cpu); |
141 | if (!tsk) | 162 | if (!tsk) |
142 | nr += max_task_bp_pinned(cpu); | 163 | nr += max_task_bp_pinned(cpu, type); |
143 | else | 164 | else |
144 | nr += task_bp_pinned(tsk); | 165 | nr += task_bp_pinned(tsk, type); |
145 | 166 | ||
146 | if (nr > slots->pinned) | 167 | if (nr > slots->pinned) |
147 | slots->pinned = nr; | 168 | slots->pinned = nr; |
148 | 169 | ||
149 | nr = per_cpu(nr_bp_flexible, cpu); | 170 | nr = per_cpu(nr_bp_flexible[type], cpu); |
150 | 171 | ||
151 | if (nr > slots->flexible) | 172 | if (nr > slots->flexible) |
152 | slots->flexible = nr; | 173 | slots->flexible = nr; |
@@ -154,31 +175,49 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp) | |||
154 | } | 175 | } |
155 | 176 | ||
156 | /* | 177 | /* |
178 | * For now, continue to consider flexible as pinned, until we can | ||
179 | * ensure no flexible event can ever be scheduled before a pinned event | ||
180 | * in a same cpu. | ||
181 | */ | ||
182 | static void | ||
183 | fetch_this_slot(struct bp_busy_slots *slots, int weight) | ||
184 | { | ||
185 | slots->pinned += weight; | ||
186 | } | ||
187 | |||
188 | /* | ||
157 | * Add a pinned breakpoint for the given task in our constraint table | 189 | * Add a pinned breakpoint for the given task in our constraint table |
158 | */ | 190 | */ |
159 | static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable) | 191 | static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable, |
192 | enum bp_type_idx type, int weight) | ||
160 | { | 193 | { |
161 | unsigned int *tsk_pinned; | 194 | unsigned int *tsk_pinned; |
162 | int count = 0; | 195 | int old_count = 0; |
196 | int old_idx = 0; | ||
197 | int idx = 0; | ||
163 | 198 | ||
164 | count = task_bp_pinned(tsk); | 199 | old_count = task_bp_pinned(tsk, type); |
200 | old_idx = old_count - 1; | ||
201 | idx = old_idx + weight; | ||
165 | 202 | ||
166 | tsk_pinned = per_cpu(nr_task_bp_pinned, cpu); | 203 | tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); |
167 | if (enable) { | 204 | if (enable) { |
168 | tsk_pinned[count]++; | 205 | tsk_pinned[idx]++; |
169 | if (count > 0) | 206 | if (old_count > 0) |
170 | tsk_pinned[count-1]--; | 207 | tsk_pinned[old_idx]--; |
171 | } else { | 208 | } else { |
172 | tsk_pinned[count]--; | 209 | tsk_pinned[idx]--; |
173 | if (count > 0) | 210 | if (old_count > 0) |
174 | tsk_pinned[count-1]++; | 211 | tsk_pinned[old_idx]++; |
175 | } | 212 | } |
176 | } | 213 | } |
177 | 214 | ||
178 | /* | 215 | /* |
179 | * Add/remove the given breakpoint in our constraint table | 216 | * Add/remove the given breakpoint in our constraint table |
180 | */ | 217 | */ |
181 | static void toggle_bp_slot(struct perf_event *bp, bool enable) | 218 | static void |
219 | toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, | ||
220 | int weight) | ||
182 | { | 221 | { |
183 | int cpu = bp->cpu; | 222 | int cpu = bp->cpu; |
184 | struct task_struct *tsk = bp->ctx->task; | 223 | struct task_struct *tsk = bp->ctx->task; |
@@ -186,20 +225,20 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
186 | /* Pinned counter task profiling */ | 225 | /* Pinned counter task profiling */ |
187 | if (tsk) { | 226 | if (tsk) { |
188 | if (cpu >= 0) { | 227 | if (cpu >= 0) { |
189 | toggle_bp_task_slot(tsk, cpu, enable); | 228 | toggle_bp_task_slot(tsk, cpu, enable, type, weight); |
190 | return; | 229 | return; |
191 | } | 230 | } |
192 | 231 | ||
193 | for_each_online_cpu(cpu) | 232 | for_each_online_cpu(cpu) |
194 | toggle_bp_task_slot(tsk, cpu, enable); | 233 | toggle_bp_task_slot(tsk, cpu, enable, type, weight); |
195 | return; | 234 | return; |
196 | } | 235 | } |
197 | 236 | ||
198 | /* Pinned counter cpu profiling */ | 237 | /* Pinned counter cpu profiling */ |
199 | if (enable) | 238 | if (enable) |
200 | per_cpu(nr_cpu_bp_pinned, bp->cpu)++; | 239 | per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; |
201 | else | 240 | else |
202 | per_cpu(nr_cpu_bp_pinned, bp->cpu)--; | 241 | per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; |
203 | } | 242 | } |
204 | 243 | ||
205 | /* | 244 | /* |
@@ -246,14 +285,29 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
246 | static int __reserve_bp_slot(struct perf_event *bp) | 285 | static int __reserve_bp_slot(struct perf_event *bp) |
247 | { | 286 | { |
248 | struct bp_busy_slots slots = {0}; | 287 | struct bp_busy_slots slots = {0}; |
288 | enum bp_type_idx type; | ||
289 | int weight; | ||
249 | 290 | ||
250 | fetch_bp_busy_slots(&slots, bp); | 291 | /* We couldn't initialize breakpoint constraints on boot */ |
292 | if (!constraints_initialized) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | /* Basic checks */ | ||
296 | if (bp->attr.bp_type == HW_BREAKPOINT_EMPTY || | ||
297 | bp->attr.bp_type == HW_BREAKPOINT_INVALID) | ||
298 | return -EINVAL; | ||
299 | |||
300 | type = find_slot_idx(bp); | ||
301 | weight = hw_breakpoint_weight(bp); | ||
302 | |||
303 | fetch_bp_busy_slots(&slots, bp, type); | ||
304 | fetch_this_slot(&slots, weight); | ||
251 | 305 | ||
252 | /* Flexible counters need to keep at least one slot */ | 306 | /* Flexible counters need to keep at least one slot */ |
253 | if (slots.pinned + (!!slots.flexible) == HBP_NUM) | 307 | if (slots.pinned + (!!slots.flexible) > nr_slots[type]) |
254 | return -ENOSPC; | 308 | return -ENOSPC; |
255 | 309 | ||
256 | toggle_bp_slot(bp, true); | 310 | toggle_bp_slot(bp, true, type, weight); |
257 | 311 | ||
258 | return 0; | 312 | return 0; |
259 | } | 313 | } |
@@ -273,7 +327,12 @@ int reserve_bp_slot(struct perf_event *bp) | |||
273 | 327 | ||
274 | static void __release_bp_slot(struct perf_event *bp) | 328 | static void __release_bp_slot(struct perf_event *bp) |
275 | { | 329 | { |
276 | toggle_bp_slot(bp, false); | 330 | enum bp_type_idx type; |
331 | int weight; | ||
332 | |||
333 | type = find_slot_idx(bp); | ||
334 | weight = hw_breakpoint_weight(bp); | ||
335 | toggle_bp_slot(bp, false, type, weight); | ||
277 | } | 336 | } |
278 | 337 | ||
279 | void release_bp_slot(struct perf_event *bp) | 338 | void release_bp_slot(struct perf_event *bp) |
@@ -308,6 +367,28 @@ int dbg_release_bp_slot(struct perf_event *bp) | |||
308 | return 0; | 367 | return 0; |
309 | } | 368 | } |
310 | 369 | ||
370 | static int validate_hw_breakpoint(struct perf_event *bp) | ||
371 | { | ||
372 | int ret; | ||
373 | |||
374 | ret = arch_validate_hwbkpt_settings(bp); | ||
375 | if (ret) | ||
376 | return ret; | ||
377 | |||
378 | if (arch_check_bp_in_kernelspace(bp)) { | ||
379 | if (bp->attr.exclude_kernel) | ||
380 | return -EINVAL; | ||
381 | /* | ||
382 | * Don't let unprivileged users set a breakpoint in the trap | ||
383 | * path to avoid trap recursion attacks. | ||
384 | */ | ||
385 | if (!capable(CAP_SYS_ADMIN)) | ||
386 | return -EPERM; | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
311 | int register_perf_hw_breakpoint(struct perf_event *bp) | 392 | int register_perf_hw_breakpoint(struct perf_event *bp) |
312 | { | 393 | { |
313 | int ret; | 394 | int ret; |
@@ -316,17 +397,7 @@ int register_perf_hw_breakpoint(struct perf_event *bp) | |||
316 | if (ret) | 397 | if (ret) |
317 | return ret; | 398 | return ret; |
318 | 399 | ||
319 | /* | 400 | ret = validate_hw_breakpoint(bp); |
320 | * Ptrace breakpoints can be temporary perf events only | ||
321 | * meant to reserve a slot. In this case, it is created disabled and | ||
322 | * we don't want to check the params right now (as we put a null addr) | ||
323 | * But perf tools create events as disabled and we want to check | ||
324 | * the params for them. | ||
325 | * This is a quick hack that will be removed soon, once we remove | ||
326 | * the tmp breakpoints from ptrace | ||
327 | */ | ||
328 | if (!bp->attr.disabled || !bp->overflow_handler) | ||
329 | ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task); | ||
330 | 401 | ||
331 | /* if arch_validate_hwbkpt_settings() fails then release bp slot */ | 402 | /* if arch_validate_hwbkpt_settings() fails then release bp slot */ |
332 | if (ret) | 403 | if (ret) |
@@ -373,7 +444,7 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att | |||
373 | if (attr->disabled) | 444 | if (attr->disabled) |
374 | goto end; | 445 | goto end; |
375 | 446 | ||
376 | err = arch_validate_hwbkpt_settings(bp, bp->ctx->task); | 447 | err = validate_hw_breakpoint(bp); |
377 | if (!err) | 448 | if (!err) |
378 | perf_event_enable(bp); | 449 | perf_event_enable(bp); |
379 | 450 | ||
@@ -480,7 +551,36 @@ static struct notifier_block hw_breakpoint_exceptions_nb = { | |||
480 | 551 | ||
481 | static int __init init_hw_breakpoint(void) | 552 | static int __init init_hw_breakpoint(void) |
482 | { | 553 | { |
554 | unsigned int **task_bp_pinned; | ||
555 | int cpu, err_cpu; | ||
556 | int i; | ||
557 | |||
558 | for (i = 0; i < TYPE_MAX; i++) | ||
559 | nr_slots[i] = hw_breakpoint_slots(i); | ||
560 | |||
561 | for_each_possible_cpu(cpu) { | ||
562 | for (i = 0; i < TYPE_MAX; i++) { | ||
563 | task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu); | ||
564 | *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i], | ||
565 | GFP_KERNEL); | ||
566 | if (!*task_bp_pinned) | ||
567 | goto err_alloc; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | constraints_initialized = 1; | ||
572 | |||
483 | return register_die_notifier(&hw_breakpoint_exceptions_nb); | 573 | return register_die_notifier(&hw_breakpoint_exceptions_nb); |
574 | |||
575 | err_alloc: | ||
576 | for_each_possible_cpu(err_cpu) { | ||
577 | if (err_cpu == cpu) | ||
578 | break; | ||
579 | for (i = 0; i < TYPE_MAX; i++) | ||
580 | kfree(per_cpu(nr_task_bp_pinned[i], cpu)); | ||
581 | } | ||
582 | |||
583 | return -ENOMEM; | ||
484 | } | 584 | } |
485 | core_initcall(init_hw_breakpoint); | 585 | core_initcall(init_hw_breakpoint); |
486 | 586 | ||
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c index d59cd6879477..8eaf00749b65 100644 --- a/kernel/trace/trace_ksym.c +++ b/kernel/trace/trace_ksym.c | |||
@@ -34,12 +34,6 @@ | |||
34 | 34 | ||
35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
36 | 36 | ||
37 | /* | ||
38 | * For now, let us restrict the no. of symbols traced simultaneously to number | ||
39 | * of available hardware breakpoint registers. | ||
40 | */ | ||
41 | #define KSYM_TRACER_MAX HBP_NUM | ||
42 | |||
43 | #define KSYM_TRACER_OP_LEN 3 /* rw- */ | 37 | #define KSYM_TRACER_OP_LEN 3 /* rw- */ |
44 | 38 | ||
45 | struct trace_ksym { | 39 | struct trace_ksym { |
@@ -53,7 +47,6 @@ struct trace_ksym { | |||
53 | 47 | ||
54 | static struct trace_array *ksym_trace_array; | 48 | static struct trace_array *ksym_trace_array; |
55 | 49 | ||
56 | static unsigned int ksym_filter_entry_count; | ||
57 | static unsigned int ksym_tracing_enabled; | 50 | static unsigned int ksym_tracing_enabled; |
58 | 51 | ||
59 | static HLIST_HEAD(ksym_filter_head); | 52 | static HLIST_HEAD(ksym_filter_head); |
@@ -181,13 +174,6 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr) | |||
181 | struct trace_ksym *entry; | 174 | struct trace_ksym *entry; |
182 | int ret = -ENOMEM; | 175 | int ret = -ENOMEM; |
183 | 176 | ||
184 | if (ksym_filter_entry_count >= KSYM_TRACER_MAX) { | ||
185 | printk(KERN_ERR "ksym_tracer: Maximum limit:(%d) reached. No" | ||
186 | " new requests for tracing can be accepted now.\n", | ||
187 | KSYM_TRACER_MAX); | ||
188 | return -ENOSPC; | ||
189 | } | ||
190 | |||
191 | entry = kzalloc(sizeof(struct trace_ksym), GFP_KERNEL); | 177 | entry = kzalloc(sizeof(struct trace_ksym), GFP_KERNEL); |
192 | if (!entry) | 178 | if (!entry) |
193 | return -ENOMEM; | 179 | return -ENOMEM; |
@@ -203,13 +189,17 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr) | |||
203 | 189 | ||
204 | if (IS_ERR(entry->ksym_hbp)) { | 190 | if (IS_ERR(entry->ksym_hbp)) { |
205 | ret = PTR_ERR(entry->ksym_hbp); | 191 | ret = PTR_ERR(entry->ksym_hbp); |
206 | printk(KERN_INFO "ksym_tracer request failed. Try again" | 192 | if (ret == -ENOSPC) { |
207 | " later!!\n"); | 193 | printk(KERN_ERR "ksym_tracer: Maximum limit reached." |
194 | " No new requests for tracing can be accepted now.\n"); | ||
195 | } else { | ||
196 | printk(KERN_INFO "ksym_tracer request failed. Try again" | ||
197 | " later!!\n"); | ||
198 | } | ||
208 | goto err; | 199 | goto err; |
209 | } | 200 | } |
210 | 201 | ||
211 | hlist_add_head_rcu(&(entry->ksym_hlist), &ksym_filter_head); | 202 | hlist_add_head_rcu(&(entry->ksym_hlist), &ksym_filter_head); |
212 | ksym_filter_entry_count++; | ||
213 | 203 | ||
214 | return 0; | 204 | return 0; |
215 | 205 | ||
@@ -265,7 +255,6 @@ static void __ksym_trace_reset(void) | |||
265 | hlist_for_each_entry_safe(entry, node, node1, &ksym_filter_head, | 255 | hlist_for_each_entry_safe(entry, node, node1, &ksym_filter_head, |
266 | ksym_hlist) { | 256 | ksym_hlist) { |
267 | unregister_wide_hw_breakpoint(entry->ksym_hbp); | 257 | unregister_wide_hw_breakpoint(entry->ksym_hbp); |
268 | ksym_filter_entry_count--; | ||
269 | hlist_del_rcu(&(entry->ksym_hlist)); | 258 | hlist_del_rcu(&(entry->ksym_hlist)); |
270 | synchronize_rcu(); | 259 | synchronize_rcu(); |
271 | kfree(entry); | 260 | kfree(entry); |
@@ -338,7 +327,6 @@ static ssize_t ksym_trace_filter_write(struct file *file, | |||
338 | goto out_unlock; | 327 | goto out_unlock; |
339 | } | 328 | } |
340 | /* Error or "symbol:---" case: drop it */ | 329 | /* Error or "symbol:---" case: drop it */ |
341 | ksym_filter_entry_count--; | ||
342 | hlist_del_rcu(&(entry->ksym_hlist)); | 330 | hlist_del_rcu(&(entry->ksym_hlist)); |
343 | synchronize_rcu(); | 331 | synchronize_rcu(); |
344 | kfree(entry); | 332 | kfree(entry); |
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt index d729cee8d987..ee6525ee6d69 100644 --- a/tools/perf/Documentation/perf-trace-perl.txt +++ b/tools/perf/Documentation/perf-trace-perl.txt | |||
@@ -49,12 +49,10 @@ available as calls back into the perf executable (see below). | |||
49 | As an example, the following perf record command can be used to record | 49 | As an example, the following perf record command can be used to record |
50 | all sched_wakeup events in the system: | 50 | all sched_wakeup events in the system: |
51 | 51 | ||
52 | # perf record -c 1 -f -a -M -R -e sched:sched_wakeup | 52 | # perf record -a -e sched:sched_wakeup |
53 | 53 | ||
54 | Traces meant to be processed using a script should be recorded with | 54 | Traces meant to be processed using a script should be recorded with |
55 | the above options: -c 1 says to sample every event, -a to enable | 55 | the above option: -a to enable system-wide collection. |
56 | system-wide collection, -M to multiplex the output, and -R to collect | ||
57 | raw samples. | ||
58 | 56 | ||
59 | The format file for the sched_wakep event defines the following fields | 57 | The format file for the sched_wakep event defines the following fields |
60 | (see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): | 58 | (see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): |
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-trace-python.txt index a241aca77184..16a86500dcf1 100644 --- a/tools/perf/Documentation/perf-trace-python.txt +++ b/tools/perf/Documentation/perf-trace-python.txt | |||
@@ -93,7 +93,7 @@ don't care how it exited, so we'll use 'perf record' to record only | |||
93 | the sys_enter events: | 93 | the sys_enter events: |
94 | 94 | ||
95 | ---- | 95 | ---- |
96 | # perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter | 96 | # perf record -a -e raw_syscalls:sys_enter |
97 | 97 | ||
98 | ^C[ perf record: Woken up 1 times to write data ] | 98 | ^C[ perf record: Woken up 1 times to write data ] |
99 | [ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ] | 99 | [ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ] |
@@ -359,7 +359,7 @@ your script: | |||
359 | # cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record | 359 | # cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record |
360 | 360 | ||
361 | #!/bin/bash | 361 | #!/bin/bash |
362 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter | 362 | perf record -a -e raw_syscalls:sys_enter |
363 | ---- | 363 | ---- |
364 | 364 | ||
365 | The 'report' script is also a shell script with the same base name as | 365 | The 'report' script is also a shell script with the same base name as |
@@ -449,12 +449,10 @@ available as calls back into the perf executable (see below). | |||
449 | As an example, the following perf record command can be used to record | 449 | As an example, the following perf record command can be used to record |
450 | all sched_wakeup events in the system: | 450 | all sched_wakeup events in the system: |
451 | 451 | ||
452 | # perf record -c 1 -f -a -M -R -e sched:sched_wakeup | 452 | # perf record -a -e sched:sched_wakeup |
453 | 453 | ||
454 | Traces meant to be processed using a script should be recorded with | 454 | Traces meant to be processed using a script should be recorded with |
455 | the above options: -c 1 says to sample every event, -a to enable | 455 | the above option: -a to enable system-wide collection. |
456 | system-wide collection, -M to multiplex the output, and -R to collect | ||
457 | raw samples. | ||
458 | 456 | ||
459 | The format file for the sched_wakep event defines the following fields | 457 | The format file for the sched_wakep event defines the following fields |
460 | (see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): | 458 | (see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): |
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record index e6cb1474f8e8..423ad6aed056 100644 --- a/tools/perf/scripts/perl/bin/check-perf-trace-record +++ b/tools/perf/scripts/perl/bin/check-perf-trace-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree | 2 | perf record -a -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree |
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record index 6ad9b8f5f009..eb5846bcb565 100644 --- a/tools/perf/scripts/perl/bin/failed-syscalls-record +++ b/tools/perf/scripts/perl/bin/failed-syscalls-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit $@ | 2 | perf record -a -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record index a828679837a8..5bfaae5a6cba 100644 --- a/tools/perf/scripts/perl/bin/rw-by-file-record +++ b/tools/perf/scripts/perl/bin/rw-by-file-record | |||
@@ -1,3 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ | 2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ |
3 | 3 | ||
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record index 63976bf11e8b..6e0b2f7755ac 100644 --- a/tools/perf/scripts/perl/bin/rw-by-pid-record +++ b/tools/perf/scripts/perl/bin/rw-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ | 2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ |
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record index 63976bf11e8b..6e0b2f7755ac 100644 --- a/tools/perf/scripts/perl/bin/rwtop-record +++ b/tools/perf/scripts/perl/bin/rwtop-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ | 2 | perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ |
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record index 9c0cf588ff8c..9f2acaaae9f0 100644 --- a/tools/perf/scripts/perl/bin/wakeup-latency-record +++ b/tools/perf/scripts/perl/bin/wakeup-latency-record | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup $@ | 2 | perf record -a -e sched:sched_switch -e sched:sched_wakeup $@ |
3 | 3 | ||
4 | 4 | ||
5 | 5 | ||
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record index c2a1a9421133..85301f2471ff 100644 --- a/tools/perf/scripts/perl/bin/workqueue-stats-record +++ b/tools/perf/scripts/perl/bin/workqueue-stats-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ | 2 | perf record -a -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ |
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record index 6ad9b8f5f009..eb5846bcb565 100644 --- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit $@ | 2 | perf record -a -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record index 27ccffa26ab4..1fc5998b721d 100644 --- a/tools/perf/scripts/python/bin/sctop-record +++ b/tools/perf/scripts/python/bin/sctop-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ | 2 | perf record -a -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record index 27ccffa26ab4..1fc5998b721d 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ | 2 | perf record -a -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record index 27ccffa26ab4..1fc5998b721d 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-record +++ b/tools/perf/scripts/python/bin/syscall-counts-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ | 2 | perf record -a -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index d6ef414075a6..069f261b225c 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -691,11 +691,6 @@ static int __read_expected(enum event_type expect, const char *str, | |||
691 | return ret; | 691 | return ret; |
692 | } | 692 | } |
693 | 693 | ||
694 | static int read_expected_warn(enum event_type expect, const char *str, bool warn) | ||
695 | { | ||
696 | return __read_expected(expect, str, 1, warn); | ||
697 | } | ||
698 | |||
699 | static int read_expected(enum event_type expect, const char *str) | 694 | static int read_expected(enum event_type expect, const char *str) |
700 | { | 695 | { |
701 | return __read_expected(expect, str, 1, true); | 696 | return __read_expected(expect, str, 1, true); |
@@ -3104,90 +3099,6 @@ static void print_args(struct print_arg *args) | |||
3104 | } | 3099 | } |
3105 | } | 3100 | } |
3106 | 3101 | ||
3107 | static void parse_header_field(const char *field, | ||
3108 | int *offset, int *size, bool warn) | ||
3109 | { | ||
3110 | char *token; | ||
3111 | int type; | ||
3112 | |||
3113 | if (read_expected(EVENT_ITEM, "field") < 0) | ||
3114 | return; | ||
3115 | if (read_expected(EVENT_OP, ":") < 0) | ||
3116 | return; | ||
3117 | |||
3118 | /* type */ | ||
3119 | if (read_expect_type(EVENT_ITEM, &token) < 0) | ||
3120 | goto fail; | ||
3121 | free_token(token); | ||
3122 | |||
3123 | if (read_expected_warn(EVENT_ITEM, field, warn) < 0) | ||
3124 | return; | ||
3125 | if (read_expected(EVENT_OP, ";") < 0) | ||
3126 | return; | ||
3127 | if (read_expected(EVENT_ITEM, "offset") < 0) | ||
3128 | return; | ||
3129 | if (read_expected(EVENT_OP, ":") < 0) | ||
3130 | return; | ||
3131 | if (read_expect_type(EVENT_ITEM, &token) < 0) | ||
3132 | goto fail; | ||
3133 | *offset = atoi(token); | ||
3134 | free_token(token); | ||
3135 | if (read_expected(EVENT_OP, ";") < 0) | ||
3136 | return; | ||
3137 | if (read_expected(EVENT_ITEM, "size") < 0) | ||
3138 | return; | ||
3139 | if (read_expected(EVENT_OP, ":") < 0) | ||
3140 | return; | ||
3141 | if (read_expect_type(EVENT_ITEM, &token) < 0) | ||
3142 | goto fail; | ||
3143 | *size = atoi(token); | ||
3144 | free_token(token); | ||
3145 | if (read_expected(EVENT_OP, ";") < 0) | ||
3146 | return; | ||
3147 | type = read_token(&token); | ||
3148 | if (type != EVENT_NEWLINE) { | ||
3149 | /* newer versions of the kernel have a "signed" type */ | ||
3150 | if (type != EVENT_ITEM) | ||
3151 | goto fail; | ||
3152 | |||
3153 | if (strcmp(token, "signed") != 0) | ||
3154 | goto fail; | ||
3155 | |||
3156 | free_token(token); | ||
3157 | |||
3158 | if (read_expected(EVENT_OP, ":") < 0) | ||
3159 | return; | ||
3160 | |||
3161 | if (read_expect_type(EVENT_ITEM, &token)) | ||
3162 | goto fail; | ||
3163 | |||
3164 | free_token(token); | ||
3165 | if (read_expected(EVENT_OP, ";") < 0) | ||
3166 | return; | ||
3167 | |||
3168 | if (read_expect_type(EVENT_NEWLINE, &token)) | ||
3169 | goto fail; | ||
3170 | } | ||
3171 | fail: | ||
3172 | free_token(token); | ||
3173 | } | ||
3174 | |||
3175 | int parse_header_page(char *buf, unsigned long size) | ||
3176 | { | ||
3177 | init_input_buf(buf, size); | ||
3178 | |||
3179 | parse_header_field("timestamp", &header_page_ts_offset, | ||
3180 | &header_page_ts_size, true); | ||
3181 | parse_header_field("commit", &header_page_size_offset, | ||
3182 | &header_page_size_size, true); | ||
3183 | parse_header_field("overwrite", &header_page_overwrite_offset, | ||
3184 | &header_page_overwrite_size, false); | ||
3185 | parse_header_field("data", &header_page_data_offset, | ||
3186 | &header_page_data_size, true); | ||
3187 | |||
3188 | return 0; | ||
3189 | } | ||
3190 | |||
3191 | int parse_ftrace_file(char *buf, unsigned long size) | 3102 | int parse_ftrace_file(char *buf, unsigned long size) |
3192 | { | 3103 | { |
3193 | struct format_field *field; | 3104 | struct format_field *field; |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 43f19c1fed3a..cb54cd002f49 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -53,6 +53,12 @@ static unsigned long page_size; | |||
53 | static ssize_t calc_data_size; | 53 | static ssize_t calc_data_size; |
54 | static bool repipe; | 54 | static bool repipe; |
55 | 55 | ||
56 | /* If it fails, the next read will report it */ | ||
57 | static void skip(int size) | ||
58 | { | ||
59 | lseek(input_fd, size, SEEK_CUR); | ||
60 | } | ||
61 | |||
56 | static int do_read(int fd, void *buf, int size) | 62 | static int do_read(int fd, void *buf, int size) |
57 | { | 63 | { |
58 | int rsize = size; | 64 | int rsize = size; |
@@ -184,7 +190,6 @@ static void read_ftrace_printk(void) | |||
184 | static void read_header_files(void) | 190 | static void read_header_files(void) |
185 | { | 191 | { |
186 | unsigned long long size; | 192 | unsigned long long size; |
187 | char *header_page; | ||
188 | char *header_event; | 193 | char *header_event; |
189 | char buf[BUFSIZ]; | 194 | char buf[BUFSIZ]; |
190 | 195 | ||
@@ -194,10 +199,7 @@ static void read_header_files(void) | |||
194 | die("did not read header page"); | 199 | die("did not read header page"); |
195 | 200 | ||
196 | size = read8(); | 201 | size = read8(); |
197 | header_page = malloc_or_die(size); | 202 | skip(size); |
198 | read_or_die(header_page, size); | ||
199 | parse_header_page(header_page, size); | ||
200 | free(header_page); | ||
201 | 203 | ||
202 | /* | 204 | /* |
203 | * The size field in the page is of type long, | 205 | * The size field in the page is of type long, |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index ebfee80e4a07..406d452956db 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -244,7 +244,6 @@ extern int header_page_data_size; | |||
244 | 244 | ||
245 | extern bool latency_format; | 245 | extern bool latency_format; |
246 | 246 | ||
247 | int parse_header_page(char *buf, unsigned long size); | ||
248 | int trace_parse_common_type(void *data); | 247 | int trace_parse_common_type(void *data); |
249 | int trace_parse_common_pid(void *data); | 248 | int trace_parse_common_pid(void *data); |
250 | int parse_common_pc(void *data); | 249 | int parse_common_pc(void *data); |