diff options
| author | Raghavendra Rao Ananta <rananta@codeaurora.org> | 2018-10-19 10:06:28 -0700 |
|---|---|---|
| committer | Mukesh Ojha <mojha@codeaurora.org> | 2018-12-12 18:58:09 +0530 |
| commit | a486143d54295787909673dbaee6a6b6042a3377 (patch) | |
| tree | 99377233cc901f7fa0e55101d4ff11ae0bdfc5f7 | |
| parent | 982f5648ef062fbb28ff47b0e3fdaef1138da621 (diff) | |
perf: Cancel the mux hrtimer during CPU hotplug to avoid migration
The current design of hrtimers migrates the pinned timers to a
different CPU upon its hotplug. However, perf-core needs to
maintain the mux-hrtimers on a per CPU basis. That is, each
hrtimer carries the context for that particular CPU and would
lose this context if it gets migrated to a different CPU. As a
result, cancel the hrtimer for the CPU that's about to go down
and restart it (if required) when the perf-events are being created.
Change-Id: I7a1d0456208855e3a99a7d49e59c6dae811d146e
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
[mojha@codeaurora.org: Resolved merge conflict and added missing
`cpuctx` variable to avoid build failure]
Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
| -rw-r--r-- | include/linux/perf_event.h | 2 | ||||
| -rw-r--r-- | kernel/events/core.c | 15 |
2 files changed, 15 insertions, 2 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f501b8c0de4e..efce166a9f17 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -231,7 +231,7 @@ struct pmu { int capabilities; int * __percpu pmu_disable_count; - struct perf_cpu_context * __percpu pmu_cpu_context; + struct perf_cpu_context __percpu *pmu_cpu_context; atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */ int task_ctx_nr; int hrtimer_interval_ms; diff --git a/kernel/events/core.c b/kernel/events/core.c index 77bbbc18ce1f..66c1084752f9 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9656,13 +9656,26 @@ static void __perf_event_stop_swclock(void *__info) static void perf_event_exit_cpu_context(int cpu) { + struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; + unsigned long flags; struct pmu *pmu; int idx; idx = srcu_read_lock(&pmus_srcu); list_for_each_entry_rcu(pmu, &pmus, entry) { - ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + ctx = &cpuctx->ctx; + + /* Cancel the mux hrtimer to avoid CPU migration */ + if (pmu->task_ctx_nr != perf_sw_context) { + raw_spin_lock_irqsave(&cpuctx->hrtimer_lock, flags); + hrtimer_cancel(&cpuctx->hrtimer); + cpuctx->hrtimer_active = 0; + raw_spin_unlock_irqrestore(&cpuctx->hrtimer_lock, + flags); + } + mutex_lock(&ctx->mutex); /* * If keeping events across hotplugging is supported, do not |
