aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event_intel.c
diff options
context:
space:
mode:
authorMaria Dimakopoulou <maria.n.dimakopoulou@gmail.com>2014-11-17 14:06:57 -0500
committerIngo Molnar <mingo@kernel.org>2015-04-02 11:33:11 -0400
commit6f6539cad926f55d5eb6e79d05bbe99f0d54d56d (patch)
tree25b7ddb8abc3d567ddd108c9cc601a22ececd3bb /arch/x86/kernel/cpu/perf_event_intel.c
parent79cba822443a168c8f7f5b853d9c7225a6d5415e (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.c71
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
2227static 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
2227static int intel_pmu_cpu_prepare(int cpu) 2248static 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
2279static void intel_pmu_cpu_dying(int cpu) 2331static 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}