diff options
author | Avi Kivity <avi@redhat.com> | 2011-06-29 11:42:35 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-07-01 05:06:38 -0400 |
commit | 4dc0da86967d5463708631d02a70cfed5b104884 (patch) | |
tree | e09071a62f2457b710ff69df3be1bff39340a4c6 /kernel/events | |
parent | 89d6c0b5bdbb1927775584dcf532d98b3efe1477 (diff) |
perf: Add context field to perf_event
The perf_event overflow handler does not receive any caller-derived
argument, so many callers need to resort to looking up the perf_event
in their local data structure. This is ugly and doesn't scale if a
single callback services many perf_events.
Fix by adding a context parameter to perf_event_create_kernel_counter()
(and derived hardware breakpoints APIs) and storing it in the perf_event.
The field can be accessed from the callback as event->overflow_handler_context.
All callers are updated.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1309362157-6596-2-git-send-email-avi@redhat.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/core.c | 21 | ||||
-rw-r--r-- | kernel/events/hw_breakpoint.c | 10 |
2 files changed, 22 insertions, 9 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 81de28dcca8c..ba8e0f4a20e6 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -5745,7 +5745,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
5745 | struct task_struct *task, | 5745 | struct task_struct *task, |
5746 | struct perf_event *group_leader, | 5746 | struct perf_event *group_leader, |
5747 | struct perf_event *parent_event, | 5747 | struct perf_event *parent_event, |
5748 | perf_overflow_handler_t overflow_handler) | 5748 | perf_overflow_handler_t overflow_handler, |
5749 | void *context) | ||
5749 | { | 5750 | { |
5750 | struct pmu *pmu; | 5751 | struct pmu *pmu; |
5751 | struct perf_event *event; | 5752 | struct perf_event *event; |
@@ -5803,10 +5804,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
5803 | #endif | 5804 | #endif |
5804 | } | 5805 | } |
5805 | 5806 | ||
5806 | if (!overflow_handler && parent_event) | 5807 | if (!overflow_handler && parent_event) { |
5807 | overflow_handler = parent_event->overflow_handler; | 5808 | overflow_handler = parent_event->overflow_handler; |
5809 | context = parent_event->overflow_handler_context; | ||
5810 | } | ||
5808 | 5811 | ||
5809 | event->overflow_handler = overflow_handler; | 5812 | event->overflow_handler = overflow_handler; |
5813 | event->overflow_handler_context = context; | ||
5810 | 5814 | ||
5811 | if (attr->disabled) | 5815 | if (attr->disabled) |
5812 | event->state = PERF_EVENT_STATE_OFF; | 5816 | event->state = PERF_EVENT_STATE_OFF; |
@@ -6073,7 +6077,8 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6073 | } | 6077 | } |
6074 | } | 6078 | } |
6075 | 6079 | ||
6076 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL); | 6080 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, |
6081 | NULL, NULL); | ||
6077 | if (IS_ERR(event)) { | 6082 | if (IS_ERR(event)) { |
6078 | err = PTR_ERR(event); | 6083 | err = PTR_ERR(event); |
6079 | goto err_task; | 6084 | goto err_task; |
@@ -6258,7 +6263,8 @@ err_fd: | |||
6258 | struct perf_event * | 6263 | struct perf_event * |
6259 | perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | 6264 | perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, |
6260 | struct task_struct *task, | 6265 | struct task_struct *task, |
6261 | perf_overflow_handler_t overflow_handler) | 6266 | perf_overflow_handler_t overflow_handler, |
6267 | void *context) | ||
6262 | { | 6268 | { |
6263 | struct perf_event_context *ctx; | 6269 | struct perf_event_context *ctx; |
6264 | struct perf_event *event; | 6270 | struct perf_event *event; |
@@ -6268,7 +6274,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | |||
6268 | * Get the target context (task or percpu): | 6274 | * Get the target context (task or percpu): |
6269 | */ | 6275 | */ |
6270 | 6276 | ||
6271 | event = perf_event_alloc(attr, cpu, task, NULL, NULL, overflow_handler); | 6277 | event = perf_event_alloc(attr, cpu, task, NULL, NULL, |
6278 | overflow_handler, context); | ||
6272 | if (IS_ERR(event)) { | 6279 | if (IS_ERR(event)) { |
6273 | err = PTR_ERR(event); | 6280 | err = PTR_ERR(event); |
6274 | goto err; | 6281 | goto err; |
@@ -6552,7 +6559,7 @@ inherit_event(struct perf_event *parent_event, | |||
6552 | parent_event->cpu, | 6559 | parent_event->cpu, |
6553 | child, | 6560 | child, |
6554 | group_leader, parent_event, | 6561 | group_leader, parent_event, |
6555 | NULL); | 6562 | NULL, NULL); |
6556 | if (IS_ERR(child_event)) | 6563 | if (IS_ERR(child_event)) |
6557 | return child_event; | 6564 | return child_event; |
6558 | get_ctx(child_ctx); | 6565 | get_ctx(child_ctx); |
@@ -6579,6 +6586,8 @@ inherit_event(struct perf_event *parent_event, | |||
6579 | 6586 | ||
6580 | child_event->ctx = child_ctx; | 6587 | child_event->ctx = child_ctx; |
6581 | child_event->overflow_handler = parent_event->overflow_handler; | 6588 | child_event->overflow_handler = parent_event->overflow_handler; |
6589 | child_event->overflow_handler_context | ||
6590 | = parent_event->overflow_handler_context; | ||
6582 | 6591 | ||
6583 | /* | 6592 | /* |
6584 | * Precalculate sample_data sizes | 6593 | * Precalculate sample_data sizes |
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 086adf25a55e..b7971d6f38bf 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
@@ -431,9 +431,11 @@ int register_perf_hw_breakpoint(struct perf_event *bp) | |||
431 | struct perf_event * | 431 | struct perf_event * |
432 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 432 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
433 | perf_overflow_handler_t triggered, | 433 | perf_overflow_handler_t triggered, |
434 | void *context, | ||
434 | struct task_struct *tsk) | 435 | struct task_struct *tsk) |
435 | { | 436 | { |
436 | return perf_event_create_kernel_counter(attr, -1, tsk, triggered); | 437 | return perf_event_create_kernel_counter(attr, -1, tsk, triggered, |
438 | context); | ||
437 | } | 439 | } |
438 | EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); | 440 | EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); |
439 | 441 | ||
@@ -502,7 +504,8 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint); | |||
502 | */ | 504 | */ |
503 | struct perf_event * __percpu * | 505 | struct perf_event * __percpu * |
504 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 506 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
505 | perf_overflow_handler_t triggered) | 507 | perf_overflow_handler_t triggered, |
508 | void *context) | ||
506 | { | 509 | { |
507 | struct perf_event * __percpu *cpu_events, **pevent, *bp; | 510 | struct perf_event * __percpu *cpu_events, **pevent, *bp; |
508 | long err; | 511 | long err; |
@@ -515,7 +518,8 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr, | |||
515 | get_online_cpus(); | 518 | get_online_cpus(); |
516 | for_each_online_cpu(cpu) { | 519 | for_each_online_cpu(cpu) { |
517 | pevent = per_cpu_ptr(cpu_events, cpu); | 520 | pevent = per_cpu_ptr(cpu_events, cpu); |
518 | bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered); | 521 | bp = perf_event_create_kernel_counter(attr, cpu, NULL, |
522 | triggered, context); | ||
519 | 523 | ||
520 | *pevent = bp; | 524 | *pevent = bp; |
521 | 525 | ||