aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-12-05 03:44:31 -0500
committerFrederic Weisbecker <fweisbec@gmail.com>2009-12-06 02:27:18 -0500
commitb326e9560a28fc3e950637ef51847ed8f05c1335 (patch)
tree0804c8c4f28d4ae152d5e9205ce5a958f0d26b79 /kernel
parent2f0993e0fb663c49e4d1e02654f6203246be4817 (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 'kernel')
-rw-r--r--kernel/hw_breakpoint.c17
-rw-r--r--kernel/perf_event.c24
-rw-r--r--kernel/trace/trace_ksym.c5
3 files changed, 17 insertions, 29 deletions
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index 2d10b012828f..b600fc27f161 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -259,7 +259,7 @@ void release_bp_slot(struct perf_event *bp)
259} 259}
260 260
261 261
262int __register_perf_hw_breakpoint(struct perf_event *bp) 262int register_perf_hw_breakpoint(struct perf_event *bp)
263{ 263{
264 int ret; 264 int ret;
265 265
@@ -276,19 +276,12 @@ int __register_perf_hw_breakpoint(struct perf_event *bp)
276 * This is a quick hack that will be removed soon, once we remove 276 * This is a quick hack that will be removed soon, once we remove
277 * the tmp breakpoints from ptrace 277 * the tmp breakpoints from ptrace
278 */ 278 */
279 if (!bp->attr.disabled || bp->callback == perf_bp_event) 279 if (!bp->attr.disabled || !bp->overflow_handler)
280 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task); 280 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
281 281
282 return ret; 282 return ret;
283} 283}
284 284
285int register_perf_hw_breakpoint(struct perf_event *bp)
286{
287 bp->callback = perf_bp_event;
288
289 return __register_perf_hw_breakpoint(bp);
290}
291
292/** 285/**
293 * register_user_hw_breakpoint - register a hardware breakpoint for user space 286 * register_user_hw_breakpoint - register a hardware breakpoint for user space
294 * @attr: breakpoint attributes 287 * @attr: breakpoint attributes
@@ -297,7 +290,7 @@ int register_perf_hw_breakpoint(struct perf_event *bp)
297 */ 290 */
298struct perf_event * 291struct perf_event *
299register_user_hw_breakpoint(struct perf_event_attr *attr, 292register_user_hw_breakpoint(struct perf_event_attr *attr,
300 perf_callback_t triggered, 293 perf_overflow_handler_t triggered,
301 struct task_struct *tsk) 294 struct task_struct *tsk)
302{ 295{
303 return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered); 296 return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
@@ -322,7 +315,7 @@ modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
322 unregister_hw_breakpoint(bp); 315 unregister_hw_breakpoint(bp);
323 316
324 return perf_event_create_kernel_counter(attr, -1, bp->ctx->task->pid, 317 return perf_event_create_kernel_counter(attr, -1, bp->ctx->task->pid,
325 bp->callback); 318 bp->overflow_handler);
326} 319}
327EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); 320EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
328 321
@@ -347,7 +340,7 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
347 */ 340 */
348struct perf_event ** 341struct perf_event **
349register_wide_hw_breakpoint(struct perf_event_attr *attr, 342register_wide_hw_breakpoint(struct perf_event_attr *attr,
350 perf_callback_t triggered) 343 perf_overflow_handler_t triggered)
351{ 344{
352 struct perf_event **cpu_events, **pevent, *bp; 345 struct perf_event **cpu_events, **pevent, *bp;
353 long err; 346 long err;
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 6b7ddba1dd64..fd43ff4ac860 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -4286,15 +4286,8 @@ static void bp_perf_event_destroy(struct perf_event *event)
4286static const struct pmu *bp_perf_event_init(struct perf_event *bp) 4286static const struct pmu *bp_perf_event_init(struct perf_event *bp)
4287{ 4287{
4288 int err; 4288 int err;
4289 /* 4289
4290 * The breakpoint is already filled if we haven't created the counter 4290 err = register_perf_hw_breakpoint(bp);
4291 * through perf syscall
4292 * FIXME: manage to get trigerred to NULL if it comes from syscalls
4293 */
4294 if (!bp->callback)
4295 err = register_perf_hw_breakpoint(bp);
4296 else
4297 err = __register_perf_hw_breakpoint(bp);
4298 if (err) 4291 if (err)
4299 return ERR_PTR(err); 4292 return ERR_PTR(err);
4300 4293
@@ -4390,7 +4383,7 @@ perf_event_alloc(struct perf_event_attr *attr,
4390 struct perf_event_context *ctx, 4383 struct perf_event_context *ctx,
4391 struct perf_event *group_leader, 4384 struct perf_event *group_leader,
4392 struct perf_event *parent_event, 4385 struct perf_event *parent_event,
4393 perf_callback_t callback, 4386 perf_overflow_handler_t overflow_handler,
4394 gfp_t gfpflags) 4387 gfp_t gfpflags)
4395{ 4388{
4396 const struct pmu *pmu; 4389 const struct pmu *pmu;
@@ -4433,10 +4426,10 @@ perf_event_alloc(struct perf_event_attr *attr,
4433 4426
4434 event->state = PERF_EVENT_STATE_INACTIVE; 4427 event->state = PERF_EVENT_STATE_INACTIVE;
4435 4428
4436 if (!callback && parent_event) 4429 if (!overflow_handler && parent_event)
4437 callback = parent_event->callback; 4430 overflow_handler = parent_event->overflow_handler;
4438 4431
4439 event->callback = callback; 4432 event->overflow_handler = overflow_handler;
4440 4433
4441 if (attr->disabled) 4434 if (attr->disabled)
4442 event->state = PERF_EVENT_STATE_OFF; 4435 event->state = PERF_EVENT_STATE_OFF;
@@ -4776,7 +4769,8 @@ err_put_context:
4776 */ 4769 */
4777struct perf_event * 4770struct perf_event *
4778perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, 4771perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
4779 pid_t pid, perf_callback_t callback) 4772 pid_t pid,
4773 perf_overflow_handler_t overflow_handler)
4780{ 4774{
4781 struct perf_event *event; 4775 struct perf_event *event;
4782 struct perf_event_context *ctx; 4776 struct perf_event_context *ctx;
@@ -4793,7 +4787,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
4793 } 4787 }
4794 4788
4795 event = perf_event_alloc(attr, cpu, ctx, NULL, 4789 event = perf_event_alloc(attr, cpu, ctx, NULL,
4796 NULL, callback, GFP_KERNEL); 4790 NULL, overflow_handler, GFP_KERNEL);
4797 if (IS_ERR(event)) { 4791 if (IS_ERR(event)) {
4798 err = PTR_ERR(event); 4792 err = PTR_ERR(event);
4799 goto err_put_context; 4793 goto err_put_context;
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c
index ddfa0fd43bc0..acb87d4a4ac1 100644
--- a/kernel/trace/trace_ksym.c
+++ b/kernel/trace/trace_ksym.c
@@ -79,11 +79,12 @@ void ksym_collect_stats(unsigned long hbp_hit_addr)
79} 79}
80#endif /* CONFIG_PROFILE_KSYM_TRACER */ 80#endif /* CONFIG_PROFILE_KSYM_TRACER */
81 81
82void ksym_hbp_handler(struct perf_event *hbp, void *data) 82void ksym_hbp_handler(struct perf_event *hbp, int nmi,
83 struct perf_sample_data *data,
84 struct pt_regs *regs)
83{ 85{
84 struct ring_buffer_event *event; 86 struct ring_buffer_event *event;
85 struct ksym_trace_entry *entry; 87 struct ksym_trace_entry *entry;
86 struct pt_regs *regs = data;
87 struct ring_buffer *buffer; 88 struct ring_buffer *buffer;
88 int pc; 89 int pc;
89 90