diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2012-06-15 14:31:33 +0800 |
---|---|---|
committer | Simon Shields <keepcalm444@gmail.com> | 2016-12-13 00:14:52 +1100 |
commit | ab5cf14fb4432d2550896d37e77aa88c335ce9b8 (patch) | |
tree | 766ebdd36a300789219202229fabf597bc83c364 | |
parent | 55306f62c769cba0a97465b04790b8b9fbdce907 (diff) | |
download | kernel_samsung_smdk4412-ab5cf14fb4432d2550896d37e77aa88c335ce9b8.zip kernel_samsung_smdk4412-ab5cf14fb4432d2550896d37e77aa88c335ce9b8.tar.gz kernel_samsung_smdk4412-ab5cf14fb4432d2550896d37e77aa88c335ce9b8.tar.bz2 |
BACKPORT: perf: Introduce perf_pmu_migrate_context()
Originally from Peter Zijlstra. The helper migrates perf events
from one cpu to another cpu.
Conflicts (perf: Fix race in removing an event):
kernel/events/core.c
Change-Id: I7885fe36c9e2803b10477d556163197085be3d19
Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1339741902-8449-5-git-send-email-zheng.z.yan@intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | include/linux/perf_event.h | 2 | ||||
-rw-r--r-- | kernel/events/core.c | 36 |
2 files changed, 38 insertions, 0 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index e4d3640..42dc246 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -979,6 +979,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, struct task_struct *task, perf_overflow_handler_t callback); +extern void perf_pmu_migrate_context(struct pmu *pmu, + int src_cpu, int dst_cpu); extern u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running); diff --git a/kernel/events/core.c b/kernel/events/core.c index b9ed867..9d57031 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1580,6 +1580,8 @@ perf_install_in_context(struct perf_event_context *ctx, lockdep_assert_held(&ctx->mutex); event->ctx = ctx; + if (event->cpu != -1) + event->cpu = cpu; if (!task) { /* @@ -6651,6 +6653,7 @@ SYSCALL_DEFINE5(perf_event_open, mutex_lock(&ctx->mutex); if (move_group) { + synchronize_rcu(); perf_install_in_context(ctx, group_leader, event->cpu); get_ctx(ctx); list_for_each_entry(sibling, &group_leader->sibling_list, @@ -6750,6 +6753,39 @@ err: } EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); +void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) +{ + struct perf_event_context *src_ctx; + struct perf_event_context *dst_ctx; + struct perf_event *event, *tmp; + LIST_HEAD(events); + + src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx; + dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx; + + mutex_lock(&src_ctx->mutex); + list_for_each_entry_safe(event, tmp, &src_ctx->event_list, + event_entry) { + perf_remove_from_context(event, true); + put_ctx(src_ctx); + list_add(&event->event_entry, &events); + } + mutex_unlock(&src_ctx->mutex); + + synchronize_rcu(); + + mutex_lock(&dst_ctx->mutex); + list_for_each_entry_safe(event, tmp, &events, event_entry) { + list_del(&event->event_entry); + if (event->state >= PERF_EVENT_STATE_OFF) + event->state = PERF_EVENT_STATE_INACTIVE; + perf_install_in_context(dst_ctx, event, dst_cpu); + get_ctx(dst_ctx); + } + mutex_unlock(&dst_ctx->mutex); +} +EXPORT_SYMBOL_GPL(perf_pmu_migrate_context); + static void sync_child_event(struct perf_event *child_event, struct task_struct *child) { |