aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2014-11-17 14:07:02 -0500
committerIngo Molnar <mingo@kernel.org>2015-04-02 11:33:14 -0400
commitc02cdbf60b51b8d98a49185535f5d527a2965142 (patch)
tree05af6d083f8c1d9894fadd9e1af1e08a71660c96
parenta90738c2cb0dceb882e0d7f7f9141e0062809b4d (diff)
perf/x86/intel: Limit to half counters when the HT workaround is enabled, to avoid exclusive mode starvation
This patch limits the number of counters available to each CPU when the HT bug workaround is enabled. This is necessary to avoid situation of counter starvation. Such can arise from configuration where one HT thread, HT0, is using all 4 counters with corrupting events which require exclusion the the sibling HT, HT1. In such case, HT1 would not be able to schedule any event until HT0 is done. To mitigate this problem, this patch artificially limits the number of counters to 2. That way, we can gurantee that at least 2 counters are not in exclusive mode and therefore allow the sibling thread to schedule events of the same type (system vs. per-thread). The 2 counters are not determined in advance. We simply set the limit to two events per HT. This helps mitigate starvation in case of events with specific counter constraints such a PREC_DIST. Note that this does not elimintate the starvation is all cases. But it is better than not having it. (Solution suggested by Peter Zjilstra.) Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: bp@alien8.de Cc: jolsa@redhat.com Cc: kan.liang@intel.com Cc: maria.n.dimakopoulou@gmail.com Link: http://lkml.kernel.org/r/1416251225-17721-11-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/cpu/perf_event.h2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c22
2 files changed, 22 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 2ba71ecc244f..176749cca98f 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -134,6 +134,8 @@ enum intel_excl_state_type {
134struct intel_excl_states { 134struct intel_excl_states {
135 enum intel_excl_state_type init_state[X86_PMC_IDX_MAX]; 135 enum intel_excl_state_type init_state[X86_PMC_IDX_MAX];
136 enum intel_excl_state_type state[X86_PMC_IDX_MAX]; 136 enum intel_excl_state_type state[X86_PMC_IDX_MAX];
137 int num_alloc_cntrs;/* #counters allocated */
138 int max_alloc_cntrs;/* max #counters allowed */
137 bool sched_started; /* true if scheduling has started */ 139 bool sched_started; /* true if scheduling has started */
138}; 140};
139 141
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 4773ae0b52d0..4187d3f4ed12 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1897,7 +1897,7 @@ intel_start_scheduling(struct cpu_hw_events *cpuc)
1897 xl = &excl_cntrs->states[tid]; 1897 xl = &excl_cntrs->states[tid];
1898 1898
1899 xl->sched_started = true; 1899 xl->sched_started = true;
1900 1900 xl->num_alloc_cntrs = 0;
1901 /* 1901 /*
1902 * lock shared state until we are done scheduling 1902 * lock shared state until we are done scheduling
1903 * in stop_event_scheduling() 1903 * in stop_event_scheduling()
@@ -1963,7 +1963,6 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
1963 */ 1963 */
1964 if (cpuc->is_fake) 1964 if (cpuc->is_fake)
1965 return c; 1965 return c;
1966
1967 /* 1966 /*
1968 * event requires exclusive counter access 1967 * event requires exclusive counter access
1969 * across HT threads 1968 * across HT threads
@@ -1977,6 +1976,18 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
1977 xl = &excl_cntrs->states[tid]; 1976 xl = &excl_cntrs->states[tid];
1978 xlo = &excl_cntrs->states[o_tid]; 1977 xlo = &excl_cntrs->states[o_tid];
1979 1978
1979 /*
1980 * do not allow scheduling of more than max_alloc_cntrs
1981 * which is set to half the available generic counters.
1982 * this helps avoid counter starvation of sibling thread
1983 * by ensuring at most half the counters cannot be in
1984 * exclusive mode. There is not designated counters for the
1985 * limits. Any N/2 counters can be used. This helps with
1986 * events with specifix counter constraints
1987 */
1988 if (xl->num_alloc_cntrs++ == xl->max_alloc_cntrs)
1989 return &emptyconstraint;
1990
1980 cx = c; 1991 cx = c;
1981 1992
1982 /* 1993 /*
@@ -2624,6 +2635,8 @@ static void intel_pmu_cpu_starting(int cpu)
2624 cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR]; 2635 cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR];
2625 2636
2626 if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) { 2637 if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
2638 int h = x86_pmu.num_counters >> 1;
2639
2627 for_each_cpu(i, topology_thread_cpumask(cpu)) { 2640 for_each_cpu(i, topology_thread_cpumask(cpu)) {
2628 struct intel_excl_cntrs *c; 2641 struct intel_excl_cntrs *c;
2629 2642
@@ -2637,6 +2650,11 @@ static void intel_pmu_cpu_starting(int cpu)
2637 } 2650 }
2638 cpuc->excl_cntrs->core_id = core_id; 2651 cpuc->excl_cntrs->core_id = core_id;
2639 cpuc->excl_cntrs->refcnt++; 2652 cpuc->excl_cntrs->refcnt++;
2653 /*
2654 * set hard limit to half the number of generic counters
2655 */
2656 cpuc->excl_cntrs->states[0].max_alloc_cntrs = h;
2657 cpuc->excl_cntrs->states[1].max_alloc_cntrs = h;
2640 } 2658 }
2641} 2659}
2642 2660