perf/x86: implement HT counter corruption workaround
Subsystems (2)
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.
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 (3):
perf,x86: rename er_flags to flags
pref/x86: vectorize cpuc->kfree_on_online
perf/x86: fix intel_get_event_constraints() for dynamic constraints
arch/x86/kernel/cpu/perf_event.c | 81 ++++- arch/x86/kernel/cpu/perf_event.h | 76 ++++- arch/x86/kernel/cpu/perf_event_amd.c | 3 +- arch/x86/kernel/cpu/perf_event_intel.c | 456 +++++++++++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel_ds.c | 40 +-- 5 files changed, 586 insertions(+), 70 deletions(-)
Signature · 1 line
1.7.9.5
PATCH 1/9 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
@@ -463,7 +463,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)
@@ -480,8 +480,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
@@ -1455,7 +1455,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 )
@@ -2001,7 +2001,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;
@@ -2397,7 +2397,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 ;
@@ -2415,7 +2415,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;
@@ -2447,8 +2447,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;
@@ -2478,8 +2478,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;
@@ -2507,8 +2507,8 @@ __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_snb_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.7.9.5
PATCH 2/9 pref/x86: vectorize cpuc->kfree_on_online
In reply to Stephane EranianMake the cpuc->kfree_on_online a vector to accomodate 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
@@ -1321,11 +1321,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 ;
@@ -1338,7 +1339,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
@@ -121,6 +121,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
@@ -183,7 +189,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
@@ -2002,12 +2002,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.7.9.5
PATCH 3/9 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 | 8 ++++++++ 2 files changed, 17 insertions(+)
arch/x86/kernel/cpu/perf_event.c +9 -0
@@ -733,6 +733,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]);
@@ -779,6 +782,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]); } }/*
@@ -799,6 +804,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 +8 -0
@@ -409,6 +409,14 @@ 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.7.9.5
PATCH 4/9 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 | 40 ++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel.c | 63 +++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 9 deletions(-)
arch/x86/kernel/cpu/perf_event.h +36 -4
@@ -65,10 +65,11 @@ struct event_constraint {/* * struct hw_perf_event.flags flags */ -#define PERF_X86_EVENT_PEBS_LDLAT 0x1/* ld+ldlat data address sampling */ -#define PERF_X86_EVENT_PEBS_ST 0x2/* st data address sampling */ -#define PERF_X86_EVENT_PEBS_ST_HSW 0x4/* haswell style st data sampling */ -#define PERF_X86_EVENT_COMMITTED 0x8/* event passed commit_txn */ +#define PERF_X86_EVENT_PEBS_LDLAT 0x01/* ld+ldlat data address sampling */ +#define PERF_X86_EVENT_PEBS_ST 0x02/* st data address sampling */ +#define PERF_X86_EVENT_PEBS_ST_HSW 0x04/* haswell style st data sampling */ +#define PERF_X86_EVENT_COMMITTED 0x08/* event passed commit_txn */ +#define PERF_X86_EVENT_EXCL 0x10/* HT exclusivity on counter */ struct amd_nb {int nb_id;/* NorthBridge id */
@@ -119,6 +120,27 @@ 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; +unsigned long lock_flags; + +struct intel_excl_states states[2 ]; + +int refcnt;/* per-core: #HT threads */ +unsigned core_id;/* per-core: core id */ +}; +#define MAX_LBR_ENTRIES 16enum {
@@ -181,6 +203,11 @@ struct cpu_hw_events {* used on Intel NHM/WSM/SNB */ struct intel_shared_regs *shared_regs; +/* +* manage exclusive counter access between hyperthread +*/ +struct intel_excl_cntrs *excl_cntrs; +int excl_thread_id;/* 0 or 1 */ /* * AMD specific bits
@@ -204,6 +231,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
@@ -499,6 +530,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 +58 -5
92 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Peter Zijlstra
maintainerRe: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
Quoted 49 lines · Stephane Eranian
From: Maria Dimakopoulou <[email protected]>
This patch adds a new
shared_regsstyle 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.Reviewed-by Stephane Eranian <[email protected]>Signed-off-by Maria Dimakopoulou <[email protected]>--- arch/x86/kernel/cpu/perf_event.h | 40 ++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel.c | 63 +++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 9 deletions(-)arch/x86/kernel/cpu/perf_event.h +15
-4@@ -65,10 +65,11 @@ struct event_constraint {/* * struct hw_perf_event.flags flags */ -#define PERF_X86_EVENT_PEBS_LDLAT 0x1/* ld+ldlat data address sampling */ -#define PERF_X86_EVENT_PEBS_ST 0x2/* st data address sampling */ -#define PERF_X86_EVENT_PEBS_ST_HSW 0x4/* haswell style st data sampling */ -#define PERF_X86_EVENT_COMMITTED 0x8/* event passed commit_txn */ +#define PERF_X86_EVENT_PEBS_LDLAT 0x01/* ld+ldlat data address sampling */ +#define PERF_X86_EVENT_PEBS_ST 0x02/* st data address sampling */ +#define PERF_X86_EVENT_PEBS_ST_HSW 0x04/* haswell style st data sampling */ +#define PERF_X86_EVENT_COMMITTED 0x08/* event passed commit_txn */ +#define PERF_X86_EVENT_EXCL 0x10/* HT exclusivity on counter */ struct amd_nb {int nb_id;/* NorthBridge id */ @@ -119,6 +120,27 @@ 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 ]; +};
arch/x86/kernel/cpu/perf_event.h struct intel_shared_regs { · line 142
Quoted 10 lines
arch/x86/kernel/cpu/perf_event.h +10
-0+ +struct intel_excl_cntrs { +spinlock_t lock; +unsigned long lock_flags; + +struct intel_excl_states states[2 ]; + +int refcnt;/* per-core: #HT threads */ +unsigned core_id;/* per-core: core id */ +};
This must be a raw_spin_lock_t, its taken from pmu::add() which is called under perf_event_context::lock, which is raw_spinlock_t, as its taken under rq::lock, which too is raw_spinlock_t.
I should really get around to fixing these errors and include the lockdep infrastructure for this.
Re: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
Quoted 56 lines · Peter Zijlstra
Quoted 55 lines · Stephane Eranian
From: Maria Dimakopoulou <[email protected]>
This patch adds a new
shared_regsstyle 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.Reviewed-by Stephane Eranian <[email protected]>Signed-off-by Maria Dimakopoulou <[email protected]>--- arch/x86/kernel/cpu/perf_event.h | 40 ++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel.c | 63 +++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 9 deletions(-)arch/x86/kernel/cpu/perf_event.h +21
-4@@ -65,10 +65,11 @@ struct event_constraint {/* * struct hw_perf_event.flags flags */ -#define PERF_X86_EVENT_PEBS_LDLAT 0x1/* ld+ldlat data address sampling */ -#define PERF_X86_EVENT_PEBS_ST 0x2/* st data address sampling */ -#define PERF_X86_EVENT_PEBS_ST_HSW 0x4/* haswell style st data sampling */ -#define PERF_X86_EVENT_COMMITTED 0x8/* event passed commit_txn */ +#define PERF_X86_EVENT_PEBS_LDLAT 0x01/* ld+ldlat data address sampling */ +#define PERF_X86_EVENT_PEBS_ST 0x02/* st data address sampling */ +#define PERF_X86_EVENT_PEBS_ST_HSW 0x04/* haswell style st data sampling */ +#define PERF_X86_EVENT_COMMITTED 0x08/* event passed commit_txn */ +#define PERF_X86_EVENT_EXCL 0x10/* HT exclusivity on counter */ struct amd_nb {int nb_id;/* NorthBridge id */ @@ -119,6 +120,27 @@ 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; +unsigned long lock_flags; + +struct intel_excl_states states[2 ];
Quoted 9 lines
arch/x86/kernel/cpu/perf_event.h struct intel_shared_regs { · line 142
Quoted 4 lines
arch/x86/kernel/cpu/perf_event.h +4
-0+ +int refcnt;/* per-core: #HT threads */ +unsigned core_id;/* per-core: core id */ +};This must be a
raw_spin_lock_t, its taken frompmu::add()which is called underperf_event_context::lock, which israw_spinlock_t, as its taken underrq::lock, which too israw_spinlock_t.
Will fix this in V2.
Quoted 2 lines
I should really get around to fixing these errors and include the lockdep infrastructure for this.
Peter Zijlstra
maintainerRe: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
In reply to Stephane Eranianarch/x86/kernel/cpu/perf_event.h do { \ · line 533
Quoted 5 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event.h +1
-0@@ -499,6 +530,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 */
the EXLC thing is HT specific too, right? How about HT_EXCL or so?
Re: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
This is to indicate that the PMU needs to setup the shared state struct which is called excl_cntrs. That struct is allocated for all CPUs at first, and then half of them are destroyed and their CPUs made to point to their siblings struct.
So yes. EXCL is really related to HT.
It could be called HT_EXCL.
Will fix in V2.
Quoted 10 lines · Peter Zijlstra
arch/x86/kernel/cpu/perf_event.h do { \ · line 533
Quoted 5 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event.h +1
-0@@ -499,6 +530,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 */ the EXLC thing is HT specific too, right? How about
HT_EXCLor so?
Peter Zijlstra
maintainerRe: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
In reply to Stephane EranianQuoted 11 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +7
-0@@ -2020,12 +2050,29 @@ static void intel_pmu_cpu_starting(int cpu)if (x86_pmu.lbr_sel_map) cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR ]; + +if (x86_pmu.flags &PMU_FL_EXCL_CNTRS ) { +for_each_cpu (i,topology_thread_cpumask (cpu)) { +struct intel_excl_cntrs *c; + + c =per_cpu (cpu_hw_events, i).excl_cntrs; +if (c && c->core_id == core_id) {
arch/x86/kernel/cpu/perf_event_intel.c static void intel_pmu_cpu_starting(int cpu) · line 2069
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +9
-0+ cpuc->kfree_on_online[1 ] = cpuc->excl_cntrs; + cpuc->excl_cntrs = c; + cpuc->excl_thread_id =1 ; +break ; + } + } + cpuc->excl_cntrs->core_id = core_id; + cpuc->excl_cntrs->refcnt++; + } }
This hard assumes theres only ever 2 threads, which is true and I suppose more in arch/x86 will come apart the moment Intel makes a chip with more, still, do we have topology_thread_id() or so to cure this?
Re: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
Quoted 3 lines
This hard assumes theres only ever 2 threads, which is true and I suppose more in
arch/x86will come apart the moment Intel makes a chip with more, still, do we havetopology_thread_id()or so to cure this?
Xeon Phi already has 4 threads today.
-Andi
Signature · 1 line
[email protected] -- Speaking for myself only
Re: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
Quoted 7 lines · Andi Kleen
Quoted 3 lines
This hard assumes theres only ever 2 threads, which is true and I suppose more in
arch/x86will come apart the moment Intel makes a chip with more, still, do we havetopology_thread_id()or so to cure this?Xeon Phi already has 4 threads today.
Yes, but it does not have that bug (hopefully). This code is just for the impacted processors.
Quoted 4 lines
-Andi
--
[email protected] -- Speaking for myself only
Re: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
In reply to Peter ZijlstraQuoted 18 lines · Peter Zijlstra
Quoted 17 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +13
-0@@ -2020,12 +2050,29 @@ static void intel_pmu_cpu_starting(int cpu)if (x86_pmu.lbr_sel_map) cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR ]; + +if (x86_pmu.flags &PMU_FL_EXCL_CNTRS ) { +for_each_cpu (i,topology_thread_cpumask (cpu)) { +struct intel_excl_cntrs *c; + + c =per_cpu (cpu_hw_events, i).excl_cntrs; +if (c && c->core_id == core_id) { + cpuc->kfree_on_online[1 ] = cpuc->excl_cntrs; + cpuc->excl_cntrs = c; + cpuc->excl_thread_id =1 ; +break ; + } + }
Quoted 8 lines
arch/x86/kernel/cpu/perf_event_intel.c static void intel_pmu_cpu_starting(int cpu) · line 2069
Quoted 4 lines
arch/x86/kernel/cpu/perf_event_intel.c +3
-0+ cpuc->excl_cntrs->core_id = core_id; + cpuc->excl_cntrs->refcnt++; + } }This hard assumes theres only ever 2 threads, which is true and I suppose more in
arch/x86will come apart the moment Intel makes a chip with more, still, do we havetopology_thread_id()or so to cure this?
I assume your comment is relative to kfree_on_online[].
This code is specific to the HT bug, so yes, it assumes 2 threads and that only one entry of the two excl_cntrs structs needs to be freed. Doing otherwise, would require a list and will never be used to its full potential.
Peter Zijlstra
maintainerRe: [PATCH 4/9] perf/x86: add cross-HT counter exclusion infrastructure
Quoted 28 lines · Stephane Eranian
Quoted 18 lines · Peter Zijlstra
Quoted 17 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +13
-0@@ -2020,12 +2050,29 @@ static void intel_pmu_cpu_starting(int cpu)if (x86_pmu.lbr_sel_map) cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR ]; + +if (x86_pmu.flags &PMU_FL_EXCL_CNTRS ) { +for_each_cpu (i,topology_thread_cpumask (cpu)) { +struct intel_excl_cntrs *c; + + c =per_cpu (cpu_hw_events, i).excl_cntrs; +if (c && c->core_id == core_id) { + cpuc->kfree_on_online[1 ] = cpuc->excl_cntrs; + cpuc->excl_cntrs = c; + cpuc->excl_thread_id =1 ; +break ; + } + }Quoted 8 lines
arch/x86/kernel/cpu/perf_event_intel.c static void intel_pmu_cpu_starting(int cpu) · line 2069
Quoted 4 lines
arch/x86/kernel/cpu/perf_event_intel.c +3
-0+ cpuc->excl_cntrs->core_id = core_id; + cpuc->excl_cntrs->refcnt++; + } }This hard assumes theres only ever 2 threads, which is true and I suppose more in
arch/x86will come apart the moment Intel makes a chip with more, still, do we havetopology_thread_id()or so to cure this?
Quoted 5 lines
I assume your comment is relative to kfree_on_online[].
This code is specific to the HT bug, so yes, it assumes 2 threads and that only one entry of the twoexcl_cntrsstructs needs to be freed. Doing otherwise, would require a list and will never be used to its full potential.
That and ->excl_thread_id = 1, I was thinking that if we'd somehow have 4 threads, some of them need to have = [23] in there.
PATCH 5/9 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 | 311 +++++++++++++++++++++++++++++++- 3 files changed, 335 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/perf_event.c +19 -12
@@ -728,7 +728,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 );
@@ -771,14 +771,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 ;
@@ -786,11 +792,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];/*
@@ -800,6 +804,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); }
@@ -808,7 +815,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
@@ -70,6 +70,7 @@ struct event_constraint {#define PERF_X86_EVENT_PEBS_ST_HSW 0x04/* haswell style st data sampling */ #define PERF_X86_EVENT_COMMITTED 0x08/* event passed commit_txn */ #define PERF_X86_EVENT_EXCL 0x10/* HT exclusivity on counter */ +#define PERF_X86_EVENT_DYNAMIC 0x20/* dynamic alloc'd constraint */ struct amd_nb {int nb_id;/* NorthBridge id */
@@ -129,6 +130,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 {
@@ -288,6 +290,10 @@ struct cpu_hw_events {#define INTEL_UEVENT_CONSTRAINT (c, n) \ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) +#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, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
arch/x86/kernel/cpu/perf_event_intel.c +310 -1
336 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 22 lines · Stephane Eranian
static void
arch/x86/kernel/cpu/perf_event_intel.c +19
-0+intel_start_scheduling(struct cpu_hw_events *cpuc) +{ +/* +* lock shared state until we are done scheduling +* in stop_event_scheduling() +* makes scheduling appear as a transaction +*/ +spin_lock_irqsave (&excl_cntrs->lock, excl_cntrs->lock_flags); + +/* +* save initial state of sibling thread +*/ +memcpy (xlo->init_state, xlo->state,sizeof (xlo->init_state)); +} + +static void +intel_stop_scheduling (struct cpu_hw_events *cpuc) +{ +/*
arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1724
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* make new sibling thread state visible +*/ +memcpy (xlo->state, xlo->init_state,sizeof (xlo->state)); + + xl->sched_started = false; +/* +* release shared state lock (lock acquire in intel_start_scheduling()) +*/ +spin_unlock_irqrestore (&excl_cntrs->lock, excl_cntrs->lock_flags); +}
Do you really need the irqsave/irqrestore? From what I can tell this is always called under perf_event_context::lock and that is already an IRQ-safe lock, so interrupts should always be disabled here.
Also, it looks like xl->state is the effective state, and ->init_state is the work state? Is init the right name for this?
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
In reply to Stephane EranianQuoted 17 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +17
-0+static void intel_commit_scheduling (struct cpu_hw_events *cpuc, +struct perf_event *event,int cntr) +{ +struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs; +struct event_constraint *c = event->hw.constraint; +struct intel_excl_states *xlo, *xl; +int tid = cpuc->excl_thread_id; +int o_tid =1 - tid; +int is_excl; + +if (cpuc->is_fake || !c) +return ; + + is_excl = c->flags &PERF_X86_EVENT_EXCL ; + +if (!(c->flags &PERF_X86_EVENT_DYNAMIC )) +return ;
arch/x86/kernel/cpu/perf_event_intel.c intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc, · line 1967
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+ +WARN_ON_ONCE (!excl_cntrs); + +if (!excl_cntrs) +return ; + + xl = &excl_cntrs->states[tid]; + xlo = &excl_cntrs->states[o_tid]; + +WARN_ON_ONCE (!spin_is_locked (&excl_cntrs->lock));
Use:
lockdep_assert_held(&excl_cntrs->lock);
It also checks to see the current context is actually the lock holder, and it doesn't generate any code when !lockdep.
Quoted 8 lines
arch/x86/kernel/cpu/perf_event_intel.c +7
-0+ +if (cntr >=0 ) { +if (is_excl) + xlo->init_state[cntr] =INTEL_EXCL_EXCLUSIVE ; +else + xlo->init_state[cntr] =INTEL_EXCL_SHARED ; + } }
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
In reply to Stephane EranianQuoted 5 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +4
-0+static struct event_constraint * +intel_get_excl_constraints (struct cpu_hw_events *cpuc,struct perf_event *event, +struct event_constraint *c) +{
arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1776
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+if (!(c->flags &PERF_X86_EVENT_DYNAMIC )) { + +/* +* in case we fail, we assume no counter +* is supported to be on the safe side +*/ + cx =kmalloc (sizeof (*cx),GFP_KERNEL ); +if (!cx) +return &emptyconstraint; +
Ok, so forgive me if I'm wrong, but the way we get here is through:
x86_schedule_event()
->start_scheduling()
spin_lock()
->get_event_constraints()
intel_get_excl_constraints()
kmalloc(.gfp=GFP_KERNEL)
How can that ever work?
Re: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Are you saying it is illegal to call kmalloc() from this context?
kmalloc is needed because we need to allocate a new constraint struct since the static constraint cannot be modified.
Worst case we can statically allocate a second
constraint struct in the event struct.
Quoted 28 lines · Peter Zijlstra
Quoted 5 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +4
-0+static struct event_constraint * +intel_get_excl_constraints (struct cpu_hw_events *cpuc,struct perf_event *event, +struct event_constraint *c) +{arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1776
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+if (!(c->flags &PERF_X86_EVENT_DYNAMIC )) { + +/* +* in case we fail, we assume no counter +* is supported to be on the safe side +*/ + cx =kmalloc (sizeof (*cx),GFP_KERNEL ); +if (!cx) +return &emptyconstraint; +Ok, so forgive me if I'm wrong, but the way we get here is through:
x86_schedule_event()
->start_scheduling()spin_lock()->get_event_constraints()
intel_get_excl_constraints()
kmalloc(.gfp=GFP_KERNEL)How can that ever work?
Borislav Petkov
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 9 lines · Maria Dimakopoulou
Are you saying it is illegal to call
kmalloc()from this context?kmalloc is needed because we need to allocate a new constraint struct since the static constraint cannot be modified.
Worst case we can statically allocate a second
constraint struct in the event struct.
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?
Please do not top-post.
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
In reply to Maria DimakopoulouQuoted 28 lines · Maria Dimakopoulou
Quoted 27 lines · Peter Zijlstra
Quoted 5 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +4
-0+static struct event_constraint * +intel_get_excl_constraints (struct cpu_hw_events *cpuc,struct perf_event *event, +struct event_constraint *c) +{arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1776
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+if (!(c->flags &PERF_X86_EVENT_DYNAMIC )) { + +/* +* in case we fail, we assume no counter +* is supported to be on the safe side +*/ + cx =kmalloc (sizeof (*cx),GFP_KERNEL ); +if (!cx) +return &emptyconstraint; +Ok, so forgive me if I'm wrong, but the way we get here is through:
x86_schedule_event()
->start_scheduling()spin_lock()->get_event_constraints()
intel_get_excl_constraints()
kmalloc(.gfp=GFP_KERNEL)
Quoted 4 lines
Quoted 1 line
How can that ever work?
Are you saying it is illegal to call
kmalloc()from this context?
Nobody will come and arrest you for it, so no. Broken though. GFP_KERNEL will attempt to sleep to wait for reclaim, and you're holding a spinlock.
Quoted 6 lines
kmalloc is needed because we need to allocate a new constraint struct since the static constraint cannot be modified.
Worst case we can statically allocate a second
constraint struct in the event struct.
Nah, since you will need at most one constraint per counter, you could preallocate num_counter constraints for each cpu.
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 7 lines · Peter Zijlstra
Quoted 7 lines
Quoted 7 lines
x86_schedule_event()
->start_scheduling()spin_lock()->get_event_constraints()
intel_get_excl_constraints()
kmalloc(.gfp=GFP_KERNEL)
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
How can that ever work?
Are you saying it is illegal to call
kmalloc()from this context?Nobody will come and arrest you for it, so no. Broken though.
GFP_KERNELwill attempt to sleep to wait for reclaim, and you're holding a spinlock.
Furthermore, even GFP_ATOMIC shouldn't be used because these are/should be raw_spinlocks and the zone->lock is a regular spinlock.
So please look into the preallocation thing.
Re: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 8 lines · Peter Zijlstra
Quoted 7 lines · Peter Zijlstra
Quoted 7 lines
Quoted 7 lines
x86_schedule_event()
->start_scheduling()spin_lock()->get_event_constraints()
intel_get_excl_constraints()
kmalloc(.gfp=GFP_KERNEL)
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
How can that ever work?
Are you saying it is illegal to call
kmalloc()from this context?Nobody will come and arrest you for it, so no. Broken though.
GFP_KERNELwill attempt to sleep to wait for reclaim, and you're holding a spinlock.
Ok, got it.
Quoted 5 lines
Furthermore, even
GFP_ATOMICshouldn't be used because these are/should beraw_spinlocksand thezone->lockis a regular spinlock.So please look into the preallocation thing.
We will preallocate.
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
In reply to Stephane EranianQuoted 20 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +20
-0+ +/* +* Modify static constraint with current dynamic +* state of thread +* +* EXCLUSIVE: sibling counter measuring exclusive event +* SHARED : sibling counter measuring non-exclusive event +* UNUSED : sibling counter unused +*/ +for_each_set_bit (i, cx->idxmsk,X86_PMC_IDX_MAX ) { +/* +* exclusive event in sibling counter +* our corresponding counter cannot be used +* regardless of our event +*/ +if (xl->state[i] ==INTEL_EXCL_EXCLUSIVE ) +__clear_bit (i, cx->idxmsk); +/* +* if measuring an exclusive event, sibling +* measuring non-exclusive, then counter cannot
arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1825
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* be used +*/ +if (is_excl && xl->state[i] ==INTEL_EXCL_SHARED ) +__clear_bit (i, cx->idxmsk); + } + +/* +* recompute actual bit weight for scheduling algorithm +*/ + cx->weight =hweight64 (cx->idxmsk64);
So I think we talked about this a bit; what happens if CPU0 (taking your 4 core HSW-client) is first to program its counters and takes all 4 in exclusive mode?
Then there's none left for CPU4.
Did I miss where we avoid that problem, or is that an actual issue?
Re: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 36 lines · Peter Zijlstra
Quoted 20 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +20
-0+ +/* +* Modify static constraint with current dynamic +* state of thread +* +* EXCLUSIVE: sibling counter measuring exclusive event +* SHARED : sibling counter measuring non-exclusive event +* UNUSED : sibling counter unused +*/ +for_each_set_bit (i, cx->idxmsk,X86_PMC_IDX_MAX ) { +/* +* exclusive event in sibling counter +* our corresponding counter cannot be used +* regardless of our event +*/ +if (xl->state[i] ==INTEL_EXCL_EXCLUSIVE ) +__clear_bit (i, cx->idxmsk); +/* +* if measuring an exclusive event, sibling +* measuring non-exclusive, then counter cannot arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1825
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* be used +*/ +if (is_excl && xl->state[i] ==INTEL_EXCL_SHARED ) +__clear_bit (i, cx->idxmsk); + } + +/* +* recompute actual bit weight for scheduling algorithm +*/ + cx->weight =hweight64 (cx->idxmsk64);So I think we talked about this a bit; what happens if CPU0 (taking your 4 core HSW-client) is first to program its counters and takes all 4 in exclusive mode?
Quoted 3 lines
Then there's none left for CPU4.
Did I miss where we avoid that problem, or is that an actual issue?
Yes, this patch series does not address this problem yet. It will be in a second series.
Don't have a good solution yet.
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 37 lines · Stephane Eranian
Quoted 36 lines · Peter Zijlstra
Quoted 20 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +20
-0+ +/* +* Modify static constraint with current dynamic +* state of thread +* +* EXCLUSIVE: sibling counter measuring exclusive event +* SHARED : sibling counter measuring non-exclusive event +* UNUSED : sibling counter unused +*/ +for_each_set_bit (i, cx->idxmsk,X86_PMC_IDX_MAX ) { +/* +* exclusive event in sibling counter +* our corresponding counter cannot be used +* regardless of our event +*/ +if (xl->state[i] ==INTEL_EXCL_EXCLUSIVE ) +__clear_bit (i, cx->idxmsk); +/* +* if measuring an exclusive event, sibling +* measuring non-exclusive, then counter cannot arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1825
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* be used +*/ +if (is_excl && xl->state[i] ==INTEL_EXCL_SHARED ) +__clear_bit (i, cx->idxmsk); + } + +/* +* recompute actual bit weight for scheduling algorithm +*/ + cx->weight =hweight64 (cx->idxmsk64);So I think we talked about this a bit; what happens if CPU0 (taking your 4 core HSW-client) is first to program its counters and takes all 4 in exclusive mode?
Quoted 7 lines
Quoted 3 lines
Then there's none left for CPU4.
Did I miss where we avoid that problem, or is that an actual issue?
Yes, this patch series does not address this problem yet. It will be in a second series.
Don't have a good solution yet.
We could limit each cpu to num_counters/2 exclusive slots. That'll still be painful with some constrained events I imagine, but in general that should 'work' I suppose.
Re: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 42 lines · Peter Zijlstra
Quoted 41 lines · Stephane Eranian
Quoted 39 lines · Peter Zijlstra
Quoted 20 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +20
-0+ +/* +* Modify static constraint with current dynamic +* state of thread +* +* EXCLUSIVE: sibling counter measuring exclusive event +* SHARED : sibling counter measuring non-exclusive event +* UNUSED : sibling counter unused +*/ +for_each_set_bit (i, cx->idxmsk,X86_PMC_IDX_MAX ) { +/* +* exclusive event in sibling counter +* our corresponding counter cannot be used +* regardless of our event +*/ +if (xl->state[i] ==INTEL_EXCL_EXCLUSIVE ) +__clear_bit (i, cx->idxmsk); +/* +* if measuring an exclusive event, sibling +* measuring non-exclusive, then counter cannot arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1825
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* be used +*/ +if (is_excl && xl->state[i] ==INTEL_EXCL_SHARED ) +__clear_bit (i, cx->idxmsk); + } + +/* +* recompute actual bit weight for scheduling algorithm +*/ + cx->weight =hweight64 (cx->idxmsk64);So I think we talked about this a bit; what happens if CPU0 (taking your 4 core HSW-client) is first to program its counters and takes all 4 in exclusive mode?
Then there's none left for CPU4.
Did I miss where we avoid that problem, or is that an actual issue?
Quoted 7 lines
Quoted 3 lines
Yes, this patch series does not address this problem yet. It will be in a second series.
Don't have a good solution yet.We could limit each cpu to num_counters/2 exclusive slots. That'll still be painful with some constrained events I imagine, but in general that should 'work' I suppose.
That is probably the easiest solution, just modify the dynamic constraint mask some more. Have not yet tried it.
The repatriation of the leaked count is not so easy either. Need to IPI the other HT. There may be some restrictions as to when we can safely do this.
Peter Zijlstra
maintainerRe: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
Quoted 8 lines · Stephane Eranian
Quoted 3 lines · Peter Zijlstra
We could limit each cpu to num_counters/2 exclusive slots. That'll still be painful with some constrained events I imagine, but in general that should 'work' I suppose.
That is probably the easiest solution, just modify the dynamic constraint mask some more. Have not yet tried it.
Right, see what happens :-)
Quoted 3 lines
The repatriation of the leaked count is not so easy either. Need to IPI the other HT. There may be some restrictions as to when we can safely do this.
Yes, that'll be 'interesting'. You typically cannot do things like smp_function_call() from IRQ/NMI context. Which leaves you to asynchonous IPIs.
I suppose the easiest way is to simply push the count out to the right event when you reprogram the sibling. And maybe kick it every so often to force do this just in case the PMU doesn't get reprogrammed a lot.
Still tricky.
Re: [PATCH 5/9] perf/x86: implement cross-HT corruption bug workaround
In reply to Peter ZijlstraQuoted 42 lines · Peter Zijlstra
Quoted 41 lines · Stephane Eranian
Quoted 39 lines · Peter Zijlstra
Quoted 20 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event_intel.c +20
-0+ +/* +* Modify static constraint with current dynamic +* state of thread +* +* EXCLUSIVE: sibling counter measuring exclusive event +* SHARED : sibling counter measuring non-exclusive event +* UNUSED : sibling counter unused +*/ +for_each_set_bit (i, cx->idxmsk,X86_PMC_IDX_MAX ) { +/* +* exclusive event in sibling counter +* our corresponding counter cannot be used +* regardless of our event +*/ +if (xl->state[i] ==INTEL_EXCL_EXCLUSIVE ) +__clear_bit (i, cx->idxmsk); +/* +* if measuring an exclusive event, sibling +* measuring non-exclusive, then counter cannot arch/x86/kernel/cpu/perf_event_intel.c intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event · line 1825
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel.c +10
-0+* be used +*/ +if (is_excl && xl->state[i] ==INTEL_EXCL_SHARED ) +__clear_bit (i, cx->idxmsk); + } + +/* +* recompute actual bit weight for scheduling algorithm +*/ + cx->weight =hweight64 (cx->idxmsk64);So I think we talked about this a bit; what happens if CPU0 (taking your 4 core HSW-client) is first to program its counters and takes all 4 in exclusive mode?
Then there's none left for CPU4.
Did I miss where we avoid that problem, or is that an actual issue?
Quoted 7 lines
Quoted 3 lines
Yes, this patch series does not address this problem yet. It will be in a second series.
Don't have a good solution yet.We could limit each cpu to num_counters/2 exclusive slots. That'll still be painful with some constrained events I imagine, but in general that should 'work' I suppose.
Ok, tried this. It avoids the problems and just requires a 3 line patch. So we could go with that for now. It would avoid total starvation.
PATCH 6/9 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 };
@@ -2584,6 +2593,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" )
@@ -2796,6 +2826,7 @@ __init int intel_pmu_init(void)case 42 :/* SandyBridge */ case 45 :/* SandyBridge, "Romely-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,
@@ -2810,6 +2841,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 ;
@@ -2827,6 +2860,7 @@ __init int intel_pmu_init(void)break ;case 58 :/* IvyBridge */ case 62 :/* IvyBridge EP */ +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,
@@ -2860,6 +2894,7 @@ __init int intel_pmu_init(void)case 71 :case 63 :case 69 : +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.7.9.5
PATCH 7/9 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_intel_ds.c | 40 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_ds.c +20 -20
@@ -630,10 +630,10 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {INTEL_EVENT_CONSTRAINT (0xc5 ,0xf ),/* BR_MISP_RETIRED.* */ INTEL_PLD_CONSTRAINT (0x01cd ,0x8 ),/* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ -INTEL_EVENT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ +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.* */ INTEL_UEVENT_CONSTRAINT (0x02d4 ,0xf ),/* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */ EVENT_CONSTRAINT_END };
@@ -646,10 +646,10 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {INTEL_EVENT_CONSTRAINT (0xc5 ,0xf ),/* BR_MISP_RETIRED.* */ INTEL_PLD_CONSTRAINT (0x01cd ,0x8 ),/* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ INTEL_PST_CONSTRAINT (0x02cd ,0x8 ),/* MEM_TRANS_RETIRED.PRECISE_STORES */ -INTEL_EVENT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ -INTEL_EVENT_CONSTRAINT (0xd3 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ +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.* */ EVENT_CONSTRAINT_END };
@@ -665,24 +665,24 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {/* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ INTEL_UEVENT_CONSTRAINT (0x11d0 ,0xf ),/* MEM_UOPS_RETIRED.STLB_MISS_STORES */ -INTEL_UEVENT_CONSTRAINT (0x12d0 ,0xf ), -INTEL_UEVENT_CONSTRAINT (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ -INTEL_UEVENT_CONSTRAINT (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ +INTEL_EXCLUEVT_CONSTRAINT (0x12d0 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x21d0 ,0xf ),/* MEM_UOPS_RETIRED.LOCK_LOADS */ +INTEL_EXCLUEVT_CONSTRAINT (0x41d0 ,0xf ),/* MEM_UOPS_RETIRED.SPLIT_LOADS */ /* MEM_UOPS_RETIRED.SPLIT_STORES */ -INTEL_UEVENT_CONSTRAINT (0x42d0 ,0xf ), -INTEL_UEVENT_CONSTRAINT (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ +INTEL_EXCLUEVT_CONSTRAINT (0x42d0 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x81d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_LOADS */ INTEL_PST_HSW_CONSTRAINT (0x82d0 ,0xf ),/* MEM_UOPS_RETIRED.ALL_STORES */ -INTEL_UEVENT_CONSTRAINT (0x01d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L1_HIT */ -INTEL_UEVENT_CONSTRAINT (0x02d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L2_HIT */ -INTEL_UEVENT_CONSTRAINT (0x04d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L3_HIT */ +INTEL_EXCLUEVT_CONSTRAINT (0x01d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L1_HIT */ +INTEL_EXCLUEVT_CONSTRAINT (0x02d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L2_HIT */ +INTEL_EXCLUEVT_CONSTRAINT (0x04d1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.L3_HIT */ /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */ -INTEL_UEVENT_CONSTRAINT (0x40d1 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x40d1 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */ -INTEL_UEVENT_CONSTRAINT (0x01d2 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x01d2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */ -INTEL_UEVENT_CONSTRAINT (0x02d2 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x02d2 ,0xf ),/* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */ -INTEL_UEVENT_CONSTRAINT (0x01d3 ,0xf ), +INTEL_EXCLUEVT_CONSTRAINT (0x01d3 ,0xf ),INTEL_UEVENT_CONSTRAINT (0x04c8 ,0xf ),/* HLE_RETIRED.Abort */ INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */
Signature · 1 line
1.7.9.5
PATCH 8/9 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
@@ -1849,20 +1849,25 @@ intel_get_excl_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) { -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, event); + c2 =__intel_get_event_constraints (cpuc, 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, c); +return intel_get_excl_constraints (cpuc, event, c2); -return c; +return c2; } static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
Signature · 1 line
1.7.9.5
PATCH 9/9 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 | 31 +++++++++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event.h | 5 +++++ arch/x86/kernel/cpu/perf_event_intel.c | 4 ++-- 3 files changed, 38 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/perf_event.c +31 -0
@@ -1876,10 +1876,41 @@ 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) +{ +unsigned long val; +int ff =is_ht_workaround_enabled (); +ssize_t ret; + + ret =kstrtoul (buf,0 , &val); +if (ret) +return ret; + +if (!!val != ff) { +if (!val) + x86_pmu.flags &= ~PMU_FL_EXCL_ENABLED ; +else + x86_pmu.flags |=PMU_FL_EXCL_ENABLED ; + } +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 , };
arch/x86/kernel/cpu/perf_event.h +5 -0
@@ -537,6 +537,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
@@ -769,6 +770,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 +2 -2
@@ -1747,7 +1747,7 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,* validating a group does not require * enforcing cross-thread exclusion */ -if (cpuc->is_fake) +if (cpuc->is_fake || !is_ht_workaround_enabled ())return c;/*
@@ -2610,7 +2610,7 @@ static __init void intel_nehalem_quirk(void)*/ static __init void intel_ht_bug (void ) { - x86_pmu.flags |=PMU_FL_EXCL_CNTRS ; + x86_pmu.flags |=PMU_FL_EXCL_CNTRS |PMU_FL_EXCL_ENABLED ; x86_pmu.commit_scheduling = intel_commit_scheduling; x86_pmu.start_scheduling = intel_start_scheduling;
Signature · 1 line
1.7.9.5
Re: [PATCH 9/9] 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 your hardware contains this erratum, why would you ever want to disable the workaround? Providing the user with the option of turning this off seems like a bad idea.
I suspect that users will rarely know whether they can legitimately disable this.
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 15 lines · Matt Fleming
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_workaround
Quoted 6 lines
If your hardware contains this erratum, why would you ever want to disable the workaround? Providing the user with the option of turning this off seems like a bad idea.
I suspect that users will rarely know whether they can legitimately disable this.
If you know what you are doing (poweruser), then there are measurements which works fine with the HT erratum. This is why we have the option.
For instance if you only measure events 4x4 in system-wide mode and you know which counters these event are going to use, you don't need the workaround. For instance:
# perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5
Works well if you have a uniform workload across all CPUs. All those events leak, but the leaks balance themselves and you get the correct counts in the end. The advantage is that you don't have to multiplex. With the workaround enable, this would multiplex a lot.
But as I said, this is for experts only.
Another reason is for systems with HT disabled. It turned out to be very difficult to determine at kernel BOOT TIME if HT was enabled or not. Note what I said: ENABLED and not SUPPORTED. The latter is easy to detect. The former needs some model specific code which is quite complicated. I wish the kernel had this capability abstracted somehow. Consequently, the workaround is always enabled. When HT is disabled, there won't be multiplexing because there will never be conflict, but you pay a little price for accessing the extra data state. An init script could well detect HT is off and thus disable the workaround altogether.
Those are the two main reasons for this control in sysfs.
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 10 lines · Stephane Eranian
If you know what you are doing (poweruser), then there are measurements which works fine with the HT erratum. This is why we have the option.
For instance if you only measure events 4x4 in system-wide mode and you know which counters these event are going to use, you don't need the workaround. For instance:
# perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5
Quoted 7 lines
Works well if you have a uniform workload across all CPUs. All those events leak, but the leaks balance themselves and you get the correct counts in the end. The advantage is that you don't have to multiplex. With the workaround enable, this would multiplex a lot.
But as I said, this is for experts only.
Is it not possible to detect this in the kernel and only enable the workaround for the case where the leaks don't balance? It may not be possible (or practical) but I do think it's worth having the discussion.
Quoted 9 lines
Another reason is for systems with HT disabled. It turned out to be very difficult to determine at kernel BOOT TIME if HT was enabled or not. Note what I said: ENABLED and not SUPPORTED. The latter is easy to detect. The former needs some model specific code which is quite complicated. I wish the kernel had this capability abstracted somehow. Consequently, the workaround is always enabled. When HT is disabled, there won't be multiplexing because there will never be conflict, but you pay a little price for accessing the extra data state.
Does cpu_sibling_map not give you some indication of whether HT is enabled? I think the topology_thread_cpumask() is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.
Quoted 1 line
An init script could well detect HT is off and thus disable the workaround altogether.
This is exactly the kind of thing I think we should try to avoid. The ideal is that things just work out of the box and don't require these magic knobs to be tweaked.
Quoted 1 line
Those are the two main reasons for this control in sysfs.
Thanks for the info!
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 17 lines · Matt Fleming
Quoted 16 lines · Stephane Eranian
If you know what you are doing (poweruser), then there are measurements which works fine with the HT erratum. This is why we have the option.
For instance if you only measure events 4x4 in system-wide mode and you know which counters these event are going to use, you don't need the workaround. For instance:
# perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5Works well if you have a uniform workload across all CPUs. All those events leak, but the leaks balance themselves and you get the correct counts in the end. The advantage is that you don't have to multiplex. With the workaround enable, this would multiplex a lot.
Quoted 7 lines
Quoted 1 line
But as I said, this is for experts only.
Is it not possible to detect this in the kernel and only enable the workaround for the case where the leaks don't balance? It may not be possible (or practical) but I do think it's worth having the discussion.
How would you know that you have a uniform workload from inside the kernel?
Quoted 10 lines
Quoted 9 lines
Another reason is for systems with HT disabled. It turned out to be very difficult to determine at kernel BOOT TIME if HT was enabled or not. Note what I said: ENABLED and not SUPPORTED. The latter is easy to detect. The former needs some model specific code which is quite complicated. I wish the kernel had this capability abstracted somehow. Consequently, the workaround is always enabled. When HT is disabled, there won't be multiplexing because there will never be conflict, but you pay a little price for accessing the extra data state.
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.
Remember trying some of that, but when perf_event is initialized, those masks are not yet setup properly.
Quoted 9 lines
Quoted 1 line
An init script could well detect HT is off and thus disable the workaround altogether.
This is exactly the kind of thing I think we should try to avoid. The ideal is that things just work out of the box and don't require these magic knobs to be tweaked.
Quoted 1 line
Those are the two main reasons for this control in sysfs.
Thanks for the info!
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
Quoted 7 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.
Oh, bummer.
If there's no way to detect whether we should enable this workaround at runtime (and it sounds like there isn't a good way), then that's fair enough.
We should think twice about allowing it to be disabled via sysfs, however. Because what is guaranteed to happen is that some user will report getting bogus results from perf for these events and we'll spend days trying to figure out why, only to discover they disabled the workaround and didn't tell us or didn't realise that they'd disabled it.
If the workaround is low overhead, can't we just leave it enabled?
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 6 lines · Matt Fleming
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
No way to know this otherwise we could play some tricks.
Quoted 10 lines
Quoted 7 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.Oh, bummer.
I think those should be initialized earlier on during booting.
Quoted 4 lines
If there's no way to detect whether we should enable this workaround at runtime (and it sounds like there isn't a good way), then that's fair enough.
Quoted 8 lines
We should think twice about allowing it to be disabled via sysfs, however. Because what is guaranteed to happen is that some user will report getting bogus results from perf for these events and we'll spend days trying to figure out why, only to discover they disabled the workaround and didn't tell us or didn't realise that they'd disabled it.
If the workaround is low overhead, can't we just leave it enabled?
It is enabled by default. Nothing is done to try and disable it later even once the kernel is fully booted. So this is mostly for testing and power-users.
Borislav Petkov
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 3 lines · Stephane Eranian
It is enabled by default. Nothing is done to try and disable it later even once the kernel is fully booted. So this is mostly for testing and power-users.
You keep saying "power-users". What is the disadvantage for power users running with the workaround disabled? I.e., why would anyone want to disable it at all, what is the use case for that?
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 9 lines · Borislav Petkov
Quoted 3 lines · Stephane Eranian
It is enabled by default. Nothing is done to try and disable it later even once the kernel is fully booted. So this is mostly for testing and power-users.
You keep saying "power-users". What is the disadvantage for power users running with the workaround disabled? I.e., why would anyone want to disable it at all, what is the use case for that?
I gave a test case earlier:
# echo 0 >/proc/sys/kernel/nmi_watchdog # run_my_uniform_workload_on_all_cpus & # perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5
That run gives the correct answer.
If I just look at CPU0 CPU4 siblings:
CPU0, counter0 leaks N counts to CPU4, counter 0
but at the same time:
CPU4, counter0 leaks N counts to CPU0, counter 0
This is because we have the same event in the same counter AND the workload is uniform, meaning the event (here loads retired) occurs at the same rate on both siblings.
You can test this by measuring only on one HT.
# perf stat -a -C0 -e r81d0,r01d1,r08d0,r20d1 sleep 5
Note that some events, leak more than they count.
Again, this is really for experts. The average users should not have to deal with this. So we can drop the sysfs entry.
Borislav Petkov
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 21 lines · Stephane Eranian
I gave a test case earlier:
# echo 0 >/proc/sys/kernel/nmi_watchdog # run_my_uniform_workload_on_all_cpus & # perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5That run gives the correct answer.
If I just look at CPU0 CPU4 siblings:
CPU0, counter0 leaks N counts to CPU4, counter 0
but at the same time:
CPU4, counter0 leaks N counts to CPU0, counter 0
This is because we have the same event in the same counter AND the workload is uniform, meaning the event (here loads retired) occurs at the same rate on both siblings.
Quoted 4 lines
You can test this by measuring only on one HT.
# perf stat -a -C0 -e r81d0,r01d1,r08d0,r20d1 sleep 5Note that some events, leak more than they count.
Ok, so AFAIU, this particular workload counts correctly just because counters leak the same amount. If so, what happens if you run this exact same workload with the workaround enabled? I read something about a bit more counter multiplexing... or is there a more serious issue?
Thanks.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 25 lines · Borislav Petkov
Quoted 24 lines · Stephane Eranian
I gave a test case earlier:
# echo 0 >/proc/sys/kernel/nmi_watchdog # run_my_uniform_workload_on_all_cpus & # perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5That run gives the correct answer.
If I just look at CPU0 CPU4 siblings:
CPU0, counter0 leaks N counts to CPU4, counter 0
but at the same time:
CPU4, counter0 leaks N counts to CPU0, counter 0
This is because we have the same event in the same counter AND the workload is uniform, meaning the event (here loads retired) occurs at the same rate on both siblings.
You can test this by measuring only on one HT.
# perf stat -a -C0 -e r81d0,r01d1,r08d0,r20d1 sleep 5
Quoted 6 lines
Quoted 1 line
Note that some events, leak more than they count.
Ok, so AFAIU, this particular workload counts correctly just because counters leak the same amount. If so, what happens if you run this exact same workload with the workaround enabled? I read something about a bit more counter multiplexing... or is there a more serious issue?
The issue is that the outcoming leaked counts are not compensated by the incoming leaked counts of the sibling thread. With the workaround, corrupting events are always scheduled with an empty sibling counter. This means that their leaked counts are lost. So it is expected to see lower counts with the workaround. Note that this is not a side-effect of the workaround; leaked counts are expected to be lost with nothing measured on the sibling counter in general.
In a second series we intend to re-integrate the counts for counting mode events. The workaround makes this easier because it guarantees that the sibling counter is unused, thus its counts are purely leaked counts and they can be safely re-integrated.
Quoted 9 lines
Thanks.
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Borislav Petkov
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 8 lines · Maria Dimakopoulou
The issue is that the outcoming leaked counts are not compensated by the incoming leaked counts of the sibling thread. With the workaround, corrupting events are always scheduled with an empty sibling counter. This means that their leaked counts are lost. So it is expected to see lower counts with the workaround. Note that this is not a side-effect of the workaround; leaked counts are expected to be lost with nothing measured on the sibling counter in general.
Quoted 4 lines
In a second series we intend to re-integrate the counts for counting mode events. The workaround makes this easier because it guarantees that the sibling counter is unused, thus its counts are purely leaked counts and they can be safely re-integrated.
IIUC, sounds to me like reintegrating the leaked counts from the unused counter should be part of the workaround too, not a second series...
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 9 lines · Borislav Petkov
Quoted 8 lines · Maria Dimakopoulou
The issue is that the outcoming leaked counts are not compensated by the incoming leaked counts of the sibling thread. With the workaround, corrupting events are always scheduled with an empty sibling counter. This means that their leaked counts are lost. So it is expected to see lower counts with the workaround. Note that this is not a side-effect of the workaround; leaked counts are expected to be lost with nothing measured on the sibling counter in general.
Quoted 8 lines
Quoted 4 lines
In a second series we intend to re-integrate the counts for counting mode events. The workaround makes this easier because it guarantees that the sibling counter is unused, thus its counts are purely leaked counts and they can be safely re-integrated.
IIUC, sounds to me like reintegrating the leaked counts from the unused counter should be part of the workaround too, not a second series...
This series aims to avoid corruption of non-corrupting events. Re-integration of the counts is not related to this. This is why we chose to fix this other problem on a second series to keep things clean and concepts separated.
Quoted 6 lines
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 15 lines · Maria Dimakopoulou
Quoted 14 lines · Borislav Petkov
Quoted 12 lines · Maria Dimakopoulou
The issue is that the outcoming leaked counts are not compensated by the incoming leaked counts of the sibling thread. With the workaround, corrupting events are always scheduled with an empty sibling counter. This means that their leaked counts are lost. So it is expected to see lower counts with the workaround. Note that this is not a side-effect of the workaround; leaked counts are expected to be lost with nothing measured on the sibling counter in general.
In a second series we intend to re-integrate the counts for counting mode events. The workaround makes this easier because it guarantees that the sibling counter is unused, thus its counts are purely leaked counts and they can be safely re-integrated.
Quoted 9 lines
Quoted 3 lines
IIUC, sounds to me like reintegrating the leaked counts from the unused counter should be part of the workaround too, not a second series...
This series aims to avoid corruption of non-corrupting events. Re-integration of the counts is not related to this. This is why we chose to fix this other problem on a second series to keep things clean and concepts separated.
I agree with Maria here. The reintegration is different problem. The series here helps and is a required first step. Reintegration will be added asap.
Quoted 6 lines
Quoted 6 lines
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Borislav Petkov
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
In reply to Maria DimakopoulouQuoted 2 lines · Maria Dimakopoulou
This series aims to avoid corruption of non-corrupting events. Re-integration of the counts is not related to this.
What do you mean "not related"? Then you have a partial workaround. This whole thing is trying to fix a hw bug so of course it is related.
Once you do the "full" workaround, along with the part which reintegrates the counts and thus completely fixes the issue (I believe), then you don't need to disable it at all because disabling it doesn't make any sense then. See what I'm saying?
This is the whole point Matt and I are trying to make: if the *full* workaround doesn't have any noticeable disadvantages, then you don't need to add a disable-mechanism due to the can of worms opening if you do.
How you get this upstream to ease the review is a whole another story and I applaud your desire to keep things clean.
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Maria Dimakopoulou
This series aims to avoid corruption of non-corrupting events. Re-integration of the counts is not related to this.
What do you mean "not related"? Then you have a partial workaround. This whole thing is trying to fix a hw bug so of course it is related.
I said not related to the problem of corruption of non-corrupting events which we solve here.
Re-integration of the counts of corrupting events is a different problem. Both problems are related to HT bug.
Quoted 11 lines
Once you do the "full" workaround, along with the part which reintegrates the counts and thus completely fixes the issue (I believe), then you don't need to disable it at all because disabling it doesn't make any sense then. See what I'm saying?
This is the whole point Matt and I are trying to make: if the *full* workaround doesn't have any noticeable disadvantages, then you don't need to add a disable-mechanism due to the can of worms opening if you do.
As Stephane pointed out, the sysfs entry is optional and the workaround can be disabled only as root.
It is not absolutely necessary and it's not important. We will drop it in V2.
Quoted 3 lines
How you get this upstream to ease the review is a whole another story and I applaud your desire to keep things clean.
Then, I guess we agree to keep the re-integration for another series for the reason you just pointed.
Quoted 6 lines
--
Regards/Gruss,
Boris.Sent from a fat crate under my desk. Formatting is fine. --
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 5 lines
As Stephane pointed out, the sysfs entry is optional and the workaround can be disabled only as root.
It is not absolutely necessary and it's not important. We will drop it in V2.
I would prefer to keep it. It's fairly complex and it's always good to have a way to disable complex things in case something goes wrong.
-Andi
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 8 lines · Andi Kleen
Quoted 5 lines
As Stephane pointed out, the sysfs entry is optional and the workaround can be disabled only as root.
It is not absolutely necessary and it's not important. We will drop it in V2.
I would prefer to keep it. It's fairly complex and it's always good to have a way to disable complex things in case something goes wrong.
You want to be able to disable the workaround in case it doesn't work? I'm having a hard time buying that as a valid reason for this knob.
If someone runs into issues with the workaround we want them to report those issues so that we can tweak the code. If they've got the ability to simply disable the code they're less likely to report the problem and we'll all be worse for it.
Having the knob increase the number of configurations and increases complexity, it doesn't reduce it.
Peter Zijlstra
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
In reply to Matt FlemingQuoted 11 lines · Matt Fleming
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
Quoted 5 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.
Quoted 4 lines
Quoted 2 lines
Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.Oh, bummer.
So we init perf very early to get nmi-watchdog up and running, but there's no reason you cannot register a second initcall later and flip the switch from it there.
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Matt Fleming
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
Quoted 5 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.Oh, bummer.
So we init perf very early to get nmi-watchdog up and running, but there's no reason you cannot register a second initcall later and flip the switch from it there.
and what initcall would that be?
Peter Zijlstra
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 16 lines · Stephane Eranian
Quoted 15 lines · Peter Zijlstra
Quoted 14 lines · Matt Fleming
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
Quoted 7 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Oh, bummer.
So we init perf very early to get nmi-watchdog up and running, but there's no reason you cannot register a second initcall later and flip the switch from it there.
and what initcall would that be?
Pretty much anything !early_initcall() is ran after SMP bringup iirc.
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 19 lines · Peter Zijlstra
Quoted 18 lines · Stephane Eranian
Quoted 17 lines · Peter Zijlstra
Quoted 15 lines · Matt Fleming
Quoted 2 lines · Stephane Eranian
How would you know that you have a uniform workload from inside the kernel?
That's what I'm asking you ;-)
Quoted 7 lines
Quoted 5 lines
Does
cpu_sibling_mapnot give you some indication of whether HT is enabled? I think thetopology_thread_cpumask()is the topology API for that. But I could most definitely be wrong. Hopefully someone on the Cc list will know.Remember trying some of that, but when
perf_eventis initialized, those masks are not yet setup properly.Oh, bummer.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
So we init perf very early to get nmi-watchdog up and running, but there's no reason you cannot register a second initcall later and flip the switch from it there.
and what initcall would that be?
Pretty much anything !early_initcall() is ran after SMP bringup iirc.
Ok, we can try this. Need to check the impact on NMI watchdog if already active.
Peter Zijlstra
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 4 lines · Stephane Eranian
Quoted 1 line
Pretty much anything !early_initcall() is ran after SMP bringup iirc.
Ok, we can try this. Need to check the impact on NMI watchdog if already active.
Right, we could provide an interface to stop and restart the watchdog so that the PMU is quiescent when we flip this switch, if required.
Peter Zijlstra
maintainerRe: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
In reply to Stephane EranianQuoted 9 lines · Stephane Eranian
If you know what you are doing (poweruser), then there are measurements which works fine with the HT erratum. This is why we have the option.
For instance if you only measure events 4x4 in system-wide mode and you know which counters these event are going to use, you don't need the workaround. For instance:
# perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5
Quoted 7 lines
Works well if you have a uniform workload across all CPUs. All those events leak, but the leaks balance themselves and you get the correct counts in the end. The advantage is that you don't have to multiplex. With the workaround enable, this would multiplex a lot.
But as I said, this is for experts only.
Still seems tricky, you really want those pinned to make that guarantee, and even then its a stretch. I don't think perf tool exposes the pinned attribute though, or I'm just not looking right.
I say stretch, because while I think it'll work out and we'll end up programming the counters the same way on each cpu, we really do not make that guarantee either, pinned or not.
I think I agree with Matt in that exposing this to userspace is really asking for trouble.
Now, I've not yet read through the entire patch series, but how impossible is it to allow programming the exact same event on both HT siblings?
Re: [PATCH 9/9] perf/x86: add syfs entry to disable HT bug workaround
Quoted 17 lines · Peter Zijlstra
Quoted 15 lines · Stephane Eranian
If you know what you are doing (poweruser), then there are measurements which works fine with the HT erratum. This is why we have the option.
For instance if you only measure events 4x4 in system-wide mode and you know which counters these event are going to use, you don't need the workaround. For instance:
# perf stat -a -e r81d0,r01d1,r08d0,r20d1 sleep 5Works well if you have a uniform workload across all CPUs. All those events leak, but the leaks balance themselves and you get the correct counts in the end. The advantage is that you don't have to multiplex. With the workaround enable, this would multiplex a lot.
Quoted 6 lines
Quoted 1 line
But as I said, this is for experts only.
Still seems tricky, you really want those pinned to make that guarantee, and even then its a stretch. I don't think perf tool exposes the pinned attribute though, or I'm just not looking right.
I think it does. But regardless, if you are on single user machine, NMI disabled,
and you know where events can run, workload is uniform, then it does work. Of course, this is a stretch for average users.
Quoted 4 lines
I say stretch, because while I think it'll work out and we'll end up programming the counters the same way on each cpu, we really do not make that guarantee either, pinned or not.
There is no guarantee. However, this is what is currently going on.
Quoted 3 lines
I think I agree with Matt in that exposing this to userspace is really asking for trouble.
This is a separate patch for a good reason, it is optional. If you think it is too risky, then drop it.
Quoted 3 lines
Now, I've not yet read through the entire patch series, but how impossible is it to allow programming the exact same event on both HT siblings?
That would require global view of scheduling and multiplexing in sync between HT to ensure corrupting events always face each other. But again this also assume only one tool instance is running.
I think it is better to use the workaround and repatriate the counts for corrupting events. That would allow correct counting. Sampling is out on those.
Quoted 1 line
There is no HW or FW workaround for this problem.
Actually there is for global measurements:
measure with Any bit set and divide by two.
Please add a check that the any bit is set, and disable the workaround for that case.
-Andi
Quoted 9 lines · Andi Kleen
Quoted 1 line
There is no HW or FW workaround for this problem.
Actually there is for global measurements:
measure with Any bit set and divide by two.
Please add a check that the any bit is set, and disable the workaround for that case.
I think this assume same event is measured on sibling counters at any time. Otherwise, how does that eliminate the corruption?