diff options
author | Maria Dimakopoulou <maria.n.dimakopoulou@gmail.com> | 2014-11-17 14:06:57 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-02 11:33:11 -0400 |
commit | 6f6539cad926f55d5eb6e79d05bbe99f0d54d56d (patch) | |
tree | 25b7ddb8abc3d567ddd108c9cc601a22ececd3bb /arch/x86/kernel/cpu/perf_event_intel.c | |
parent | 79cba822443a168c8f7f5b853d9c7225a6d5415e (diff) |
perf/x86/intel: Add cross-HT counter exclusion infrastructure
This patch adds a new shared_regs style structure to the
per-cpu x86 state (cpuc). It is used to coordinate access
between counters which must be used with exclusion across
HyperThreads on Intel processors. This new struct is not
needed on each PMU, thus is is allocated on demand.
Signed-off-by: Maria Dimakopoulou <maria.n.dimakopoulou@gmail.com>
[peterz: spinlock_t -> raw_spinlock_t]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Stephane Eranian <eranian@google.com>
Cc: bp@alien8.de
Cc: jolsa@redhat.com
Cc: kan.liang@intel.com
Link: http://lkml.kernel.org/r/1416251225-17721-6-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_intel.c')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 2dd34b57d3ff..7f54000fd0f1 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -2224,16 +2224,52 @@ struct intel_shared_regs *allocate_shared_regs(int cpu) | |||
2224 | return regs; | 2224 | return regs; |
2225 | } | 2225 | } |
2226 | 2226 | ||
2227 | static struct intel_excl_cntrs *allocate_excl_cntrs(int cpu) | ||
2228 | { | ||
2229 | struct intel_excl_cntrs *c; | ||
2230 | int i; | ||
2231 | |||
2232 | c = kzalloc_node(sizeof(struct intel_excl_cntrs), | ||
2233 | GFP_KERNEL, cpu_to_node(cpu)); | ||
2234 | if (c) { | ||
2235 | raw_spin_lock_init(&c->lock); | ||
2236 | for (i = 0; i < X86_PMC_IDX_MAX; i++) { | ||
2237 | c->states[0].state[i] = INTEL_EXCL_UNUSED; | ||
2238 | c->states[0].init_state[i] = INTEL_EXCL_UNUSED; | ||
2239 | |||
2240 | c->states[1].state[i] = INTEL_EXCL_UNUSED; | ||
2241 | c->states[1].init_state[i] = INTEL_EXCL_UNUSED; | ||
2242 | } | ||
2243 | c->core_id = -1; | ||
2244 | } | ||
2245 | return c; | ||
2246 | } | ||
2247 | |||
2227 | static int intel_pmu_cpu_prepare(int cpu) | 2248 | static int intel_pmu_cpu_prepare(int cpu) |
2228 | { | 2249 | { |
2229 | struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); | 2250 | struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); |
2230 | 2251 | ||
2231 | if (!(x86_pmu.extra_regs || x86_pmu.lbr_sel_map)) | 2252 | if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) { |
2232 | return NOTIFY_OK; | 2253 | cpuc->shared_regs = allocate_shared_regs(cpu); |
2254 | if (!cpuc->shared_regs) | ||
2255 | return NOTIFY_BAD; | ||
2256 | } | ||
2233 | 2257 | ||
2234 | cpuc->shared_regs = allocate_shared_regs(cpu); | 2258 | if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) { |
2235 | if (!cpuc->shared_regs) | 2259 | size_t sz = X86_PMC_IDX_MAX * sizeof(struct event_constraint); |
2236 | return NOTIFY_BAD; | 2260 | |
2261 | cpuc->constraint_list = kzalloc(sz, GFP_KERNEL); | ||
2262 | if (!cpuc->constraint_list) | ||
2263 | return NOTIFY_BAD; | ||
2264 | |||
2265 | cpuc->excl_cntrs = allocate_excl_cntrs(cpu); | ||
2266 | if (!cpuc->excl_cntrs) { | ||
2267 | kfree(cpuc->constraint_list); | ||
2268 | kfree(cpuc->shared_regs); | ||
2269 | return NOTIFY_BAD; | ||
2270 | } | ||
2271 | cpuc->excl_thread_id = 0; | ||
2272 | } | ||
2237 | 2273 | ||
2238 | return NOTIFY_OK; | 2274 | return NOTIFY_OK; |
2239 | } | 2275 | } |
@@ -2274,12 +2310,29 @@ static void intel_pmu_cpu_starting(int cpu) | |||
2274 | 2310 | ||
2275 | if (x86_pmu.lbr_sel_map) | 2311 | if (x86_pmu.lbr_sel_map) |
2276 | cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR]; | 2312 | cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR]; |
2313 | |||
2314 | if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) { | ||
2315 | for_each_cpu(i, topology_thread_cpumask(cpu)) { | ||
2316 | struct intel_excl_cntrs *c; | ||
2317 | |||
2318 | c = per_cpu(cpu_hw_events, i).excl_cntrs; | ||
2319 | if (c && c->core_id == core_id) { | ||
2320 | cpuc->kfree_on_online[1] = cpuc->excl_cntrs; | ||
2321 | cpuc->excl_cntrs = c; | ||
2322 | cpuc->excl_thread_id = 1; | ||
2323 | break; | ||
2324 | } | ||
2325 | } | ||
2326 | cpuc->excl_cntrs->core_id = core_id; | ||
2327 | cpuc->excl_cntrs->refcnt++; | ||
2328 | } | ||
2277 | } | 2329 | } |
2278 | 2330 | ||
2279 | static void intel_pmu_cpu_dying(int cpu) | 2331 | static void intel_pmu_cpu_dying(int cpu) |
2280 | { | 2332 | { |
2281 | struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); | 2333 | struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); |
2282 | struct intel_shared_regs *pc; | 2334 | struct intel_shared_regs *pc; |
2335 | struct intel_excl_cntrs *c; | ||
2283 | 2336 | ||
2284 | pc = cpuc->shared_regs; | 2337 | pc = cpuc->shared_regs; |
2285 | if (pc) { | 2338 | if (pc) { |
@@ -2287,6 +2340,14 @@ static void intel_pmu_cpu_dying(int cpu) | |||
2287 | kfree(pc); | 2340 | kfree(pc); |
2288 | cpuc->shared_regs = NULL; | 2341 | cpuc->shared_regs = NULL; |
2289 | } | 2342 | } |
2343 | c = cpuc->excl_cntrs; | ||
2344 | if (c) { | ||
2345 | if (c->core_id == -1 || --c->refcnt == 0) | ||
2346 | kfree(c); | ||
2347 | cpuc->excl_cntrs = NULL; | ||
2348 | kfree(cpuc->constraint_list); | ||
2349 | cpuc->constraint_list = NULL; | ||
2350 | } | ||
2290 | 2351 | ||
2291 | fini_debug_store_on_cpu(cpu); | 2352 | fini_debug_store_on_cpu(cpu); |
2292 | } | 2353 | } |