perf/x86: implement HT counter corruption workaround
Subsystems (3)
v3 cover perf/x86: implement HT counter corruption workaround
From: Maria Dimakopoulou <[email protected]>
This patch series addresses a serious known erratum in the PMU of Intel SandyBridge, IvyBrige, Haswell processors with hyper-threading enabled.
The erratum is documented in the Intel specification update documents for each processor under the errata listed below:
- SandyBridge: BJ122
- IvyBridge: BV98
- Haswell: HSD29
The bug causes silent counter corruption across hyperthreads only when measuring certain memory events (0xd0, 0xd1, 0xd2, 0xd3). Counters measuring those events may leak counts to the sibling counter. For instance, counter 0, thread 0 measuring event 0x81d0, may leak to counter 0, thread 1, regardless of the event measured there. The size of the leak is not predictible. It all depends on the workload and the state of each sibling hyper-thread. The corrupting events do undercount as a consequence of the leak. The leak is compensated automatically only when the sibling counter measures the exact same corrupting event AND the workload is on the two threads is the same. Given, there is no way to guarantee this, a workaround is necessary. Furthermore, there is a serious problem if the leaked counts are added to a low-occurrence event. In that case the corruption on the low occurrence event can be very large, e.g., orders of magnitude.
There is no HW or FW workaround for this problem.
The bug is very easy to reproduce on a loaded system. Here is an example on a Haswell client, where CPU0 and CPU4 are siblings. We load the CPUs with a simple triad app streaming large floating-point vector. We use 0x81d0 corrupting event (MEM_UOPS_RETIRED:ALL_LOADS) and 0x20cc (ROB_MISC_EVENTS:LBR_INSERTS). Given we are not using the LBR, the 0x20cc event should be zero.
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
139 277 291 r20cc
10,000969126 seconds time elapsedIn this example, 0x81d0 and r20cc are using sibling counters on CPU0 and CPU4. 0x81d0 leaks into 0x20cc and corrupts it from 0 to 139 millions occurrences.
This patch provides a software workaround to this problem by modifying the way events are scheduled onto counters by the kernel. The patch forces cross-thread mutual exclusion between sibling counters in case a corrupting event is measured by one of the hyper-threads. If thread 0, counter 0 is measuring event 0x81d0, then nothing can be measured on counter 0, thread 1. If no corrupting event is measured on any hyper-thread, event scheduling proceeds as before.
The same example run with the workaround enabled, yields the correct answer:
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
0 r20cc
10,000969126 seconds time elapsedThe patch does provide correctness for all non-corrupting events. It does not "repatriate" the leaked counts back to the leaking counter. This is planned for a second patch series. This patch series however makes this repatriation easier by guaranteeing that the sibling counter is not measuring any useful event.
The patch introduces dynamic constraints for events. That means that events which did not have constraints, i.e., could be measured on any counters, may now be constrained to a subset of the counters depending on what is going on the sibling thread. The algorithm is similar to a cache coherency protocol. We call it XSU in reference to Exclusive, Shared, Unused, the 3 possible states of a PMU counter.
As a consequence of the workaround, users may see an increased amount of event multiplexing, even in situtations where there are fewer events than counters measured on a CPU.
Patch has been tested on all three impacted processors. Note that when HT is off, there is no corruption. However, the workaround is still enabled, yet not costing too much. Adding a dynamic detection of HT on turned out to be complex are requiring too much to code to be justified. This patch series also covers events used with PEBS.
Special thanks to Maria for working out a solution to this complex problem.
In V2, we rebased to 3.17, we also addressed all the feedback received for LKML from V1. In particular, we now automatically detect if HT is disabled, and if so we disable the workaround altogether. This is done as a 2-step initcall as suggested by PeterZ. We also fixed the spinlock irq masking. We pre-allocate the dynamic constraints in the per-cpu cpuc struct. We have isolated the sysfs sysctl to make it optional.
In V3, we rebased the code to 3.18-rc5. We cleaned up the auto-detection of Hyperthreading. But more importantly, we implemented a solution suggested by PeterZ to avoid the counter starvation introduced by the workaround. Because of exclusive access across HT threads, one HT can starve the other by measuring 4 corrupting events. Though this would be rare, we wanted to mitigate this problem. The idea of Peter was to artificially limit the number of counters available to each HT to half the actual number, i.e., 2. That way, we guarantee that at least 2 counters are not in exclusive mode. This mitigates the starvation situations though some corner cases still exist. But we think this is better than not having it.
Maria Dimakopoulou (6):
perf/x86: add 3 new scheduling callbacks
perf/x86: add cross-HT counter exclusion infrastructure perf/x86: implement cross-HT corruption bug workaround perf/x86: enforce HT bug workaround for SNB/IVB/HSW perf/x86: enforce HT bug workaround with PEBS for SNB/IVB/HSW perf/x86: add syfs entry to disable HT bug workaround
Stephane Eranian (7):
perf,x86: rename er_flags to flags
perf/x86: vectorize cpuc->kfree_on_online
perf/x86: add index param to get_event_constraint() callback perf/x86: fix intel_get_event_constraints() for dynamic constraints perf/x86: limit to half counters to avoid exclusive mode starvation
watchdog: add watchdog enable/disable all functions perf/x86: make HT bug workaround conditioned on HT enabled
arch/x86/kernel/cpu/perf_event.c | 98 +++++- arch/x86/kernel/cpu/perf_event.h | 95 +++++- arch/x86/kernel/cpu/perf_event_amd.c | 9 +- arch/x86/kernel/cpu/perf_event_intel.c | 544 ++++++++++++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel_ds.c | 28 +- include/linux/watchdog.h | 8 + kernel/watchdog.c | 28 ++ 7 files changed, 744 insertions(+), 66 deletions(-)
Signature · 1 line
1.9.1
PATCH v3 1/13 perf,x86: rename er_flags to flags
Because it will be used for more than just
tracking the presence of extra registers.
--- arch/x86/kernel/cpu/perf_event.h | 9 ++++++--- arch/x86/kernel/cpu/perf_event_intel.c | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/perf_event.h +6 -3
@@ -505,7 +505,7 @@ struct x86_pmu {* Extra registers for events */ struct extra_reg *extra_regs; -unsigned int er_flags; +unsigned int flags;/* * Intel host/guest support (KVM)
@@ -522,8 +522,11 @@ do { \ x86_pmu.quirks = &__quirk; \ }while (0 ) -#define ERF_NO_HT_SHARING 1 -#define ERF_HAS_RSP_1 2 +/* +* x86_pmu flags + */ +#define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ +#define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
arch/x86/kernel/cpu/perf_event_intel.c +10 -10
@@ -1464,7 +1464,7 @@ intel_bts_constraints(struct perf_event *event)static int intel_alt_er (int idx) { -if (!(x86_pmu.er_flags &ERF_HAS_RSP_1 )) +if (!(x86_pmu.flags &PMU_FL_HAS_RSP_1 ))return idx;if (idx ==EXTRA_REG_RSP_0 )
@@ -2010,7 +2010,7 @@ static void intel_pmu_cpu_starting(int cpu)if (!cpuc->shared_regs)return ; -if (!(x86_pmu.er_flags &ERF_NO_HT_SHARING )) { +if (!(x86_pmu.flags &PMU_FL_NO_HT_SHARING )) {for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_shared_regs *pc;
@@ -2442,7 +2442,7 @@ __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_slm_event_constraints; x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints; x86_pmu.extra_regs = intel_slm_extra_regs; - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ;pr_cont ("Silvermont events, " );break ;
@@ -2460,7 +2460,7 @@ __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints; x86_pmu.extra_regs = intel_westmere_extra_regs; - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; x86_pmu.cpu_events = nhm_events_attrs;
@@ -2492,8 +2492,8 @@ __init int intel_pmu_init(void)else x86_pmu.extra_regs = intel_snb_extra_regs;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.cpu_events = snb_events_attrs;
@@ -2527,8 +2527,8 @@ __init int intel_pmu_init(void)else x86_pmu.extra_regs = intel_snb_extra_regs;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.cpu_events = snb_events_attrs;
@@ -2555,8 +2555,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snbep_extra_regs; x86_pmu.pebs_aliases = intel_pebs_aliases_snb;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints;
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86: Rename x86_pmu::er_flags to 'flags'
perf/x86: Rename x86_pmu::er_flags to 'flags'
Commit-ID: 9a5e3fb52ae5458c8bf1a67129b96c39b541a582 Gitweb: http://git.kernel.org/tip/9a5e3fb52ae5458c8bf1a67129b96c39b541a582 Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:53 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:08 +0200
perf/x86: Rename x86_pmu::er_flags to 'flags'
Because it will be used for more than just tracking the presence of extra registers.
--- arch/x86/kernel/cpu/perf_event.h | 9 ++++++--- arch/x86/kernel/cpu/perf_event_intel.c | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 15 deletions(-)
arch/x86/kernel/cpu/perf_event.h +6 -3
@@ -521,7 +521,7 @@ struct x86_pmu {* Extra registers for events */ struct extra_reg *extra_regs; -unsigned int er_flags; +unsigned int flags;/* * Intel host/guest support (KVM)
@@ -545,8 +545,11 @@ do { \ x86_pmu.quirks = &__quirk; \ }while (0 ) -#define ERF_NO_HT_SHARING 1 -#define ERF_HAS_RSP_1 2 +/* +* x86_pmu flags + */ +#define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ +#define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
arch/x86/kernel/cpu/perf_event_intel.c +12 -12
@@ -1667,7 +1667,7 @@ intel_bts_constraints(struct perf_event *event)static int intel_alt_er (int idx) { -if (!(x86_pmu.er_flags &ERF_HAS_RSP_1 )) +if (!(x86_pmu.flags &PMU_FL_HAS_RSP_1 ))return idx;if (idx ==EXTRA_REG_RSP_0 )
@@ -2250,7 +2250,7 @@ static void intel_pmu_cpu_starting(int cpu)if (!cpuc->shared_regs)return ; -if (!(x86_pmu.er_flags &ERF_NO_HT_SHARING )) { +if (!(x86_pmu.flags &PMU_FL_NO_HT_SHARING )) {for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_shared_regs *pc;
@@ -2671,7 +2671,7 @@ __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_slm_event_constraints; x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints; x86_pmu.extra_regs = intel_slm_extra_regs; - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ;pr_cont ("Silvermont events, " );break ;
@@ -2689,7 +2689,7 @@ __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints; x86_pmu.extra_regs = intel_westmere_extra_regs; - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; x86_pmu.cpu_events = nhm_events_attrs;
@@ -2721,8 +2721,8 @@ __init int intel_pmu_init(void)else x86_pmu.extra_regs = intel_snb_extra_regs;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.cpu_events = snb_events_attrs;
@@ -2756,8 +2756,8 @@ __init int intel_pmu_init(void)else x86_pmu.extra_regs = intel_snb_extra_regs;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.cpu_events = snb_events_attrs;
@@ -2784,8 +2784,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snbep_extra_regs; x86_pmu.pebs_aliases = intel_pebs_aliases_snb;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints;
@@ -2817,8 +2817,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snbep_extra_regs; x86_pmu.pebs_aliases = intel_pebs_aliases_snb;/* all extra regs are per-cpu when HT is on */ - x86_pmu.er_flags |=ERF_HAS_RSP_1 ; - x86_pmu.er_flags |=ERF_NO_HT_SHARING ; + x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; + x86_pmu.flags |=PMU_FL_NO_HT_SHARING ; x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints;
PATCH v3 2/13 perf/x86: vectorize cpuc->kfree_on_online
In reply to Stephane EranianMake the cpuc->kfree_on_online a vector to accommodate more than one entry and add the second entry to be used by a later patch.
--- arch/x86/kernel/cpu/perf_event.c | 10 +++++++--- arch/x86/kernel/cpu/perf_event.h | 8 +++++++- arch/x86/kernel/cpu/perf_event_amd.c | 3 ++- arch/x86/kernel/cpu/perf_event_intel.c | 4 +++- 4 files changed, 19 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +7 -3
@@ -1317,11 +1317,12 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) {unsigned int cpu = (long )hcpu;struct cpu_hw_events *cpuc = &per_cpu (cpu_hw_events, cpu); -int ret =NOTIFY_OK ; +int i, ret =NOTIFY_OK ;switch (action & ~CPU_TASKS_FROZEN ) {case CPU_UP_PREPARE : - cpuc->kfree_on_online =NULL ; +for (i =0 ; i <X86_PERF_KFREE_MAX ; i++) + cpuc->kfree_on_online[i] =NULL ;if (x86_pmu.cpu_prepare) ret = x86_pmu.cpu_prepare (cpu);break ;
@@ -1334,7 +1335,10 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)break ;case CPU_ONLINE : -kfree (cpuc->kfree_on_online); +for (i =0 ; i <X86_PERF_KFREE_MAX ; i++) { +kfree (cpuc->kfree_on_online[i]); + cpuc->kfree_on_online[i] =NULL ; + }break ;case CPU_DYING :
arch/x86/kernel/cpu/perf_event.h +7 -1
@@ -123,6 +123,12 @@ struct intel_shared_regs {#define MAX_LBR_ENTRIES 16 +enum { +X86_PERF_KFREE_SHARED =0 , +X86_PERF_KFREE_EXCL =1 , +X86_PERF_KFREE_MAX +}; +struct cpu_hw_events {/* * Generic x86 PMC bits
@@ -185,7 +191,7 @@ struct cpu_hw_events {/* Inverted mask of bits to clear in the perf_ctr ctrl registers */ u64 perf_ctr_virt_mask; -void *kfree_on_online; +void *kfree_on_online[X86_PERF_KFREE_MAX ]; };#define __EVENT_CONSTRAINT (c, n, m, w, o, f) {\
arch/x86/kernel/cpu/perf_event_amd.c +2 -1
@@ -382,6 +382,7 @@ static int amd_pmu_cpu_prepare(int cpu)static void amd_pmu_cpu_starting (int cpu) {struct cpu_hw_events *cpuc = &per_cpu (cpu_hw_events, cpu); +void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED ];struct amd_nb *nb;int i, nb_id;
@@ -399,7 +400,7 @@ static void amd_pmu_cpu_starting(int cpu)continue ;if (nb->nb_id == nb_id) { - cpuc->kfree_on_online = cpuc->amd_nb; + *onln = cpuc->amd_nb; cpuc->amd_nb = nb;break ; }
arch/x86/kernel/cpu/perf_event_intel.c +3 -1
@@ -2011,12 +2011,14 @@ static void intel_pmu_cpu_starting(int cpu)return ;if (!(x86_pmu.flags &PMU_FL_NO_HT_SHARING )) { +void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED ]; +for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_shared_regs *pc; pc =per_cpu (cpu_hw_events, i).shared_regs;if (pc && pc->core_id == core_id) { - cpuc->kfree_on_online = cpuc->shared_regs; + *onln = cpuc->shared_regs; cpuc->shared_regs = pc;break ; }
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86: Vectorize cpuc->kfree_on_online
perf/x86: Vectorize cpuc->kfree_on_online
Commit-ID: 90413464313e00fe4975f4a0ebf25fe31d01f793 Gitweb: http://git.kernel.org/tip/90413464313e00fe4975f4a0ebf25fe31d01f793 Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:54 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:08 +0200
perf/x86: Vectorize cpuc->kfree_on_online
Make the cpuc->kfree_on_online a vector to accommodate more than one entry and add the second entry to be used by a later patch.
--- arch/x86/kernel/cpu/perf_event.c | 10 +++++++--- arch/x86/kernel/cpu/perf_event.h | 8 +++++++- arch/x86/kernel/cpu/perf_event_amd.c | 3 ++- arch/x86/kernel/cpu/perf_event_intel.c | 4 +++- 4 files changed, 19 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +7 -3
@@ -1373,11 +1373,12 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) {unsigned int cpu = (long )hcpu;struct cpu_hw_events *cpuc = &per_cpu (cpu_hw_events, cpu); -int ret =NOTIFY_OK ; +int i, ret =NOTIFY_OK ;switch (action & ~CPU_TASKS_FROZEN ) {case CPU_UP_PREPARE : - cpuc->kfree_on_online =NULL ; +for (i =0 ; i <X86_PERF_KFREE_MAX ; i++) + cpuc->kfree_on_online[i] =NULL ;if (x86_pmu.cpu_prepare) ret = x86_pmu.cpu_prepare (cpu);break ;
@@ -1388,7 +1389,10 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)break ;case CPU_ONLINE : -kfree (cpuc->kfree_on_online); +for (i =0 ; i <X86_PERF_KFREE_MAX ; i++) { +kfree (cpuc->kfree_on_online[i]); + cpuc->kfree_on_online[i] =NULL ; + }break ;case CPU_DYING :
arch/x86/kernel/cpu/perf_event.h +7 -1
@@ -125,6 +125,12 @@ struct intel_shared_regs {#define MAX_LBR_ENTRIES 16 +enum { +X86_PERF_KFREE_SHARED =0 , +X86_PERF_KFREE_EXCL =1 , +X86_PERF_KFREE_MAX +}; +struct cpu_hw_events {/* * Generic x86 PMC bits
@@ -187,7 +193,7 @@ struct cpu_hw_events {/* Inverted mask of bits to clear in the perf_ctr ctrl registers */ u64 perf_ctr_virt_mask; -void *kfree_on_online; +void *kfree_on_online[X86_PERF_KFREE_MAX ]; };#define __EVENT_CONSTRAINT (c, n, m, w, o, f) {\
arch/x86/kernel/cpu/perf_event_amd.c +2 -1
@@ -382,6 +382,7 @@ static int amd_pmu_cpu_prepare(int cpu)static void amd_pmu_cpu_starting (int cpu) {struct cpu_hw_events *cpuc = &per_cpu (cpu_hw_events, cpu); +void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED ];struct amd_nb *nb;int i, nb_id;
@@ -399,7 +400,7 @@ static void amd_pmu_cpu_starting(int cpu)continue ;if (nb->nb_id == nb_id) { - cpuc->kfree_on_online = cpuc->amd_nb; + *onln = cpuc->amd_nb; cpuc->amd_nb = nb;break ; }
arch/x86/kernel/cpu/perf_event_intel.c +3 -1
@@ -2251,12 +2251,14 @@ static void intel_pmu_cpu_starting(int cpu)return ;if (!(x86_pmu.flags &PMU_FL_NO_HT_SHARING )) { +void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED ]; +for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_shared_regs *pc; pc =per_cpu (cpu_hw_events, i).shared_regs;if (pc && pc->core_id == core_id) { - cpuc->kfree_on_online = cpuc->shared_regs; + *onln = cpuc->shared_regs; cpuc->shared_regs = pc;break ; }
PATCH v3 3/13 perf/x86: add 3 new scheduling callbacks
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
This patch adds 3 new PMU model specific callbacks during the event scheduling done by x86_schedule_events().
- start_scheduling: invoked when entering the schedule routine.
- stop_scheduling: invoked at the end of the schedule routine
- commit_scheduling: invoked for each committed event
To be used optionally by model-specific code.
--- arch/x86/kernel/cpu/perf_event.c | 9 +++++++++ arch/x86/kernel/cpu/perf_event.h | 9 +++++++++ 2 files changed, 18 insertions(+)
arch/x86/kernel/cpu/perf_event.c +9 -0
@@ -729,6 +729,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)bitmap_zero (used_mask,X86_PMC_IDX_MAX ); +if (x86_pmu.start_scheduling) + x86_pmu.start_scheduling (cpuc); +for (i =0 , wmin =X86_PMC_IDX_MAX , wmax =0 ; i < n; i++) { hwc = &cpuc->event_list[i]->hw; c = x86_pmu.get_event_constraints (cpuc, cpuc->event_list[i]);
@@ -775,6 +778,8 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)for (i =0 ; i < n; i++) { e = cpuc->event_list[i]; e->hw.flags |=PERF_X86_EVENT_COMMITTED ; +if (x86_pmu.commit_scheduling) + x86_pmu.commit_scheduling (cpuc, e, assign[i]); } }/*
@@ -795,6 +800,10 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) x86_pmu.put_event_constraints (cpuc, e); } } + +if (x86_pmu.stop_scheduling) + x86_pmu.stop_scheduling (cpuc); +return num ? -EINVAL :0 ; }
arch/x86/kernel/cpu/perf_event.h +9 -0
@@ -451,6 +451,15 @@ struct x86_pmu {void (*put_event_constraints)(struct cpu_hw_events *cpuc,struct perf_event *event); + +void (*commit_scheduling)(struct cpu_hw_events *cpuc, +struct perf_event *event, +int cntr); + +void (*start_scheduling)(struct cpu_hw_events *cpuc); + +void (*stop_scheduling)(struct cpu_hw_events *cpuc); +struct event_constraint *event_constraints;struct x86_pmu_quirk *quirks;int perfctr_second_write;
Signature · 1 line
1.9.1
tip-bot for Maria Dimakopoulou
merge bot[tip:perf/core] perf/x86: Add 3 new scheduling callbacks
perf/x86: Add 3 new scheduling callbacks
Commit-ID: c5362c0c376486afcf3c91d3c2691d348ac1e2fd Gitweb: http://git.kernel.org/tip/c5362c0c376486afcf3c91d3c2691d348ac1e2fd Author: Maria Dimakopoulou <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:55 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:09 +0200
perf/x86: Add 3 new scheduling callbacks
This patch adds 3 new PMU model specific callbacks during the event scheduling done by x86_schedule_events().
->start_scheduling(): invoked when entering the schedule routine.
->stop_scheduling(): invoked at the end of the schedule routine
->commit_scheduling(): invoked for each committed event
To be used optionally by model-specific code.
--- arch/x86/kernel/cpu/perf_event.c | 9 +++++++++ arch/x86/kernel/cpu/perf_event.h | 9 +++++++++ 2 files changed, 18 insertions(+)
arch/x86/kernel/cpu/perf_event.c +9 -0
@@ -784,6 +784,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)bitmap_zero (used_mask,X86_PMC_IDX_MAX ); +if (x86_pmu.start_scheduling) + x86_pmu.start_scheduling (cpuc); +for (i =0 , wmin =X86_PMC_IDX_MAX , wmax =0 ; i < n; i++) { hwc = &cpuc->event_list[i]->hw; c = x86_pmu.get_event_constraints (cpuc, cpuc->event_list[i]);
@@ -830,6 +833,8 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)for (i =0 ; i < n; i++) { e = cpuc->event_list[i]; e->hw.flags |=PERF_X86_EVENT_COMMITTED ; +if (x86_pmu.commit_scheduling) + x86_pmu.commit_scheduling (cpuc, e, assign[i]); } }/*
@@ -850,6 +855,10 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) x86_pmu.put_event_constraints (cpuc, e); } } + +if (x86_pmu.stop_scheduling) + x86_pmu.stop_scheduling (cpuc); +return num ? -EINVAL :0 ; }
arch/x86/kernel/cpu/perf_event.h +9 -0
@@ -460,6 +460,15 @@ struct x86_pmu {void (*put_event_constraints)(struct cpu_hw_events *cpuc,struct perf_event *event); + +void (*commit_scheduling)(struct cpu_hw_events *cpuc, +struct perf_event *event, +int cntr); + +void (*start_scheduling)(struct cpu_hw_events *cpuc); + +void (*stop_scheduling)(struct cpu_hw_events *cpuc); +struct event_constraint *event_constraints;struct x86_pmu_quirk *quirks;int perfctr_second_write;
PATCH v3 4/13 perf/x86: add index param to get_event_constraint() callback
In reply to Stephane EranianThis patch adds an index parameter to the get_event_constraint() x86_pmu callback. It is expected to represent the index of the event in the cpuc->event_list[] array. When the callback is used for fake_cpuc (evnet validation), then the index must be -1. The motivation for passing the index is to use it to index into another cpuc array.
--- arch/x86/kernel/cpu/perf_event.c | 4 ++-- arch/x86/kernel/cpu/perf_event.h | 4 +++- arch/x86/kernel/cpu/perf_event_amd.c | 6 ++++-- arch/x86/kernel/cpu/perf_event_intel.c | 15 ++++++++++----- 4 files changed, 19 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/perf_event.c +2 -2
@@ -734,7 +734,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)for (i =0 , wmin =X86_PMC_IDX_MAX , wmax =0 ; i < n; i++) { hwc = &cpuc->event_list[i]->hw; - c = x86_pmu.get_event_constraints (cpuc, cpuc->event_list[i]); + c = x86_pmu.get_event_constraints (cpuc, i, cpuc->event_list[i]); hwc->constraint = c; wmin =min (wmin, c->weight);
@@ -1723,7 +1723,7 @@ static int validate_event(struct perf_event *event)if (IS_ERR (fake_cpuc))return PTR_ERR (fake_cpuc); - c = x86_pmu.get_event_constraints (fake_cpuc, event); + c = x86_pmu.get_event_constraints (fake_cpuc,-1 , event);if (!c || !c->weight) ret = -EINVAL ;
arch/x86/kernel/cpu/perf_event.h +3 -1
@@ -447,6 +447,7 @@ struct x86_pmu {u64 max_period;struct event_constraint * (*get_event_constraints)(struct cpu_hw_events *cpuc, +int idx,struct perf_event *event); void (*put_event_constraints)(struct cpu_hw_events *cpuc,
@@ -693,7 +694,8 @@ static inline int amd_pmu_init(void)int intel_pmu_save_and_restart (struct perf_event *event);struct event_constraint * -x86_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event); +x86_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event);struct intel_shared_regs *allocate_shared_regs (int cpu);
arch/x86/kernel/cpu/perf_event_amd.c +4 -2
@@ -430,7 +430,8 @@ static void amd_pmu_cpu_dead(int cpu) }static struct event_constraint * -amd_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +amd_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {/* * if not NB event or no NB, then no constraints
@@ -538,7 +539,8 @@ static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);static struct event_constraint amd_f15_PMC53 =EVENT_CONSTRAINT (0 ,0x38 ,0 );static struct event_constraint * -amd_get_event_constraints_f15h (struct cpu_hw_events *cpuc,struct perf_event *event) +amd_get_event_constraints_f15h (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;unsigned int event_code =amd_get_event_code (hwc);
arch/x86/kernel/cpu/perf_event_intel.c +10 -5
@@ -1624,7 +1624,8 @@ intel_shared_regs_constraints(struct cpu_hw_events *cpuc, }struct event_constraint * -x86_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +x86_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct event_constraint *c;
@@ -1641,7 +1642,8 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) }static struct event_constraint * -intel_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +intel_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct event_constraint *c;
@@ -1657,7 +1659,7 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *eventif (c)return c; -return x86_get_event_constraints (cpuc, event); +return x86_get_event_constraints (cpuc, idx, event); } static void
@@ -1891,9 +1893,12 @@ static struct event_constraint counter2_constraint =EVENT_CONSTRAINT (0 ,0x4 ,0 );static struct event_constraint * -hsw_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +hsw_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) { -struct event_constraint *c =intel_get_event_constraints (cpuc, event); +struct event_constraint *c; + + c =intel_get_event_constraints (cpuc, idx, event);/* Handle special quirk on in_tx_checkpointed only in counter 2 */ if (event->hw.config &HSW_IN_TX_CHECKPOINTED ) {
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86: Add 'index' param to get_event_constraint() callback
perf/x86: Add 'index' param to get_event_constraint() callback
Commit-ID: 79cba822443a168c8f7f5b853d9c7225a6d5415e Gitweb: http://git.kernel.org/tip/79cba822443a168c8f7f5b853d9c7225a6d5415e Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:56 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:10 +0200
perf/x86: Add 'index' param to get_event_constraint() callback
This patch adds an index parameter to the get_event_constraint() x86_pmu callback. It is expected to represent the index of the event in the cpuc->event_list[] array. When the callback is used for fake_cpuc (evnet validation), then the index must be -1. The motivation for passing the index is to use it to index into another cpuc array.
--- arch/x86/kernel/cpu/perf_event.c | 4 ++-- arch/x86/kernel/cpu/perf_event.h | 4 +++- arch/x86/kernel/cpu/perf_event_amd.c | 6 ++++-- arch/x86/kernel/cpu/perf_event_intel.c | 15 ++++++++++----- 4 files changed, 19 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/perf_event.c +2 -2
@@ -789,7 +789,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)for (i =0 , wmin =X86_PMC_IDX_MAX , wmax =0 ; i < n; i++) { hwc = &cpuc->event_list[i]->hw; - c = x86_pmu.get_event_constraints (cpuc, cpuc->event_list[i]); + c = x86_pmu.get_event_constraints (cpuc, i, cpuc->event_list[i]); hwc->constraint = c; wmin =min (wmin, c->weight);
@@ -1777,7 +1777,7 @@ static int validate_event(struct perf_event *event)if (IS_ERR (fake_cpuc))return PTR_ERR (fake_cpuc); - c = x86_pmu.get_event_constraints (fake_cpuc, event); + c = x86_pmu.get_event_constraints (fake_cpuc,-1 , event);if (!c || !c->weight) ret = -EINVAL ;
arch/x86/kernel/cpu/perf_event.h +3 -1
@@ -456,6 +456,7 @@ struct x86_pmu {u64 max_period;struct event_constraint * (*get_event_constraints)(struct cpu_hw_events *cpuc, +int idx,struct perf_event *event); void (*put_event_constraints)(struct cpu_hw_events *cpuc,
@@ -751,7 +752,8 @@ static inline bool intel_pmu_has_bts(struct perf_event *event)int intel_pmu_save_and_restart (struct perf_event *event);struct event_constraint * -x86_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event); +x86_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event);struct intel_shared_regs *allocate_shared_regs (int cpu);
arch/x86/kernel/cpu/perf_event_amd.c +4 -2
@@ -430,7 +430,8 @@ static void amd_pmu_cpu_dead(int cpu) }static struct event_constraint * -amd_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +amd_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {/* * if not NB event or no NB, then no constraints
@@ -538,7 +539,8 @@ static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);static struct event_constraint amd_f15_PMC53 =EVENT_CONSTRAINT (0 ,0x38 ,0 );static struct event_constraint * -amd_get_event_constraints_f15h (struct cpu_hw_events *cpuc,struct perf_event *event) +amd_get_event_constraints_f15h (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;unsigned int event_code =amd_get_event_code (hwc);
arch/x86/kernel/cpu/perf_event_intel.c +10 -5
@@ -1827,7 +1827,8 @@ intel_shared_regs_constraints(struct cpu_hw_events *cpuc, }struct event_constraint * -x86_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +x86_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct event_constraint *c;
@@ -1844,7 +1845,8 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) }static struct event_constraint * -intel_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +intel_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) {struct event_constraint *c;
@@ -1860,7 +1862,7 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *eventif (c)return c; -return x86_get_event_constraints (cpuc, event); +return x86_get_event_constraints (cpuc, idx, event); } static void
@@ -2105,9 +2107,12 @@ static struct event_constraint counter2_constraint =EVENT_CONSTRAINT (0 ,0x4 ,0 );static struct event_constraint * -hsw_get_event_constraints (struct cpu_hw_events *cpuc,struct perf_event *event) +hsw_get_event_constraints (struct cpu_hw_events *cpuc,int idx, +struct perf_event *event) { -struct event_constraint *c =intel_get_event_constraints (cpuc, event); +struct event_constraint *c; + + c =intel_get_event_constraints (cpuc, idx, event);/* Handle special quirk on in_tx_checkpointed only in counter 2 */ if (event->hw.config &HSW_IN_TX_CHECKPOINTED ) {
PATCH v3 5/13 perf/x86: add cross-HT counter exclusion infrastructure
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
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.
--- arch/x86/kernel/cpu/perf_event.h | 32 +++++++++++++++ arch/x86/kernel/cpu/perf_event_intel.c | 71 +++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event.h +32 -0
@@ -71,6 +71,7 @@ struct event_constraint {#define PERF_X86_EVENT_COMMITTED 0x8/* event passed commit_txn */ #define PERF_X86_EVENT_PEBS_LD_HSW 0x10/* haswell style datala, load */ #define PERF_X86_EVENT_PEBS_NA_HSW 0x20/* haswell style datala, unknown */ +#define PERF_X86_EVENT_EXCL 0x40/* HT exclusivity on counter */ struct amd_nb {int nb_id;/* NorthBridge id */
@@ -121,6 +122,26 @@ struct intel_shared_regs {unsigned core_id;/* per-core: core id */ }; +enum intel_excl_state_type { +INTEL_EXCL_UNUSED =0 ,/* counter is unused */ +INTEL_EXCL_SHARED =1 ,/* counter can be used by both threads */ +INTEL_EXCL_EXCLUSIVE =2 ,/* counter can be used by one thread only */ +}; + +struct intel_excl_states { +enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ]; +enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +}; + +struct intel_excl_cntrs { +spinlock_t lock; + +struct intel_excl_states states[2 ]; + +int refcnt;/* per-core: #HT threads */ +unsigned core_id;/* per-core: core id */ +}; +#define MAX_LBR_ENTRIES 16enum {
@@ -183,6 +204,12 @@ struct cpu_hw_events {* used on Intel NHM/WSM/SNB */ struct intel_shared_regs *shared_regs; +/* +* manage exclusive counter access between hyperthread +*/ +struct event_constraint *constraint_list;/* in enable order */ +struct intel_excl_cntrs *excl_cntrs; +int excl_thread_id;/* 0 or 1 */ /* * AMD specific bits
@@ -206,6 +233,10 @@ struct cpu_hw_events {#define EVENT_CONSTRAINT (c, n, m) \ __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0) +#define INTEL_EXCLEVT_CONSTRAINT (c, n) \ + __EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT, HWEIGHT(n),\ + 0, PERF_X86_EVENT_EXCL) +/* * The overlap flag marks event constraints with overlapping counter * masks. This is the case if the counter mask of such an event is not
@@ -543,6 +574,7 @@ do { \*/ #define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ #define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ +#define PMU_FL_EXCL_CNTRS 0x4/* has exclusive counter requirements */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
arch/x86/kernel/cpu/perf_event_intel.c +66 -5
100 lines not on this page · raw message
Signature · 1 line
1.9.1
tip-bot for Maria Dimakopoulou
merge bot[tip:perf/core] perf/x86/intel: Add cross-HT counter exclusion infrastructure
perf/x86/intel: Add cross-HT counter exclusion infrastructure
Commit-ID: 6f6539cad926f55d5eb6e79d05bbe99f0d54d56d Gitweb: http://git.kernel.org/tip/6f6539cad926f55d5eb6e79d05bbe99f0d54d56d Author: Maria Dimakopoulou <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:57 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:11 +0200
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.
--- arch/x86/kernel/cpu/perf_event.h | 32 +++++++++++++++ arch/x86/kernel/cpu/perf_event_intel.c | 71 +++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event.h +32 -0
@@ -71,6 +71,7 @@ struct event_constraint {#define PERF_X86_EVENT_COMMITTED 0x8/* event passed commit_txn */ #define PERF_X86_EVENT_PEBS_LD_HSW 0x10/* haswell style datala, load */ #define PERF_X86_EVENT_PEBS_NA_HSW 0x20/* haswell style datala, unknown */ +#define PERF_X86_EVENT_EXCL 0x40/* HT exclusivity on counter */ #define PERF_X86_EVENT_RDPMC_ALLOWED 0x40/* grant rdpmc permission */
@@ -123,6 +124,26 @@ struct intel_shared_regs {unsigned core_id;/* per-core: core id */ }; +enum intel_excl_state_type { +INTEL_EXCL_UNUSED =0 ,/* counter is unused */ +INTEL_EXCL_SHARED =1 ,/* counter can be used by both threads */ +INTEL_EXCL_EXCLUSIVE =2 ,/* counter can be used by one thread only */ +}; + +struct intel_excl_states { +enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ]; +enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +}; + +struct intel_excl_cntrs { +raw_spinlock_t lock; + +struct intel_excl_states states[2 ]; + +int refcnt;/* per-core: #HT threads */ +unsigned core_id;/* per-core: core id */ +}; +#define MAX_LBR_ENTRIES 16enum {
@@ -185,6 +206,12 @@ struct cpu_hw_events {* used on Intel NHM/WSM/SNB */ struct intel_shared_regs *shared_regs; +/* +* manage exclusive counter access between hyperthread +*/ +struct event_constraint *constraint_list;/* in enable order */ +struct intel_excl_cntrs *excl_cntrs; +int excl_thread_id;/* 0 or 1 */ /* * AMD specific bits
@@ -208,6 +235,10 @@ struct cpu_hw_events {#define EVENT_CONSTRAINT (c, n, m) \ __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0) +#define INTEL_EXCLEVT_CONSTRAINT (c, n) \ + __EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT, HWEIGHT(n),\ + 0, PERF_X86_EVENT_EXCL) +/* * The overlap flag marks event constraints with overlapping counter * masks. This is the case if the counter mask of such an event is not
@@ -566,6 +597,7 @@ do { \*/ #define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ #define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ +#define PMU_FL_EXCL_CNTRS 0x4/* has exclusive counter requirements */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
arch/x86/kernel/cpu/perf_event_intel.c +66 -5
100 lines not on this page · raw message
PATCH v3 6/13 perf/x86: implement cross-HT corruption bug workaround
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
This patch implements a software workaround for a HW erratum on Intel SandyBridge, IvyBridge and Haswell processors with Hyperthreading enabled. The errata are documented for each processor in their respective specification update documents:
- SandyBridge: BJ122
- IvyBridge: BV98
- Haswell: HSD29
The bug causes silent counter corruption across hyperthreads only when measuring certain memory events (0xd0, 0xd1, 0xd2, 0xd3). Counters measuring those events may leak counts to the sibling counter. For instance, counter 0, thread 0 measuring event 0xd0, may leak to counter 0, thread 1, regardless of the event measured there. The size of the leak is not predictible. It all depends on the workload and the state of each sibling hyper-thread. The corrupting events do undercount as a consequence of the leak. The leak is compensated automatically only when the sibling counter measures the exact same corrupting event AND the workload is on the two threads is the same. Given, there is no way to guarantee this, a work-around is necessary. Furthermore, there is a serious problem if the leaked count is added to a low-occurrence event. In that case the corruption on the low occurrence event can be very large, e.g., orders of magnitude.
There is no HW or FW workaround for this problem.
The bug is very easy to reproduce on a loaded system. Here is an example on a Haswell client, where CPU0, CPU4 are siblings. We load the CPUs with a simple triad app streaming large floating-point vector. We use 0x81d0 corrupting event (MEM_UOPS_RETIRED:ALL_LOADS) and 0x20cc (ROB_MISC_EVENTS:LBR_INSERTS). Given we are not using the LBR, the 0x20cc event should be zero.
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
139 277 291 r20cc
10,000969126 seconds time elapsedIn this example, 0x81d0 and r20cc ar eusing sinling counters on CPU0 and CPU4. 0x81d0 leaks into 0x20cc and corrupts it from 0 to 139 millions occurrences.
This patch provides a software workaround to this problem by modifying the way events are scheduled onto counters by the kernel. The patch forces cross-thread mutual exclusion between counters in case a corrupting event is measured by one of the hyper-threads. If thread 0, counter 0 is measuring event 0xd0, then nothing can be measured on counter 0, thread 1. If no corrupting event is measured on any hyper-thread, event scheduling proceeds as before.
The same example run with the workaround enabled, yield the correct answer:
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
0 r20cc
10,000969126 seconds time elapsedThe patch does provide correctness for all non-corrupting events. It does not "repatriate" the leaked counts back to the leaking counter. This is planned for a second patch series. This patch series makes this repatriation more easy by guaranteeing the sibling counter is not measuring any useful event.
The patch introduces dynamic constraints for events. That means that events which did not have constraints, i.e., could be measured on any counters, may now be constrained to a subset of the counters depending on what is going on the sibling thread. The algorithm is similar to a cache coherency protocol. We call it XSU in reference to Exclusive, Shared, Unused, the 3 possible states of a PMU counter.
As a consequence of the workaround, users may see an increased amount of event multiplexing, even in situtations where there are fewer events than counters measured on a CPU.
Patch has been tested on all three impacted processors. Note that when HT is off, there is no corruption. However, the workaround is still enabled, yet not costing too much. Adding a dynamic detection of HT on turned out to be complex are requiring too much to code to be justified.
This patch addresses the issue when PEBS is not used. A subsequent patch fixes the problem when PEBS is used.
--- arch/x86/kernel/cpu/perf_event.c | 31 ++-- arch/x86/kernel/cpu/perf_event.h | 6 + arch/x86/kernel/cpu/perf_event_intel.c | 307 ++++++++++++++++++++++++++++++++- 3 files changed, 331 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/perf_event.c +19 -12
@@ -724,7 +724,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)struct event_constraint *c;unsigned long used_mask[BITS_TO_LONGS (X86_PMC_IDX_MAX )];struct perf_event *e; -int i, wmin, wmax, num =0 ; +int i, wmin, wmax, unsched =0 ;struct hw_perf_event *hwc;bitmap_zero (used_mask,X86_PMC_IDX_MAX );
@@ -767,14 +767,20 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)/* slow path */ if (i != n) - num =perf_assign_events (cpuc->event_list, n, wmin, - wmax, assign); + unsched =perf_assign_events (cpuc->event_list, n, wmin, + wmax, assign);/* -* Mark the event as committed, so we do not put_constraint() -* in case new events are added and fail scheduling. +* In case of success (unsched = 0), mark events as committed, +* so we do not put_constraint() in case new events are added +* and fail to be scheduled +* +* We invoke the lower level commit callback to lock the resource +* +* We do not need to do all of this in case we are called to +* validate an event group (assign == NULL) */ -if (!num && assign) { +if (!unsched && assign) {for (i =0 ; i < n; i++) { e = cpuc->event_list[i]; e->hw.flags |=PERF_X86_EVENT_COMMITTED ;
@@ -782,11 +788,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) x86_pmu.commit_scheduling (cpuc, e, assign[i]); } } -/* -* scheduling failed or is just a simulation, -* free resources if necessary -*/ -if (!assign || num) { + +if (!assign || unsched) { +for (i =0 ; i < n; i++) { e = cpuc->event_list[i];/*
@@ -796,6 +800,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)if ((e->hw.flags &PERF_X86_EVENT_COMMITTED ))continue ; +/* +* release events that failed scheduling +*/ if (x86_pmu.put_event_constraints) x86_pmu.put_event_constraints (cpuc, e); }
@@ -804,7 +811,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)if (x86_pmu.stop_scheduling) x86_pmu.stop_scheduling (cpuc); -return num ? -EINVAL :0 ; +return unsched ? -EINVAL :0 ; }/*
arch/x86/kernel/cpu/perf_event.h +6 -0
@@ -72,6 +72,7 @@ struct event_constraint {#define PERF_X86_EVENT_PEBS_LD_HSW 0x10/* haswell style datala, load */ #define PERF_X86_EVENT_PEBS_NA_HSW 0x20/* haswell style datala, unknown */ #define PERF_X86_EVENT_EXCL 0x40/* HT exclusivity on counter */ +#define PERF_X86_EVENT_DYNAMIC 0x80/* dynamic alloc'd constraint */ struct amd_nb {int nb_id;/* NorthBridge id */
@@ -131,6 +132,7 @@ enum intel_excl_state_type {struct intel_excl_states {enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ];enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +bool sched_started;/* true if scheduling has started */ };struct intel_excl_cntrs {
@@ -294,6 +296,10 @@ struct cpu_hw_events {#define INTEL_FLAGS_UEVENT_CONSTRAINT (c, n) \ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS) +#define INTEL_EXCLUEVT_CONSTRAINT (c, n) \ + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ + HWEIGHT(n), 0, PERF_X86_EVENT_EXCL) +#define INTEL_PLD_CONSTRAINT (c, n) \ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
arch/x86/kernel/cpu/perf_event_intel.c +306 -1
332 lines not on this page · raw message
Signature · 1 line
1.9.1
tip-bot for Maria Dimakopoulou
merge bot[tip:perf/core] perf/x86/intel: Implement cross-HT corruption bug workaround
perf/x86/intel: Implement cross-HT corruption bug workaround
Commit-ID: e979121b1b1556e184492e6fc149bbe188fc83e6 Gitweb: http://git.kernel.org/tip/e979121b1b1556e184492e6fc149bbe188fc83e6 Author: Maria Dimakopoulou <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:58 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:12 +0200
perf/x86/intel: Implement cross-HT corruption bug workaround
This patch implements a software workaround for a HW erratum on Intel SandyBridge, IvyBridge and Haswell processors with Hyperthreading enabled. The errata are documented for each processor in their respective specification update documents:
- SandyBridge: BJ122
- IvyBridge: BV98
- Haswell: HSD29
The bug causes silent counter corruption across hyperthreads only when measuring certain memory events (0xd0, 0xd1, 0xd2, 0xd3). Counters measuring those events may leak counts to the sibling counter. For instance, counter 0, thread 0 measuring event 0xd0, may leak to counter 0, thread 1, regardless of the event measured there. The size of the leak is not predictible. It all depends on the workload and the state of each sibling hyper-thread. The corrupting events do undercount as a consequence of the leak. The leak is compensated automatically only when the sibling counter measures the exact same corrupting event AND the workload is on the two threads is the same. Given, there is no way to guarantee this, a work-around is necessary. Furthermore, there is a serious problem if the leaked count is added to a low-occurrence event. In that case the corruption on the low occurrence event can be very large, e.g., orders of magnitude.
There is no HW or FW workaround for this problem.
The bug is very easy to reproduce on a loaded system. Here is an example on a Haswell client, where CPU0, CPU4 are siblings. We load the CPUs with a simple triad app streaming large floating-point vector. We use 0x81d0 corrupting event (MEM_UOPS_RETIRED:ALL_LOADS) and 0x20cc (ROB_MISC_EVENTS:LBR_INSERTS). Given we are not using the LBR, the 0x20cc event should be zero.
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
139 277 291 r20cc
10,000969126 seconds time elapsedIn this example, 0x81d0 and r20cc ar eusing sinling counters on CPU0 and CPU4. 0x81d0 leaks into 0x20cc and corrupts it from 0 to 139 millions occurrences.
This patch provides a software workaround to this problem by modifying the way events are scheduled onto counters by the kernel. The patch forces cross-thread mutual exclusion between counters in case a corrupting event is measured by one of the hyper-threads. If thread 0, counter 0 is measuring event 0xd0, then nothing can be measured on counter 0, thread 1. If no corrupting event is measured on any hyper-thread, event scheduling proceeds as before.
The same example run with the workaround enabled, yield the correct answer:
$ taskset -c 0 triad &
$ taskset -c 4 triad &
$ perf stat -a -C 0 -e r81d0 sleep 100 &
$ perf stat -a -C 4 -r20cc sleep 10
Performance counter stats for 'system wide':
0 r20cc
10,000969126 seconds time elapsedThe patch does provide correctness for all non-corrupting events. It does not "repatriate" the leaked counts back to the leaking counter. This is planned for a second patch series. This patch series makes this repatriation more easy by guaranteeing the sibling counter is not measuring any useful event.
The patch introduces dynamic constraints for events. That means that events which did not have constraints, i.e., could be measured on any counters, may now be constrained to a subset of the counters depending on what is going on the sibling thread. The algorithm is similar to a cache coherency protocol. We call it XSU in reference to Exclusive, Shared, Unused, the 3 possible states of a PMU counter.
As a consequence of the workaround, users may see an increased amount of event multiplexing, even in situtations where there are fewer events than counters measured on a CPU.
Patch has been tested on all three impacted processors. Note that when HT is off, there is no corruption. However, the workaround is still enabled, yet not costing too much. Adding a dynamic detection of HT on turned out to be complex are requiring too much to code to be justified.
This patch addresses the issue when PEBS is not used. A subsequent patch fixes the problem when PEBS is used.
--- arch/x86/kernel/cpu/perf_event.c | 31 ++-- arch/x86/kernel/cpu/perf_event.h | 6 + arch/x86/kernel/cpu/perf_event_intel.c | 307 ++++++++++++++++++++++++++++++++- 3 files changed, 331 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/perf_event.c +19 -12
@@ -779,7 +779,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)struct event_constraint *c;unsigned long used_mask[BITS_TO_LONGS (X86_PMC_IDX_MAX )];struct perf_event *e; -int i, wmin, wmax, num =0 ; +int i, wmin, wmax, unsched =0 ;struct hw_perf_event *hwc;bitmap_zero (used_mask,X86_PMC_IDX_MAX );
@@ -822,14 +822,20 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)/* slow path */ if (i != n) - num =perf_assign_events (cpuc->event_list, n, wmin, - wmax, assign); + unsched =perf_assign_events (cpuc->event_list, n, wmin, + wmax, assign);/* -* Mark the event as committed, so we do not put_constraint() -* in case new events are added and fail scheduling. +* In case of success (unsched = 0), mark events as committed, +* so we do not put_constraint() in case new events are added +* and fail to be scheduled +* +* We invoke the lower level commit callback to lock the resource +* +* We do not need to do all of this in case we are called to +* validate an event group (assign == NULL) */ -if (!num && assign) { +if (!unsched && assign) {for (i =0 ; i < n; i++) { e = cpuc->event_list[i]; e->hw.flags |=PERF_X86_EVENT_COMMITTED ;
@@ -837,11 +843,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) x86_pmu.commit_scheduling (cpuc, e, assign[i]); } } -/* -* scheduling failed or is just a simulation, -* free resources if necessary -*/ -if (!assign || num) { + +if (!assign || unsched) { +for (i =0 ; i < n; i++) { e = cpuc->event_list[i];/*
@@ -851,6 +855,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)if ((e->hw.flags &PERF_X86_EVENT_COMMITTED ))continue ; +/* +* release events that failed scheduling +*/ if (x86_pmu.put_event_constraints) x86_pmu.put_event_constraints (cpuc, e); }
@@ -859,7 +866,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)if (x86_pmu.stop_scheduling) x86_pmu.stop_scheduling (cpuc); -return num ? -EINVAL :0 ; +return unsched ? -EINVAL :0 ; }/*
arch/x86/kernel/cpu/perf_event.h +6 -0
@@ -72,6 +72,7 @@ struct event_constraint {#define PERF_X86_EVENT_PEBS_LD_HSW 0x10/* haswell style datala, load */ #define PERF_X86_EVENT_PEBS_NA_HSW 0x20/* haswell style datala, unknown */ #define PERF_X86_EVENT_EXCL 0x40/* HT exclusivity on counter */ +#define PERF_X86_EVENT_DYNAMIC 0x80/* dynamic alloc'd constraint */ #define PERF_X86_EVENT_RDPMC_ALLOWED 0x40/* grant rdpmc permission */
@@ -133,6 +134,7 @@ enum intel_excl_state_type {struct intel_excl_states {enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ];enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +bool sched_started;/* true if scheduling has started */ };struct intel_excl_cntrs {
@@ -296,6 +298,10 @@ struct cpu_hw_events {#define INTEL_FLAGS_UEVENT_CONSTRAINT (c, n) \ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS) +#define INTEL_EXCLUEVT_CONSTRAINT (c, n) \ + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ + HWEIGHT(n), 0, PERF_X86_EVENT_EXCL) +#define INTEL_PLD_CONSTRAINT (c, n) \ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
arch/x86/kernel/cpu/perf_event_intel.c +306 -1
332 lines not on this page · raw message
PATCH v3 7/13 perf/x86: enforce HT bug workaround for SNB/IVB/HSW
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
This patches activates the HT bug workaround for the SNB/IVB/HSW processors. This covers non-PEBS mode. Activation is done thru the constraint tables.
Both client and server processors needs this workaround.
--- arch/x86/kernel/cpu/perf_event_intel.c | 53 ++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 9 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +44 -9
@@ -113,6 +113,12 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly =INTEL_EVENT_CONSTRAINT (0xcd ,0x8 ),/* MEM_TRANS_RETIRED.LOAD_LATENCY */ INTEL_UEVENT_CONSTRAINT (0x04a3 ,0xf ),/* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */ INTEL_UEVENT_CONSTRAINT (0x02a3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -131,15 +137,12 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly =INTEL_UEVENT_CONSTRAINT (0x08a3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT (0x0ca3 ,0x4 ),/* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT (0x01c0 ,0x2 ),/* INST_RETIRED.PREC_DIST */ -/* -* Errata BV98 -- MEM_*_RETIRED events can leak between counters of SMT -* siblings; disable these events because they can corrupt unrelated -* counters. -*/ -INTEL_EVENT_CONSTRAINT (0xd0 ,0x0 ),/* MEM_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd1 ,0x0 ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd2 ,0x0 ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd3 ,0x0 ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -217,6 +220,12 @@ static struct event_constraint intel_hsw_event_constraints[] = {INTEL_EVENT_CONSTRAINT (0x0ca3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ INTEL_EVENT_CONSTRAINT (0x04a3 ,0xf ), + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -2637,6 +2646,27 @@ static __init void intel_nehalem_quirk(void) } } +/* +* enable software workaround for errata: +* SNB: BJ122 +* IVB: BV98 +* HSW: HSD29 +* +* Only needed when HT is enabled. However detecting +* this is too difficult and model specific so we enable +* it even with HT off for now. +*/ +static __init void intel_ht_bug (void ) +{ + x86_pmu.flags |=PMU_FL_EXCL_CNTRS ; + + x86_pmu.commit_scheduling = intel_commit_scheduling; + x86_pmu.start_scheduling = intel_start_scheduling; + x86_pmu.stop_scheduling = intel_stop_scheduling; + +pr_info ("CPU erratum BJ122, BV98, HSD29 worked around\n" ); +} +EVENT_ATTR_STR (mem-loads, mem_ld_hsw,"event=0xcd,umask=0x1,ldlat=3" );EVENT_ATTR_STR (mem-stores, mem_st_hsw,"event=0xd0,umask=0x82" )
@@ -2850,6 +2880,7 @@ __init int intel_pmu_init(void)case 42 :/* 32nm SandyBridge */ case 45 :/* 32nm SandyBridge-E/EN/EP */ x86_add_quirk (intel_sandybridge_quirk); +x86_add_quirk (intel_ht_bug);memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids)); memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
@@ -2864,6 +2895,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snbep_extra_regs; else x86_pmu.extra_regs = intel_snb_extra_regs; + +/* all extra regs are per-cpu when HT is on */ x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; x86_pmu.flags |=PMU_FL_NO_HT_SHARING ;
@@ -2882,6 +2915,7 @@ __init int intel_pmu_init(void)case 58 :/* 22nm IvyBridge */ case 62 :/* 22nm IvyBridge-EP/EX */ +x86_add_quirk (intel_ht_bug);memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids));/* dTLB-load-misses on IVB is different than SNB */
@@ -2917,6 +2951,7 @@ __init int intel_pmu_init(void)case 63 :/* 22nm Haswell Server */ case 69 :/* 22nm Haswell ULT */ case 70 :/* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ +x86_add_quirk (intel_ht_bug); x86_pmu.late_ack = true;memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids));memcpy (hw_cache_extra_regs, snb_hw_cache_extra_regs,sizeof (hw_cache_extra_regs));
Signature · 1 line
1.9.1
tip-bot for Maria Dimakopoulou
merge bot[tip:perf/core] perf/x86/intel: Enforce HT bug workaround for SNB /IVB/HSW
perf/x86/intel: Enforce HT bug workaround for SNB/IVB/HSW
Commit-ID: 93fcf72cc0fa286aa8c3e11a1a8fd4659f0e27c0 Gitweb: http://git.kernel.org/tip/93fcf72cc0fa286aa8c3e11a1a8fd4659f0e27c0 Author: Maria Dimakopoulou <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:06:59 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:12 +0200
perf/x86/intel: Enforce HT bug workaround for SNB/IVB/HSW
This patches activates the HT bug workaround for the SNB/IVB/HSW processors. This covers non-PEBS mode. Activation is done thru the constraint tables.
Both client and server processors needs this workaround.
--- arch/x86/kernel/cpu/perf_event_intel.c | 53 ++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 9 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +44 -9
@@ -113,6 +113,12 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly =INTEL_EVENT_CONSTRAINT (0xcd ,0x8 ),/* MEM_TRANS_RETIRED.LOAD_LATENCY */ INTEL_UEVENT_CONSTRAINT (0x04a3 ,0xf ),/* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */ INTEL_UEVENT_CONSTRAINT (0x02a3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -131,15 +137,12 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly =INTEL_UEVENT_CONSTRAINT (0x08a3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT (0x0ca3 ,0x4 ),/* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT (0x01c0 ,0x2 ),/* INST_RETIRED.PREC_DIST */ -/* -* Errata BV98 -- MEM_*_RETIRED events can leak between counters of SMT -* siblings; disable these events because they can corrupt unrelated -* counters. -*/ -INTEL_EVENT_CONSTRAINT (0xd0 ,0x0 ),/* MEM_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd1 ,0x0 ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd2 ,0x0 ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd3 ,0x0 ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -217,6 +220,12 @@ static struct event_constraint intel_hsw_event_constraints[] = {INTEL_UEVENT_CONSTRAINT (0x0ca3 ,0x4 ),/* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ INTEL_UEVENT_CONSTRAINT (0x04a3 ,0xf ), + +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + EVENT_CONSTRAINT_END };
@@ -2865,6 +2874,27 @@ static __init void intel_nehalem_quirk(void) } } +/* +* enable software workaround for errata: +* SNB: BJ122 +* IVB: BV98 +* HSW: HSD29 +* +* Only needed when HT is enabled. However detecting +* this is too difficult and model specific so we enable +* it even with HT off for now. +*/ +static __init void intel_ht_bug (void ) +{ + x86_pmu.flags |=PMU_FL_EXCL_CNTRS ; + + x86_pmu.commit_scheduling = intel_commit_scheduling; + x86_pmu.start_scheduling = intel_start_scheduling; + x86_pmu.stop_scheduling = intel_stop_scheduling; + +pr_info ("CPU erratum BJ122, BV98, HSD29 worked around\n" ); +} +EVENT_ATTR_STR (mem-loads, mem_ld_hsw,"event=0xcd,umask=0x1,ldlat=3" );EVENT_ATTR_STR (mem-stores, mem_st_hsw,"event=0xd0,umask=0x82" )
@@ -3079,6 +3109,7 @@ __init int intel_pmu_init(void)case 42 :/* 32nm SandyBridge */ case 45 :/* 32nm SandyBridge-E/EN/EP */ x86_add_quirk (intel_sandybridge_quirk); +x86_add_quirk (intel_ht_bug);memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids)); memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
@@ -3093,6 +3124,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snbep_extra_regs; else x86_pmu.extra_regs = intel_snb_extra_regs; + +/* all extra regs are per-cpu when HT is on */ x86_pmu.flags |=PMU_FL_HAS_RSP_1 ; x86_pmu.flags |=PMU_FL_NO_HT_SHARING ;
@@ -3111,6 +3144,7 @@ __init int intel_pmu_init(void)case 58 :/* 22nm IvyBridge */ case 62 :/* 22nm IvyBridge-EP/EX */ +x86_add_quirk (intel_ht_bug);memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids));/* dTLB-load-misses on IVB is different than SNB */
@@ -3146,6 +3180,7 @@ __init int intel_pmu_init(void)case 63 :/* 22nm Haswell Server */ case 69 :/* 22nm Haswell ULT */ case 70 :/* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ +x86_add_quirk (intel_ht_bug); x86_pmu.late_ack = true;memcpy (hw_cache_event_ids, hsw_hw_cache_event_ids,sizeof (hw_cache_event_ids));memcpy (hw_cache_extra_regs, hsw_hw_cache_extra_regs,sizeof (hw_cache_extra_regs));
PATCH v3 8/13 perf/x86: enforce HT bug workaround with PEBS for SNB/IVB/HSW
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
This patch modifies the PEBS constraint tables for SNB/IVB/HSW such that corrupting events supporting PEBS activate the HT workaround.
--- arch/x86/kernel/cpu/perf_event.h | 20 +++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_ds.c | 28 ++++++++++++++++++---------- 2 files changed, 37 insertions(+), 11 deletions(-)
arch/x86/kernel/cpu/perf_event.h +19 -1
@@ -324,22 +324,40 @@ struct cpu_hw_events {/* Check flags and event code, and set the HSW load flag */ #define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (code, n) \ - __EVENT_CONSTRAINT(code, n, \ + __EVENT_CONSTRAINT(code, n, \ ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) +#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW store flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (code, n) \ __EVENT_CONSTRAINT(code, n, \ INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW) +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_ST_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW load flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (code, n) \ __EVENT_CONSTRAINT(code, n, \ INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW N/A flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA (code, n) \ __EVENT_CONSTRAINT(code, n, \
arch/x86/kernel/cpu/perf_event_intel_ds.c +18 -10
@@ -611,6 +611,10 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ), +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
@@ -622,6 +626,10 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ), +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
@@ -633,16 +641,16 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ),INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA (0x01c2 ,0xf ),/* UOPS_RETIRED.ALL */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x11d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x12d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_STORES */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x42d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_STORES */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x82d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_STORES */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd2 ,0xf ),/* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd3 ,0xf ),/* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x11d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x12d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_STORES */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x42d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_STORES */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x82d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_STORES */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd2 ,0xf ),/* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd3 ,0xf ),/* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
Signature · 1 line
1.9.1
tip-bot for Maria Dimakopoulou
merge bot[tip:perf/core] perf/x86/intel: Enforce HT bug workaround with PEBS for SNB/IVB/HSW
perf/x86/intel: Enforce HT bug workaround with PEBS for SNB/IVB/HSW
Commit-ID: b63b4b459a78a9a45ea47a4803b8d1868e9d17d5 Gitweb: http://git.kernel.org/tip/b63b4b459a78a9a45ea47a4803b8d1868e9d17d5 Author: Maria Dimakopoulou <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:07:00 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:13 +0200
perf/x86/intel: Enforce HT bug workaround with PEBS for SNB/IVB/HSW
This patch modifies the PEBS constraint tables for SNB/IVB/HSW such that corrupting events supporting PEBS activate the HT workaround.
--- arch/x86/kernel/cpu/perf_event.h | 20 +++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_ds.c | 28 ++++++++++++++++++---------- 2 files changed, 37 insertions(+), 11 deletions(-)
arch/x86/kernel/cpu/perf_event.h +19 -1
@@ -326,22 +326,40 @@ struct cpu_hw_events {/* Check flags and event code, and set the HSW load flag */ #define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (code, n) \ - __EVENT_CONSTRAINT(code, n, \ + __EVENT_CONSTRAINT(code, n, \ ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) +#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW store flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (code, n) \ __EVENT_CONSTRAINT(code, n, \ INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW) +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_ST_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW load flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (code, n) \ __EVENT_CONSTRAINT(code, n, \ INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, \ + PERF_X86_EVENT_PEBS_LD_HSW|PERF_X86_EVENT_EXCL) +/* Check flags and event code/umask, and set the HSW N/A flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA (code, n) \ __EVENT_CONSTRAINT(code, n, \
arch/x86/kernel/cpu/perf_event_intel_ds.c +18 -10
@@ -612,6 +612,10 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ), +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
@@ -623,6 +627,10 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ), +INTEL_EXCLEVT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ +INTEL_EXCLEVT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
@@ -634,16 +642,16 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ INTEL_FLAGS_EVENT_CONSTRAINT (0x108001c2 ,0xf ),INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA (0x01c2 ,0xf ),/* UOPS_RETIRED.ALL */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x11d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x12d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_STORES */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x42d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_STORES */ -INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST (0x82d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_STORES */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd2 ,0xf ),/* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ -INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD (0xd3 ,0xf ),/* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x11d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x12d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_STORES */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x42d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_STORES */ +INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XST (0x82d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_STORES */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd2 ,0xf ),/* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ +INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_XLD (0xd3 ,0xf ),/* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ /* Allow all events as PEBS with no flags */ INTEL_ALL_EVENT_CONSTRAINT (0 ,0xf ),EVENT_CONSTRAINT_END
PATCH v3 9/13 perf/x86: fix intel_get_event_constraints() for dynamic constraints
In reply to Stephane EranianWith dynamic constraint, we need to restart from the static constraints each time the intel_get_event_constraints() is called.
--- arch/x86/kernel/cpu/perf_event_intel.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +10 -5
@@ -1860,20 +1860,25 @@ static struct event_constraint * intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx, struct perf_event *event) { - struct event_constraint *c = event->hw.constraint; + struct event_constraint *c1 = event->hw.constraint; +struct event_constraint *c2;/* * first time only * - static constraint: no change across incremental scheduling calls * - dynamic constraint: handled by intel_get_excl_constraints() */ -if (!c) - c =__intel_get_event_constraints (cpuc, idx, event); + c2 =__intel_get_event_constraints (cpuc, idx, event); +if (c1 && (c1->flags &PERF_X86_EVENT_DYNAMIC )) { +bitmap_copy (c1->idxmsk, c2->idxmsk,X86_PMC_IDX_MAX ); + c1->weight = c2->weight; + c2 = c1; + }if (cpuc->excl_cntrs) -return intel_get_excl_constraints (cpuc, event, idx, c); +return intel_get_excl_constraints (cpuc, event, idx, c2); -return c; +return c2; } static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86/intel: Fix intel_get_event_constraints() for dynamic constraints
perf/x86/intel: Fix intel_get_event_constraints() for dynamic constraints
Commit-ID: a90738c2cb0dceb882e0d7f7f9141e0062809b4d Gitweb: http://git.kernel.org/tip/a90738c2cb0dceb882e0d7f7f9141e0062809b4d Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:07:01 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:14 +0200
perf/x86/intel: Fix intel_get_event_constraints() for dynamic constraints
With dynamic constraint, we need to restart from the static constraints each time the intel_get_event_constraints() is called.
--- arch/x86/kernel/cpu/perf_event_intel.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +10 -5
@@ -2063,20 +2063,25 @@ static struct event_constraint * intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx, struct perf_event *event) { - struct event_constraint *c = event->hw.constraint; + struct event_constraint *c1 = event->hw.constraint; +struct event_constraint *c2;/* * first time only * - static constraint: no change across incremental scheduling calls * - dynamic constraint: handled by intel_get_excl_constraints() */ -if (!c) - c =__intel_get_event_constraints (cpuc, idx, event); + c2 =__intel_get_event_constraints (cpuc, idx, event); +if (c1 && (c1->flags &PERF_X86_EVENT_DYNAMIC )) { +bitmap_copy (c1->idxmsk, c2->idxmsk,X86_PMC_IDX_MAX ); + c1->weight = c2->weight; + c2 = c1; + }if (cpuc->excl_cntrs) -return intel_get_excl_constraints (cpuc, event, idx, c); +return intel_get_excl_constraints (cpuc, event, idx, c2); -return c; +return c2; } static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
PATCH v3 10/13 perf/x86: limit to half counters to avoid exclusive mode starvation
In reply to Stephane EranianThis 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.
--- arch/x86/kernel/cpu/perf_event.h | 2 ++ arch/x86/kernel/cpu/perf_event_intel.c | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -132,6 +132,8 @@ enum intel_excl_state_type {struct intel_excl_states {enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ];enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +int num_alloc_cntrs;/* #counters allocated */ +int max_alloc_cntrs;/* max #counters allowed */ bool sched_started;/* true if scheduling has started */ };
arch/x86/kernel/cpu/perf_event_intel.c +20 -2
@@ -1694,7 +1694,7 @@ intel_start_scheduling(struct cpu_hw_events *cpuc) xl = &excl_cntrs->states[tid]; xl->sched_started = true; - + xl->num_alloc_cntrs =0 ;/* * lock shared state until we are done scheduling * in stop_event_scheduling()
@@ -1760,7 +1760,6 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,*/ if (cpuc->is_fake)return c; -/* * event requires exclusive counter access * across HT threads
@@ -1774,6 +1773,18 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, xl = &excl_cntrs->states[tid]; xlo = &excl_cntrs->states[o_tid]; +/* +* do not allow scheduling of more than max_alloc_cntrs +* which is set to half the available generic counters. +* this helps avoid counter starvation of sibling thread +* by ensuring at most half the counters cannot be in +* exclusive mode. There is not designated counters for the +* limits. Any N/2 counters can be used. This helps with +* events with specifix counter constraints +*/ +if (xl->num_alloc_cntrs++ == xl->max_alloc_cntrs) +return &emptyconstraint; + cx = c;/*
@@ -2384,6 +2395,8 @@ static void intel_pmu_cpu_starting(int cpu) cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR ];if (x86_pmu.flags &PMU_FL_EXCL_CNTRS ) { +int h = x86_pmu.num_counters >>1 ; +for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_excl_cntrs *c;
@@ -2397,6 +2410,11 @@ static void intel_pmu_cpu_starting(int cpu) } cpuc->excl_cntrs->core_id = core_id; cpuc->excl_cntrs->refcnt++; +/* +* set hard limit to half the number of generic counters +*/ + cpuc->excl_cntrs->states[0 ].max_alloc_cntrs = h; + cpuc->excl_cntrs->states[1 ].max_alloc_cntrs = h; } }
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86/intel: Limit to half counters when the HT workaround is enabled, to avoid exclusive mode starvation
perf/x86/intel: Limit to half counters when the HT workaround is enabled, to avoid exclusive mode starvation
Commit-ID: c02cdbf60b51b8d98a49185535f5d527a2965142 Gitweb: http://git.kernel.org/tip/c02cdbf60b51b8d98a49185535f5d527a2965142 Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:07:02 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:14 +0200
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.)
--- arch/x86/kernel/cpu/perf_event.h | 2 ++ arch/x86/kernel/cpu/perf_event_intel.c | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -134,6 +134,8 @@ enum intel_excl_state_type {struct intel_excl_states {enum intel_excl_state_type init_state[X86_PMC_IDX_MAX ];enum intel_excl_state_type state[X86_PMC_IDX_MAX ]; +int num_alloc_cntrs;/* #counters allocated */ +int max_alloc_cntrs;/* max #counters allowed */ bool sched_started;/* true if scheduling has started */ };
arch/x86/kernel/cpu/perf_event_intel.c +20 -2
@@ -1897,7 +1897,7 @@ intel_start_scheduling(struct cpu_hw_events *cpuc) xl = &excl_cntrs->states[tid]; xl->sched_started = true; - + xl->num_alloc_cntrs =0 ;/* * lock shared state until we are done scheduling * in stop_event_scheduling()
@@ -1963,7 +1963,6 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,*/ if (cpuc->is_fake)return c; -/* * event requires exclusive counter access * across HT threads
@@ -1977,6 +1976,18 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, xl = &excl_cntrs->states[tid]; xlo = &excl_cntrs->states[o_tid]; +/* +* do not allow scheduling of more than max_alloc_cntrs +* which is set to half the available generic counters. +* this helps avoid counter starvation of sibling thread +* by ensuring at most half the counters cannot be in +* exclusive mode. There is not designated counters for the +* limits. Any N/2 counters can be used. This helps with +* events with specifix counter constraints +*/ +if (xl->num_alloc_cntrs++ == xl->max_alloc_cntrs) +return &emptyconstraint; + cx = c;/*
@@ -2624,6 +2635,8 @@ static void intel_pmu_cpu_starting(int cpu) cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR ];if (x86_pmu.flags &PMU_FL_EXCL_CNTRS ) { +int h = x86_pmu.num_counters >>1 ; +for_each_cpu (i,topology_thread_cpumask (cpu)) {struct intel_excl_cntrs *c;
@@ -2637,6 +2650,11 @@ static void intel_pmu_cpu_starting(int cpu) } cpuc->excl_cntrs->core_id = core_id; cpuc->excl_cntrs->refcnt++; +/* +* set hard limit to half the number of generic counters +*/ + cpuc->excl_cntrs->states[0 ].max_alloc_cntrs = h; + cpuc->excl_cntrs->states[1 ].max_alloc_cntrs = h; } }
PATCH v3 11/13 watchdog: add watchdog enable/disable all functions
In reply to Stephane EranianThis patch adds two new functions to enable/disable the watchdog across all CPUs.
--- include/linux/watchdog.h | 8 ++++++++ kernel/watchdog.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
include/linux/watchdog.h +8 -0
@@ -137,4 +137,12 @@ extern int watchdog_init_timeout(struct watchdog_device *wdd,extern int watchdog_register_device (struct watchdog_device *);extern void watchdog_unregister_device (struct watchdog_device *); +#ifdef CONFIG_HARDLOCKUP_DETECTOR +void watchdog_nmi_disable_all (void ); +void watchdog_nmi_enable_all (void ); +#else +static inline void watchdog_nmi_disable_all (void ) {} +static inline void watchdog_nmi_enable_all (void ) {} +#endif +#endif /* ifndef _LINUX_WATCHDOG_H */
kernel/watchdog.c +28 -0
@@ -567,9 +567,37 @@ static void watchdog_nmi_disable(unsigned int cpu) cpu0_err = 0; } } + +void watchdog_nmi_enable_all (void ) +{ +int cpu; + +if (!watchdog_user_enabled) +return ; + +get_online_cpus (); +for_each_online_cpu (cpu) +watchdog_nmi_enable (cpu); +put_online_cpus (); +} + +void watchdog_nmi_disable_all (void ) +{ +int cpu; + +if (!watchdog_running) +return ; + +get_online_cpus (); +for_each_online_cpu (cpu) +watchdog_nmi_disable (cpu); +put_online_cpus (); +}#else static int watchdog_nmi_enable (unsigned int cpu) {return 0 ; }static void watchdog_nmi_disable (unsigned int cpu) {return ; } +void watchdog_nmi_enable_all (void ) {} +void watchdog_nmi_disable_all (void ) {}#endif /* CONFIG_HARDLOCKUP_DETECTOR */ static struct smp_hotplug_thread watchdog_threads = {
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] watchdog: Add watchdog enable/ disable all functions
watchdog: Add watchdog enable/disable all functions
Commit-ID: b3738d29323344da3017a91010530cf3a58590fc Gitweb: http://git.kernel.org/tip/b3738d29323344da3017a91010530cf3a58590fc Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:07:03 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:15 +0200
watchdog: Add watchdog enable/disable all functions
This patch adds two new functions to enable/disable the watchdog across all CPUs.
This will be used by the HT PMU bug workaround code to disable/enable the NMI watchdog across quirk enablement.
--- include/linux/watchdog.h | 8 ++++++++ kernel/watchdog.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
include/linux/watchdog.h +8 -0
@@ -137,4 +137,12 @@ extern int watchdog_init_timeout(struct watchdog_device *wdd,extern int watchdog_register_device (struct watchdog_device *);extern void watchdog_unregister_device (struct watchdog_device *); +#ifdef CONFIG_HARDLOCKUP_DETECTOR +void watchdog_nmi_disable_all (void ); +void watchdog_nmi_enable_all (void ); +#else +static inline void watchdog_nmi_disable_all (void ) {} +static inline void watchdog_nmi_enable_all (void ) {} +#endif +#endif /* ifndef _LINUX_WATCHDOG_H */
kernel/watchdog.c +28 -0
@@ -567,9 +567,37 @@ static void watchdog_nmi_disable(unsigned int cpu) cpu0_err = 0; } } + +void watchdog_nmi_enable_all (void ) +{ +int cpu; + +if (!watchdog_user_enabled) +return ; + +get_online_cpus (); +for_each_online_cpu (cpu) +watchdog_nmi_enable (cpu); +put_online_cpus (); +} + +void watchdog_nmi_disable_all (void ) +{ +int cpu; + +if (!watchdog_running) +return ; + +get_online_cpus (); +for_each_online_cpu (cpu) +watchdog_nmi_disable (cpu); +put_online_cpus (); +}#else static int watchdog_nmi_enable (unsigned int cpu) {return 0 ; }static void watchdog_nmi_disable (unsigned int cpu) {return ; } +void watchdog_nmi_enable_all (void ) {} +void watchdog_nmi_disable_all (void ) {}#endif /* CONFIG_HARDLOCKUP_DETECTOR */ static struct smp_hotplug_thread watchdog_threads = {
PATCH v3 12/13 perf/x86: make HT bug workaround conditioned on HT enabled
In reply to Stephane EranianThis patch disables the PMU HT bug when Hyperthreading (HT) is disabled. We cannot do this test immediately when perf_events is initialized. We need to wait until the topology information is setup properly. As such, we register a later initcall, check the topology and potentially disable the workaround. To do this, we need to ensure there is no user of the PMU. At this point of the boot, the only user is the NMI watchdog, thus we disable it during the switch and re-enable right after.
Having the workaround disabled when it is not needed provides some benefits by limiting the overhead is time and space. The workaround still ensures correct scheduling of the corrupting memory events (0xd0, 0xd1, 0xd2) when HT is off. Those events can only be measured on counters 0-3. Something else the current kernel did not handle correctly.
--- arch/x86/kernel/cpu/perf_event.h | 5 ++ arch/x86/kernel/cpu/perf_event_intel.c | 95 ++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 21 deletions(-)
arch/x86/kernel/cpu/perf_event.h +5 -0
@@ -601,6 +601,7 @@ do { \#define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ #define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ #define PMU_FL_EXCL_CNTRS 0x4/* has exclusive counter requirements */ +#define PMU_FL_EXCL_ENABLED 0x8/* exclusive counter active */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
@@ -834,6 +835,10 @@ int knc_pmu_init(void);ssize_t events_sysfs_show (struct device *dev,struct device_attribute *attr,char *page); +static inline int is_ht_workaround_enabled (void ) +{ +return !!(x86_pmu.flags &PMU_FL_EXCL_ENABLED ); +}#else /* CONFIG_CPU_SUP_INTEL */ static inline void reserve_ds_buffers (void )
arch/x86/kernel/cpu/perf_event_intel.c +74 -21
155 lines not on this page · raw message
Signature · 1 line
1.9.1
tip-bot for Stephane Eranian
merge bot[tip:perf/core] perf/x86/intel: Make the HT bug workaround conditional on HT enabled
perf/x86/intel: Make the HT bug workaround conditional on HT enabled
Commit-ID: b37609c30e41264c4df4acff78abfc894499a49b Gitweb: http://git.kernel.org/tip/b37609c30e41264c4df4acff78abfc894499a49b Author: Stephane Eranian <[email protected]> AuthorDate: Mon, 17 Nov 2014 20:07:04 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 2 Apr 2015 17:33:15 +0200
perf/x86/intel: Make the HT bug workaround conditional on HT enabled
This patch disables the PMU HT bug when Hyperthreading (HT) is disabled. We cannot do this test immediately when perf_events is initialized. We need to wait until the topology information is setup properly. As such, we register a later initcall, check the topology and potentially disable the workaround. To do this, we need to ensure there is no user of the PMU. At this point of the boot, the only user is the NMI watchdog, thus we disable it during the switch and re-enable it right after.
Having the workaround disabled when it is not needed provides some benefits by limiting the overhead is time and space. The workaround still ensures correct scheduling of the corrupting memory events (0xd0, 0xd1, 0xd2) when HT is off. Those events can only be measured on counters 0-3. Something else the current kernel did not handle correctly.
--- arch/x86/kernel/cpu/perf_event.h | 5 ++ arch/x86/kernel/cpu/perf_event_intel.c | 95 ++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 21 deletions(-)
arch/x86/kernel/cpu/perf_event.h +5 -0
@@ -624,6 +624,7 @@ do { \#define PMU_FL_NO_HT_SHARING 0x1/* no hyper-threading resource sharing */ #define PMU_FL_HAS_RSP_1 0x2/* has 2 equivalent offcore_rsp regs */ #define PMU_FL_EXCL_CNTRS 0x4/* has exclusive counter requirements */ +#define PMU_FL_EXCL_ENABLED 0x8/* exclusive counter active */ #define EVENT_VAR (_id) event_attr_##_id#define EVENT_PTR (_id) &event_attr_##_id.attr.attr
@@ -904,6 +905,10 @@ int knc_pmu_init(void);ssize_t events_sysfs_show (struct device *dev,struct device_attribute *attr,char *page); +static inline int is_ht_workaround_enabled (void ) +{ +return !!(x86_pmu.flags &PMU_FL_EXCL_ENABLED ); +}#else /* CONFIG_CPU_SUP_INTEL */ static inline void reserve_ds_buffers (void )
arch/x86/kernel/cpu/perf_event_intel.c +74 -21
155 lines not on this page · raw message
PATCH v3 13/13 perf/x86: add syfs entry to disable HT bug workaround
In reply to Stephane EranianFrom: Maria Dimakopoulou <[email protected]>
This patch adds a sysfs entry:
/sys/devices/cpu/ht_bug_workaround
to activate/deactivate the PMU HT bug workaround.
To activate (activated by default):
# echo 1 > /sys/devices/cpu/ht_bug_workaround
To deactivate:
# echo 0 > /sys/devices/cpu/ht_bug_workaround
Results effective only once there is no more active events.
--- arch/x86/kernel/cpu/perf_event.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
arch/x86/kernel/cpu/perf_event.c +44 -0
@@ -1881,10 +1881,54 @@ static ssize_t set_attr_rdpmc(struct device *cdev,return count; } +static ssize_t get_attr_xsu (struct device *cdev, +struct device_attribute *attr, +char *buf) +{ +int ff =is_ht_workaround_enabled (); + +return snprintf (buf,40 ,"%d\n" , ff); +} + +static ssize_t set_attr_xsu (struct device *cdev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs; +unsigned long val; +unsigned long flags; +int ff =is_ht_workaround_enabled (); +ssize_t ret; + +/* +* if workaround, disabled, no effect +*/ +if (!excl_cntrs) +return count; + + ret =kstrtoul (buf,0 , &val); +if (ret) +return ret; + +spin_lock_irqsave (&excl_cntrs->lock, flags); +if (!!val != ff) { +if (!val) + x86_pmu.flags &= ~PMU_FL_EXCL_ENABLED ; +else + x86_pmu.flags |=PMU_FL_EXCL_ENABLED ; + } +spin_unlock_irqrestore (&excl_cntrs->lock, flags); +return count; +} + static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc); +static DEVICE_ATTR(ht_bug_workaround, S_IRUSR | S_IWUSR, get_attr_xsu, + set_attr_xsu);static struct attribute *x86_pmu_attrs[] = { &dev_attr_rdpmc.attr, + &dev_attr_ht_bug_workaround.attr,NULL , };
Signature · 1 line
1.9.1
Borislav Petkov
maintainerRe: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 6 lines · Stephane Eranian
From: Maria Dimakopoulou <[email protected]>
This patch adds a sysfs entry:
/sys/devices/cpu/ht_bug_workaround
Quoted 7 lines
to activate/deactivate the PMU HT bug workaround.
To activate (activated by default):
# echo 1 > /sys/devices/cpu/ht_bug_workaroundTo deactivate:
# echo 0 > /sys/devices/cpu/ht_bug_workaround
If I put my simple-user hat and stare at this sysfs node, I'm not really becoming any smarter from looking at the name. HT bug? A hyper-threading bug?? I see the user forums going nuts already.
Instead of adding a sysfs node per CPU bug, I'm wondering whether adding a
/sys/devices/system/cpu/bugs
file which gets a mask of bits to enable and disable workarounds would be much cleaner.
x86 guys, what do you guys think?
Such a scheme should be much more easily extensible in the future in case we want to add another workaround toggle.
The hierarchy is not optimal either as it should be under "perf"-something but I don't think we have a perf sysfs node...
Quoted 6 lines
Results effective only once there is no more active events.
Reviewed-by Stephane Eranian <[email protected]>Signed-off-by Maria Dimakopoulou <[email protected]>---
...
arch/x86/kernel/cpu/perf_event.c static ssize_t set_attr_rdpmc(struct device *cdev, · line 1931
Quoted 7 lines
static
DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);arch/x86/kernel/cpu/perf_event.c +3
-0+static DEVICE_ATTR(ht_bug_workaround, S_IRUSR | S_IWUSR, get_attr_xsu, + set_attr_xsu);static struct attribute *x86_pmu_attrs[] = { &dev_attr_rdpmc.attr, + &dev_attr_ht_bug_workaround.attr,
You should be adding this dynamically, only when running on Intel, i.e.
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) /* add bug_workaround attr */
For an example, see amd_l3_attrs() inarch/x86/kernel/cpu/intel_cacheinfo.c
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 22 lines · Borislav Petkov
Quoted 6 lines · Stephane Eranian
From: Maria Dimakopoulou <[email protected]>
This patch adds a sysfs entry:
/sys/devices/cpu/ht_bug_workaroundQuoted 7 lines
to activate/deactivate the PMU HT bug workaround.
To activate (activated by default):
# echo 1 > /sys/devices/cpu/ht_bug_workaroundTo deactivate:
# echo 0 > /sys/devices/cpu/ht_bug_workaroundIf I put my simple-user hat and stare at this sysfs node, I'm not really becoming any smarter from looking at the name. HT bug? A hyper-threading bug?? I see the user forums going nuts already.
Instead of adding a sysfs node per CPU bug, I'm wondering whether adding a
Quoted 6 lines
/sys/devices/system/cpu/bugsfile which gets a mask of bits to enable and disable workarounds would be much cleaner.
x86 guys, what do you guys think?
Well a bitmask is a pretty indescriptive item as well. Putting my user hat on: Where is the documentation for the bits?
Quoted 2 lines
Such a scheme should be much more easily extensible in the future in case we want to add another workaround toggle.
Agreed, but that does not make it more intuitive.
Quoted 2 lines
The hierarchy is not optimal either as it should be under "perf"-something but I don't think we have a perf sysfs node...
I'm not sure about that. Its a CPU bug at the very end. We should not care much which of the various bits and pieces of a CPU it affects and some of them affect more than one ....
But OTOH, we dont want to have random entries with impossible to understand file names under /sys/devices/cpu/ either.
So what about adding:
/sys/devices/cpu/bugs/
and collect the various user tweakable (or not) bug data there.
So for the problem at hand:
/sys/devices/cpu/bugs/ht_some_sensible_name/
Directory
/sys/devices/cpu/bugs/ht_some_sensible_name/info
File, which describes the bug comprehensive. URL reference, Errata Nr. or something like that.
/sys/devices/cpu/bugs/ht_some_sensible_name/workaround
File, to retrieve the status of the workaround. Possibly RO depending on the nature of the issue.
Quoted 4 lines
Quoted 4 lines
static
DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);arch/x86/kernel/cpu/perf_event.c +2
-0+static DEVICE_ATTR(ht_bug_workaround, S_IRUSR | S_IWUSR, get_attr_xsu, + set_attr_xsu);
Quoted 8 lines
arch/x86/kernel/cpu/perf_event.c static ssize_t set_attr_rdpmc(struct device *cdev, · line 1931
Quoted 3 lines
static struct attribute *x86_pmu_attrs[] = {
arch/x86/kernel/cpu/perf_event.c +1
-0&dev_attr_rdpmc.attr, + &dev_attr_ht_bug_workaround.attr,You should be adding this dynamically, only when running on Intel, i.e.
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) /* add bug_workaround attr */
and if it's a family/model specific issue, we don't want to see it if we are not running on such a machine.
Quoted 2 lines
For an example, see
amd_l3_attrs()inarch/x86/kernel/cpu/intel_cacheinfo.c
Given the fact that the number of bugs is going to grow, we probably want some infrastructure for this.
Thanks,
tglx
Borislav Petkov
maintainerRe: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 2 lines · Thomas Gleixner
Well a bitmask is a pretty indescriptive item as well. Putting my user hat on: Where is the documentation for the bits?
$ cat /sys/devices/system/cpu/bugs 0xXXXXXX - currently enabled workarounds are the set bits. bit 0: workaround for bug#blabla bit 1: workaround for bug#1 bit 2: workaround for bug#2; remember to do <bla> before disabling workaround ... bits n-63 are reserved, cannot be set and RAZ.
This will be issued when user cats the sysfs file.
Quoted 21 lines
I'm not sure about that. Its a CPU bug at the very end. We should not care much which of the various bits and pieces of a CPU it affects and some of them affect more than one ....
But OTOH, we dont want to have random entries with impossible to understand file names under
/sys/devices/cpu/either.So what about adding:
/sys/devices/cpu/bugs/and collect the various user tweakable (or not) bug data there.
So for the problem at hand:
/sys/devices/cpu/bugs/ht_some_sensible_name/Directory
/sys/devices/cpu/bugs/ht_some_sensible_name/info
Quoted 7 lines
File, which describes the bug comprehensive. URL reference, Errata Nr. or something like that.
/sys/devices/cpu/bugs/ht_some_sensible_name/workaroundFile, to retrieve the status of the workaround. Possibly RO depending on the nature of the issue.
Yes, that could be an alternative scheme to the one I'm proposing above. But the one above is easier to implement and should contain enough info to find the bug number in the relevant revision guide/doc update.
Quoted 7 lines
Quoted 4 lines
You should be adding this dynamically, only when running on Intel, i.e.
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) /* add bug_workaround attr */and if it's a family/model specific issue, we don't want to see it if we are not running on such a machine.
Yep.
Quoted 2 lines
Given the fact that the number of bugs is going to grow, we probably want some infrastructure for this.
Yeah, there's the "bugs:" line in /proc/cpuinfo so it should be easy to extend the X86_BUG_XXXX fun.
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 11 lines · Borislav Petkov
Quoted 2 lines · Thomas Gleixner
Well a bitmask is a pretty indescriptive item as well. Putting my user hat on: Where is the documentation for the bits?
$ cat /sys/devices/system/cpu/bugs 0xXXXXXX - currently enabled workarounds are the set bits. bit 0: workaround for bug#blabla bit 1: workaround for bug#1 bit 2: workaround for bug#2; remember to do <bla> before disabling workaround ... bits n-63 are reserved, cannot be set and RAZ.
You sure that 64 are enough?
You need to create stable but numbers, i.e. each bug gets a fixed but number whethr it affects the machine or not. Otherwise you will drive admins completely nuts.
Quoted 1 line
This will be issued when user cats the sysfs file.
That might work as well, though you want that to be:
/sys/devices/system/cpu/bugs/
/sys/devices/system/cpu/bugs/status
/sys/devices/system/cpu/bugs/enable_workaround
/sys/devices/system/cpu/bugs/disable_workaround
The latter two take a bit number rather than a magic mask.
So while it looks less effort to implement and extend in the first place I think, that a bit of infrastructure work will make the explicit scheme I proposed before a no brainer to maintain and extend, but I cannot judge what's more intuitive to use.
Thanks,
tglx
Re: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Hi,
Quoted 26 lines · Thomas Gleixner
Quoted 11 lines · Borislav Petkov
Quoted 2 lines · Thomas Gleixner
Well a bitmask is a pretty indescriptive item as well. Putting my user hat on: Where is the documentation for the bits?
$ cat /sys/devices/system/cpu/bugs 0xXXXXXX - currently enabled workarounds are the set bits. bit 0: workaround for bug#blabla bit 1: workaround for bug#1 bit 2: workaround for bug#2; remember to do <bla> before disabling workaround ... bits n-63 are reserved, cannot be set and RAZ.You sure that 64 are enough?
You need to create stable but numbers, i.e. each bug gets a fixed but number whethr it affects the machine or not. Otherwise you will drive admins completely nuts.
Quoted 1 line
This will be issued when user cats the sysfs file.
That might work as well, though you want that to be:
/sys/devices/system/cpu/bugs/
Quoted 8 lines
/sys/devices/system/cpu/bugs/status
/sys/devices/system/cpu/bugs/enable_workaround
/sys/devices/system/cpu/bugs/disable_workaroundThe latter two take a bit number rather than a magic mask.
I am trying to get a better understanding of this scheme.
status:
- a summary of what is enabled/disabled?
- With description (as suggested by Boris)?
- File is readonly
- is that printing a variable length bitmask?
enable_workaround:
- provide the bit number (of the workaround) to enable the workaround
- File is write-only
disable_workaround:
- provide the bit number (of the workaround) to disable the workaround
- File is write-only
The split enable/disable is to avoid the read-modify-write issue.
Am I getting this right?
I understand the value of this proposition. But, I feel, it is beyond the scope of the patch series to workaround the PMU bug. Initially, we had talked about not
even providing the sysfs file. Now, the series adjusts the workaround on boot. The series is restructured so that the sysfs patch is the last one and is totally optional. I think we should implement the proposed scheme but we should not delay the review and merge of the rest of the patch series for this. But I can propose a separate patch series to implement the proposed scheme.
Quoted 11 lines
So while it looks less effort to implement and extend in the first place I think, that a bit of infrastructure work will make the explicit scheme I proposed before a no brainer to maintain and extend, but I cannot judge what's more intuitive to use.
Thanks,
tglx
Borislav Petkov
maintainerRe: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 7 lines · Stephane Eranian
I am trying to get a better understanding of this scheme.
status:
- a summary of what is enabled/disabled?
- With description (as suggested by Boris)?
- File is readonly
- is that printing a variable length bitmask?
Should be the easiest. Maybe extend/add to the X86_BUG() functionality in arch/x86/include/asm/cpufeature.h which already deals with CPU bugs.
Quoted 2 lines
enable_workaround:
- provide the bit number (of the workaround) to enable the workaround
Right, writing the bit number could be part of the description message above - just so that users know how to control the interface.
Quoted 10 lines
- File is write-only
disable_workaround:
- provide the bit number (of the workaround) to disable the workaround
- File is write-onlyThe split enable/disable is to avoid the read-modify-write issue.
Am I getting this right?
Quoted 9 lines
I understand the value of this proposition. But, I feel, it is beyond the scope of the patch series to workaround the PMU bug. Initially, we had talked about not
even providing the sysfs file. Now, the series adjusts the workaround on boot. The series is restructured so that the sysfs patch is the last one and is totally optional. I think we should implement the proposed scheme but we should not delay the review and merge of the rest of the patch series for this. But I can propose a separate patch series to implement the proposed scheme.
Right, IMHO, we can always add sysfs structure later, when its design is sane. What we should absolutely avoid is exposing something to userspace now and then try to hide it/replace it with something else and break userspace, which, as we all know, is a no-no, punishable by Linus coming to your house with a bat.
:-) :-)
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 12 lines · Borislav Petkov
Quoted 7 lines · Stephane Eranian
I am trying to get a better understanding of this scheme.
status:
- a summary of what is enabled/disabled?
- With description (as suggested by Boris)?
- File is readonly
- is that printing a variable length bitmask?Should be the easiest. Maybe extend/add to the
X86_BUG()functionality inarch/x86/include/asm/cpufeature.hwhich already deals with CPU bugs.
Does it need to bit a bitmask, as opposed to just a bug number (which could be implemented as a bitmask)?
Quoted 6 lines
Quoted 2 lines
enable_workaround:
- provide the bit number (of the workaround) to enable the workaroundRight, writing the bit number could be part of the description message above - just so that users know how to control the interface.
writing the bug number....
Quoted 20 lines
Quoted 10 lines
- File is write-only
disable_workaround:
- provide the bit number (of the workaround) to disable the workaround
- File is write-onlyThe split enable/disable is to avoid the read-modify-write issue.
Am I getting this right?
Quoted 9 lines
I understand the value of this proposition. But, I feel, it is beyond the scope of the patch series to workaround the PMU bug. Initially, we had talked about not
even providing the sysfs file. Now, the series adjusts the workaround on boot. The series is restructured so that the sysfs patch is the last one and is totally optional. I think we should implement the proposed scheme but we should not delay the review and merge of the rest of the patch series for this. But I can propose a separate patch series to implement the proposed scheme.
Quoted 6 lines
Right, IMHO, we can always add sysfs structure later, when its design is sane. What we should absolutely avoid is exposing something to userspace now and then try to hide it/replace it with something else and break userspace, which, as we all know, is a no-no, punishable by Linus coming to your house with a bat.
I am okay with this approach.
Quoted 8 lines
:-) :-)
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Borislav Petkov
maintainerRe: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 10 lines · Stephane Eranian
Does it need to bit a bitmask, as opposed to just a bug number (which could be implemented as a bitmask)?
Quoted 6 lines
Quoted 2 lines
enable_workaround:
- provide the bit number (of the workaround) to enable the workaroundRight, writing the bit number could be part of the description message above - just so that users know how to control the interface.
writing the bug number....
Ah, ok, I see what you mean. I guess we can do increasing bug numbers. The mapping internally to bits in bitmasks or whatever fancy thing we do should remain hidden. So I'd guess assigning bug numbers to the bugs should be the only thing that's stable and user-visible...
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
In reply to Borislav PetkovQuoted 12 lines · Borislav Petkov
Quoted 11 lines · Stephane Eranian
From: Maria Dimakopoulou <[email protected]>
This patch adds a sysfs entry:
/sys/devices/cpu/ht_bug_workaroundto activate/deactivate the PMU HT bug workaround.
To activate (activated by default):
# echo 1 > /sys/devices/cpu/ht_bug_workaround
Quoted 7 lines
Quoted 2 lines
To deactivate:
# echo 0 > /sys/devices/cpu/ht_bug_workaroundIf I put my simple-user hat and stare at this sysfs node, I'm not really becoming any smarter from looking at the name. HT bug? A hyper-threading bug?? I see the user forums going nuts already.
OK. We can call it perf_pmu_ht_bug_workaround to make this more explicit.
The other thing we will do in V4 is to make the file disappear if HT is off because
the problem does not exist in that case.
Quoted 49 lines
Instead of adding a sysfs node per CPU bug, I'm wondering whether adding a
/sys/devices/system/cpu/bugsfile which gets a mask of bits to enable and disable workarounds would be much cleaner.
x86 guys, what do you guys think?
Such a scheme should be much more easily extensible in the future in case we want to add another workaround toggle.
The hierarchy is not optimal either as it should be under "perf"-something but I don't think we have a perf sysfs node...
Quoted 6 lines
Results effective only once there is no more active events.
Reviewed-by Stephane Eranian <[email protected]>Signed-off-by Maria Dimakopoulou <[email protected]>---
...
arch/x86/kernel/cpu/perf_event.c static ssize_t set_attr_rdpmc(struct device *cdev, · line 1931
Quoted 7 lines
static
DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);arch/x86/kernel/cpu/perf_event.c +3
-0+static DEVICE_ATTR(ht_bug_workaround, S_IRUSR | S_IWUSR, get_attr_xsu, + set_attr_xsu);static struct attribute *x86_pmu_attrs[] = { &dev_attr_rdpmc.attr, + &dev_attr_ht_bug_workaround.attr,You should be adding this dynamically, only when running on Intel, i.e.
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) /* add bug_workaround attr */For an example, see
amd_l3_attrs()inarch/x86/kernel/cpu/intel_cacheinfo.cThanks.
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Borislav Petkov
maintainerRe: [PATCH v3 13/13] perf/x86: add syfs entry to disable HT bug workaround
Quoted 2 lines · Maria Dimakopoulou
OK. We can call it
perf_pmu_ht_bug_workaroundto make this more explicit.
I think you should consider adding a more generic scheme from the get-go, as Thomas suggested instead of a specific file. We need this hammered out properly before it gets exposed as it is user-visible and once it is out there, there's no changing.
And this is not the only CPU bug we'll be implementing workaround for in the future so a generic scheme is the right way to go IMO.
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--