perf/x86/intel: Fix bugs of auto counter reload sampling
Subsystems (3)
v4 cover perf/x86/intel: Fix bugs of auto counter reload sampling
Changes:
v3 -> v4:
- Simplify ACR group indices valiation (Sashiko, patch 1/5)
- Fix the issue that new acr_mask may not be updated into HW if match_prev_assignment() returns true. (Sashiko, patch 2/5)
v2 -> v3:
- Fix the issue that user-space ACR-mask is not properly validated. (Sashiko, patch 1/4)
v1 -> v2:
- Clear stale mask for all events (Sashiko, Patch 1/4)
- Enable auto counter reload for DMR. (Patch 3/4)
- Remove duplicated CFG_C MSR value tracking. (Patch 4/4)
This small patch-set fixes several issues in auto counter reload support.
- The stale ACR mask is not properly validated before setting a new one. Patch 1/4 fixes this issue.
- PMI is enabled by default for self-reloaded ACR events which causes suspicious NMI warning. Patch 2/4 fixes this issue.
- ACR sampling is not really enabled on DMR. Patch 3/4 fixes the issue.
- Two variables are used to trace CFG_C MSR value independently for ACR and arch-PEBS. It's error-prone and fragile. Patch 4/4 fixes this issue.
Besides an ACR unit test is added into perf tests which would be posted in a separate session.
Tests:
Run below ACR sampling commands on CWF, DMR, PTL and NVL (hybrid platforms), no issues are found.
1. Non-PEBS ACR sampling
perf record -e '{instructions/period=20000,acr_mask=0x2/u,cycles/period=40000,acr_mask=0x3/u}' ~/test
2. PEBS ACR sampling
perf record -e '{instructions/period=20000,acr_mask=0x2/pu,cycles/period=40000,acr_mask=0x3/u}' ~/test
3. Perf-tools ACR sampling test
The patch (https://lore.kernel.org/all/[email protected]/)
adds ACR sampling test case in perf tools record test.
perf test 148
History:
v1: https://lore.kernel.org/all/[email protected]/
v2: https://lore.kernel.org/all/[email protected]/
v3: https://lore.kernel.org/all/[email protected]/
Dapeng Mi (5):
perf/x86/intel: Improve validation and configuration of ACR masks perf/x86/intel: Always reprogram ACR events to prevent stale masks perf/x86/intel: Disable PMI for self-reloaded ACR events perf/x86/intel: Enable auto counter reload for DMR perf/x86/intel: Consolidate MSR_IA32_PERF_CFG_C tracking
arch/x86/events/core.c | 13 +++++--- arch/x86/events/intel/core.c | 63 ++++++++++++++++++++++++++---------- arch/x86/events/perf_event.h | 14 ++++++-- 3 files changed, 65 insertions(+), 25 deletions(-)
Signature · 1 line
2.34.1
PATCH v4 1/5 perf/x86/intel: Improve validation and configuration of ACR masks
Currently there are several issues on the user space ACR mask validation and configuration.
- The validation for user space ACR mask (attr.config2) is incomplete, e.g., the ACR mask could include the index which belongs to another ACR events group, but it's not validated.
- An early return on an invalid ACR mask caused all subsequent ACR groups to be skipped.
- The stale hardware ACR mask (hw.config1) is not cleared before setting new hardware ACR mask.
The following changes address all of the above issues.
- Figure out the event index group of an ACR group. Any bits in the user-space mask not present in the index group are now dropped.
- Instead of an early return on invalid bits, drop only the invalid portions and continue iterating through all ACR events to ensure full configuration.
- Explicitly clear the stale hardware ACR mask for each event prior to writing the new configuration.
Besides, a non-leader event member of ACR group could be disabled in theory. This could cause bit-shifting errors in the acr_mask of remaining group members. But since ACR sampling requires all events to be active, this should not be a big concern in real use case. Add a "FIXME" comment to notice this risk.
---
V4: 1) Simplify ACR group indices validation. 2) Add FIXME to notify the bit-shifting risk of ACR mask if event numbers of ACR group are diabled.
arch/x86/events/intel/core.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
arch/x86/events/intel/core.c +25 -7
@@ -3332,23 +3332,41 @@ static void intel_pmu_enable_event(struct perf_event *event)static void intel_pmu_acr_late_setup (struct cpu_hw_events *cpuc) {struct perf_event *event, *leader; -int i, j, idx; +int i, j, k, bit, idx; +/* +* FIXME: ACR mask parsing relies on cpuc->event_list[] (active events only). +* Disabling an ACR event causes bit-shifting errors in the acr_mask of +* remaining group members. As ACR sampling requires all events to be active, +* this limitation is acceptable for now. Revisit if independent event toggling +* is required. +*/ for (i =0 ; i < cpuc->n_events; i++) { leader = cpuc->event_list[i];if (!is_acr_event_group (leader))continue ; -/* The ACR events must be contiguous. */ +/* Find the last event of the ACR group. */ for (j = i; j < cpuc->n_events; j++) { event = cpuc->event_list[j];if (event->group_leader != leader->group_leader)break ; -for_each_set_bit (idx, (unsigned long *)&event->attr.config2,X86_PMC_IDX_MAX ) { -if (i + idx >= cpuc->n_events || - !is_acr_event_group (cpuc->event_list[i + idx])) -return ; -__set_bit (cpuc->assign[i + idx], (unsigned long *)&event->hw.config1); + } + +/* +* Translate the user-space ACR mask (attr.config2) into the physical +* counter bitmask (hw.config1) for each ACR event in the group. +* NOTE: ACR event contiguity is guaranteed by intel_pmu_hw_config(). +*/ +for (k = i; k < j; k++) { + event = cpuc->event_list[k]; + event->hw.config1 =0 ; +for_each_set_bit (bit, (unsigned long *)&event->attr.config2,X86_PMC_IDX_MAX ) { + idx = i + bit; +/* Event index of ACR group must locate in [i, j). */ +if (idx >= j || !is_acr_event_group (cpuc->event_list[idx])) +continue ; +__set_bit (cpuc->assign[idx], (unsigned long *)&event->hw.config1); } } i = j -1 ;
Signature · 1 line
2.34.1
[tip: perf/core] perf/x86/intel: Improve validation and configuration of ACR masks
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 5ad732a56be46aabf158c16aa0c095291727aaef Gitweb: https://git.kernel.org/tip/5ad732a56be46aabf158c16aa0c095291727aaef Author: Dapeng Mi <[email protected]> AuthorDate: Thu, 30 Apr 2026 08:25:54 +08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 05 May 2026 12:47:21 +02:00
perf/x86/intel: Improve validation and configuration of ACR masks
Currently there are several issues on the user space ACR mask validation and configuration.
- The validation for user space ACR mask (attr.config2) is incomplete, e.g., the ACR mask could include the index which belongs to another ACR events group, but it's not validated.
- An early return on an invalid ACR mask caused all subsequent ACR groups to be skipped.
- The stale hardware ACR mask (hw.config1) is not cleared before setting new hardware ACR mask.
The following changes address all of the above issues.
- Figure out the event index group of an ACR group. Any bits in the user-space mask not present in the index group are now dropped.
- Instead of an early return on invalid bits, drop only the invalid portions and continue iterating through all ACR events to ensure full configuration.
- Explicitly clear the stale hardware ACR mask for each event prior to writing the new configuration.
Besides, a non-leader event member of ACR group could be disabled in theory. This could cause bit-shifting errors in the acr_mask of remaining group members. But since ACR sampling requires all events to be active, this should not be a big concern in real use case. Add a "FIXME" comment to notice this risk.
--- arch/x86/events/intel/core.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
arch/x86/events/intel/core.c +25 -7
@@ -3332,23 +3332,41 @@ static void intel_pmu_enable_event(struct perf_event *event)static void intel_pmu_acr_late_setup (struct cpu_hw_events *cpuc) {struct perf_event *event, *leader; -int i, j, idx; +int i, j, k, bit, idx; +/* +* FIXME: ACR mask parsing relies on cpuc->event_list[] (active events only). +* Disabling an ACR event causes bit-shifting errors in the acr_mask of +* remaining group members. As ACR sampling requires all events to be active, +* this limitation is acceptable for now. Revisit if independent event toggling +* is required. +*/ for (i =0 ; i < cpuc->n_events; i++) { leader = cpuc->event_list[i];if (!is_acr_event_group (leader))continue ; -/* The ACR events must be contiguous. */ +/* Find the last event of the ACR group. */ for (j = i; j < cpuc->n_events; j++) { event = cpuc->event_list[j];if (event->group_leader != leader->group_leader)break ; -for_each_set_bit (idx, (unsigned long *)&event->attr.config2,X86_PMC_IDX_MAX ) { -if (i + idx >= cpuc->n_events || - !is_acr_event_group (cpuc->event_list[i + idx])) -return ; -__set_bit (cpuc->assign[i + idx], (unsigned long *)&event->hw.config1); + } + +/* +* Translate the user-space ACR mask (attr.config2) into the physical +* counter bitmask (hw.config1) for each ACR event in the group. +* NOTE: ACR event contiguity is guaranteed by intel_pmu_hw_config(). +*/ +for (k = i; k < j; k++) { + event = cpuc->event_list[k]; + event->hw.config1 =0 ; +for_each_set_bit (bit, (unsigned long *)&event->attr.config2,X86_PMC_IDX_MAX ) { + idx = i + bit; +/* Event index of ACR group must locate in [i, j). */ +if (idx >= j || !is_acr_event_group (cpuc->event_list[idx])) +continue ; +__set_bit (cpuc->assign[idx], (unsigned long *)&event->hw.config1); } } i = j -1 ;
PATCH v4 2/5 perf/x86/intel: Always reprogram ACR events to prevent stale masks
In reply to Dapeng MiMembers of an ACR group are logically linked via a bitmask of their hardware counter indices. If some members of the group are assigned new hardware counters during rescheduling, even events that keep their original counter index must be updated with a new mask.
Without this, an event will continue to use a stale acr_mask that references the old indices of its group peers. Ensure all ACR events are reprogrammed during the scheduling path to maintain consistency across the group.
---
V4: new patch.
arch/x86/events/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
arch/x86/events/core.c +8 -5
@@ -1294,13 +1294,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)return event->hw.event_base_rdpmc; } -static inline int match_prev_assignment (struct hw_perf_event *hwc, +static inline int match_prev_assignment (struct perf_event *event,struct cpu_hw_events *cpuc,int i) { +struct hw_perf_event *hwc = &event->hw; +return hwc->idx == cpuc->assign[i] && - hwc->last_cpu ==smp_processor_id () && - hwc->last_tag == cpuc->tags[i]; + hwc->last_cpu ==smp_processor_id () && + hwc->last_tag == cpuc->tags[i] && + !is_acr_event_group (event); }static void x86_pmu_start (struct perf_event *event,int flags);
@@ -1346,7 +1349,7 @@ static void x86_pmu_enable(struct pmu *pmu)* - no other event has used the counter since */ if (hwc->idx ==-1 || -match_prev_assignment (hwc, cpuc, i)) +match_prev_assignment (event, cpuc, i))continue ;/*
@@ -1367,7 +1370,7 @@ static void x86_pmu_enable(struct pmu *pmu) event = cpuc->event_list[i]; hwc = &event->hw; -if (!match_prev_assignment (hwc, cpuc, i)) +if (!match_prev_assignment (event, cpuc, i))x86_assign_hw_event (event, cpuc, i);else if (i < n_running)continue ;
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [Patch v4 2/5] perf/x86/intel: Always reprogram ACR events to prevent stale masks
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Unconditional hardware MSR reprogramming for ACR events introduces performance regression and…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Unconditional hardware MSR reprogramming for ACR events introduces performance regression and increases measurement blind spots. --
commit a8f30026401c4d7de00c3f1a7543204056d7235c
Author: Dapeng Mi <[email protected]> perf/x86/intel: Always reprogram ACR events to prevent stale masks
This commit modifies PMU event scheduling to force reprogramming of all ACR events during rescheduling. It does this by making match_prev_assignment() always return false for ACR events.
Quoted 12 lines
arch/x86/events/core.c +1
-1@@ -1294,13 +1294,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)return event->hw.event_base_rdpmc; } -static inline int match_prev_assignment (struct hw_perf_event *hwc, +static inline int match_prev_assignment (struct perf_event *event,struct cpu_hw_events *cpuc,int i)
arch/x86/events/core.c int x86_perf_rdpmc_index(struct perf_event *event) · line 1307
Quoted 10 lines
arch/x86/events/core.c +5
-2{ +struct hw_perf_event *hwc = &event->hw; +return hwc->idx == cpuc->assign[i] && - hwc->last_cpu ==smp_processor_id () && - hwc->last_tag == cpuc->tags[i]; + hwc->last_cpu ==smp_processor_id () && + hwc->last_tag == cpuc->tags[i] && + !is_acr_event_group (event); }
Does this unconditional hardware MSR reprogramming for ACR events introduce a performance regression and increase measurement blind spots?
By unconditionally returning false for all ACR events, every active ACR event will undergo a full x86_pmu_stop() and x86_pmu_start() cycle during PMU re-enablement (e.g., in x86_pmu_enable() when cpuc->n_added > 0).
These full stop/start cycles invoke multiple wrmsr and rdpmc instructions, adding significant cycle overhead to the hot scheduling path. Since this occurs while the PMU is globally disabled, the added latency extends the global PMU off-time, unnecessarily increasing the measurement blind spot where events are not counted across the CPU.
Could this overhead be avoided by checking if the mask actually changed?
x86_pmu_late_setup() calculates the new physical mask and stores it in event->hw.config1 before match_prev_assignment() is evaluated. Would it be better to compare event->hw.config1 against the previously programmed mask stored in cpuc->acr_cfg_b[hwc->idx] and only force a reprogram when they differ?
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [Patch v4 2/5] perf/x86/intel: Always reprogram ACR events to prevent stale masks
Quoted 47 lines · On 4/30/2026 10:04 AM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Unconditional hardware MSR reprogramming for ACR events introduces performance regression and increases measurement blind spots. --commit
a8f30026401c4d7de00c3f1a7543204056d7235c
Author: Dapeng Mi <[email protected]> perf/x86/intel: Always reprogram ACR events to prevent stale masksThis commit modifies PMU event scheduling to force reprogramming of all ACR events during rescheduling. It does this by making
match_prev_assignment()always return false for ACR events.Quoted 12 lines
arch/x86/events/core.c +1
-1@@ -1294,13 +1294,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)return event->hw.event_base_rdpmc; } -static inline int match_prev_assignment (struct hw_perf_event *hwc, +static inline int match_prev_assignment (struct perf_event *event,struct cpu_hw_events *cpuc,int i)arch/x86/events/core.c int x86_perf_rdpmc_index(struct perf_event *event) · line 1307
Quoted 10 lines
arch/x86/events/core.c +5
-2{ +struct hw_perf_event *hwc = &event->hw; +return hwc->idx == cpuc->assign[i] && - hwc->last_cpu ==smp_processor_id () && - hwc->last_tag == cpuc->tags[i]; + hwc->last_cpu ==smp_processor_id () && + hwc->last_tag == cpuc->tags[i] && + !is_acr_event_group (event); }Does this unconditional hardware MSR reprogramming for ACR events introduce a performance regression and increase measurement blind spots?
By unconditionally returning false for all ACR events, every active ACR event will undergo a full
x86_pmu_stop()andx86_pmu_start()cycle during PMU re-enablement (e.g., inx86_pmu_enable()whencpuc->n_added> 0).These full stop/start cycles invoke multiple wrmsr and rdpmc instructions, adding significant cycle overhead to the hot scheduling path. Since this occurs while the PMU is globally disabled, the added latency extends the global PMU off-time, unnecessarily increasing the measurement blind spot where events are not counted across the CPU.
Quoted 7 lines
Could this overhead be avoided by checking if the mask actually changed?
x86_pmu_late_setup()calculates the new physical mask and stores it inevent->hw.config1beforematch_prev_assignment()is evaluated. Would it be better to compareevent->hw.config1against the previously programmed mask stored in cpuc->acr_cfg_b[hwc->idx] and only force a reprogram when they differ?
Nice idea. This can be further optimized. I'm not sure if it's worth to post a new patchset for this single optimization. If not, I would post a single optimization patch for this.
Thanks.
Quoted 3 lines
[ ... ]
[tip: perf/core] perf/x86/intel: Always reprogram ACR events to prevent stale masks
In reply to Dapeng MiThe following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 8ba0b706a485b1e607594cf4210786d517ad1611 Gitweb: https://git.kernel.org/tip/8ba0b706a485b1e607594cf4210786d517ad1611 Author: Dapeng Mi <[email protected]> AuthorDate: Thu, 30 Apr 2026 08:25:55 +08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 05 May 2026 12:47:21 +02:00
perf/x86/intel: Always reprogram ACR events to prevent stale masks
Members of an ACR group are logically linked via a bitmask of their hardware counter indices. If some members of the group are assigned new hardware counters during rescheduling, even events that keep their original counter index must be updated with a new mask.
Without this, an event will continue to use a stale acr_mask that references the old indices of its group peers. Ensure all ACR events are reprogrammed during the scheduling path to maintain consistency across the group.
--- arch/x86/events/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
arch/x86/events/core.c +8 -5
@@ -1294,13 +1294,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)return event->hw.event_base_rdpmc; } -static inline int match_prev_assignment (struct hw_perf_event *hwc, +static inline int match_prev_assignment (struct perf_event *event,struct cpu_hw_events *cpuc,int i) { +struct hw_perf_event *hwc = &event->hw; +return hwc->idx == cpuc->assign[i] && - hwc->last_cpu ==smp_processor_id () && - hwc->last_tag == cpuc->tags[i]; + hwc->last_cpu ==smp_processor_id () && + hwc->last_tag == cpuc->tags[i] && + !is_acr_event_group (event); }static void x86_pmu_start (struct perf_event *event,int flags);
@@ -1346,7 +1349,7 @@ static void x86_pmu_enable(struct pmu *pmu)* - no other event has used the counter since */ if (hwc->idx ==-1 || -match_prev_assignment (hwc, cpuc, i)) +match_prev_assignment (event, cpuc, i))continue ;/*
@@ -1367,7 +1370,7 @@ static void x86_pmu_enable(struct pmu *pmu) event = cpuc->event_list[i]; hwc = &event->hw; -if (!match_prev_assignment (hwc, cpuc, i)) +if (!match_prev_assignment (event, cpuc, i))x86_assign_hw_event (event, cpuc, i);else if (i < n_running)continue ;
PATCH v4 3/5 perf/x86/intel: Disable PMI for self-reloaded ACR events
In reply to Dapeng MiOn platforms with Auto Counter Reload (ACR) support, such as NVL, a "NMI received for unknown reason 30" warning is observed when running multiple events in a group with ACR enabled:
$ perf record -e '{instructions/period=20000,acr_mask=0x2/u,\
cycles/period=40000,acr_mask=0x3/u}' ./testThe warning occurs because the Performance Monitoring Interrupt (PMI) is enabled for the self-reloaded event (the cycles event in this case). According to the Intel SDM, the overflow bit (IA32_PERF_GLOBAL_STATUS.PMCn_OVF) is never set for self-reloaded events. Since the bit is not set, the perf NMI handler cannot identify the source of the interrupt, leading to the "unknown reason" message.
Furthermore, enabling PMI for self-reloaded events is unnecessary and can lead to extraneous records that pollute the user's requested data.
Disable the interrupt bit for all events configured with ACR self-reload.
--- arch/x86/events/intel/core.c | 17 +++++++++++++---- arch/x86/events/perf_event.h | 10 ++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-)
arch/x86/events/intel/core.c +13 -4
@@ -3118,11 +3118,11 @@ static void intel_pmu_enable_fixed(struct perf_event *event)intel_set_masks (event, idx);/* -* Enable IRQ generation (0x8), if not PEBS, -* and enable ring-3 counting (0x2) and ring-0 counting (0x1) -* if requested: +* Enable IRQ generation (0x8), if not PEBS or self-reloaded +* ACR event, and enable ring-3 counting (0x2) and ring-0 +* counting (0x1) if requested: */ -if (!event->attr.precise_ip) +if (!event->attr.precise_ip && !is_acr_self_reload_event (event)) bits |=INTEL_FIXED_0_ENABLE_PMI ;if (hwc->config &ARCH_PERFMON_EVENTSEL_USR ) bits |=INTEL_FIXED_0_USER ;
@@ -3306,6 +3306,15 @@ static void intel_pmu_enable_event(struct perf_event *event)intel_set_masks (event, idx);static_call_cond (intel_pmu_enable_acr_event)(event);static_call_cond (intel_pmu_enable_event_ext)(event); +/* +* For self-reloaded ACR event, don't enable PMI since +* HW won't set overflow bit in GLOBAL_STATUS. Otherwise, +* the PMI would be recognized as a suspicious NMI. +*/ +if (is_acr_self_reload_event (event)) + hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT ; +else if (!event->attr.precise_ip) + hwc->config |=ARCH_PERFMON_EVENTSEL_INT ;__x86_pmu_enable_event (hwc, enable_mask);break ; case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1:
arch/x86/events/perf_event.h +10 -0
@@ -137,6 +137,16 @@ static inline bool is_acr_event_group(struct perf_event *event)return check_leader_group (event->group_leader,PERF_X86_EVENT_ACR ); } +static inline bool is_acr_self_reload_event (struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <0 ) +return false; + +return test_bit (hwc->idx, (unsigned long *)&hwc->config1); +} +struct amd_nb {int nb_id;/* NorthBridge id */ int refcnt;/* reference count */
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [Patch v4 3/5] perf/x86/intel: Disable PMI for self-reloaded ACR events
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Event PMIs can be permanently disabled due to a stale `hw.config1` state when an ACR group is…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Event PMIs can be permanently disabled due to a stale hw.config1 state when an ACR group is broken up. --
commit cfc30b699ff51679e8ae587b226916cfd6fbe7bc
Author: Dapeng Mi <[email protected]>
perf/x86/intel: Disable PMI for self-reloaded ACR events
This commit disables Performance Monitoring Interrupts (PMI) for all events configured with Auto Counter Reload (ACR) self-reload to prevent spurious "unknown reason" NMI warnings.
[ ... ]
Quoted 7 lines
arch/x86/events/perf_event.h +0
-0@@ -137,6 +137,16 @@ static inline bool is_acr_event_group(struct perf_event *event)return check_leader_group (event->group_leader,PERF_X86_EVENT_ACR ); }
arch/x86/events/perf_event.h static inline bool is_acr_event_group(struct perf_event *event) · line 148
Quoted 10 lines
arch/x86/events/perf_event.h +9
-0+static inline bool is_acr_self_reload_event (struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <0 ) +return false; + +return test_bit (hwc->idx, (unsigned long *)&hwc->config1); +}
Can this cause PMIs to be permanently disabled if an ACR group is broken up?
If the original group leader is closed, perf_group_detach() promotes the siblings to standalone events, making them their own leaders. These new standalone events no longer have the PERF_X86_EVENT_ACR flag (as it was only set on the original leader).
Because they lack the flag, intel_pmu_acr_late_setup() skips them, and their hw.config1 field retains the stale physical counter bitmask from when they were in the ACR group.
Since is_acr_self_reload_event() checks hw.config1 without validating if the event is still in an ACR group via is_acr_event_group(), could a detached event that gets assigned to a counter matching the stale bitmask incorrectly return true here?
This would cause intel_pmu_enable_event() to incorrectly clear the ARCH_PERFMON_EVENTSEL_INT bit, breaking PMI generation and sampling for a now-normal event.
Quoted 3 lines
arch/x86/events/perf_event.h +0
-0struct amd_nb {int nb_id;/* NorthBridge id */ int refcnt;/* reference count */
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [Patch v4 3/5] perf/x86/intel: Disable PMI for self-reloaded ACR events
Quoted 43 lines · On 4/30/2026 10:36 AM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Event PMIs can be permanently disabled due to a stalehw.config1state when an ACR group is broken up. --commit
cfc30b699ff51679e8ae587b226916cfd6fbe7bc
Author: Dapeng Mi <[email protected]>perf/x86/intel: Disable PMI for self-reloaded ACR events
This commit disables Performance Monitoring Interrupts (PMI) for all events configured with Auto Counter Reload (ACR) self-reload to prevent spurious "unknown reason" NMI warnings.
[ ... ]
Quoted 7 lines
arch/x86/events/perf_event.h +0
-0@@ -137,6 +137,16 @@ static inline bool is_acr_event_group(struct perf_event *event)return check_leader_group (event->group_leader,PERF_X86_EVENT_ACR ); }arch/x86/events/perf_event.h static inline bool is_acr_event_group(struct perf_event *event) · line 148
Quoted 10 lines
arch/x86/events/perf_event.h +9
-0+static inline bool is_acr_self_reload_event (struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <0 ) +return false; + +return test_bit (hwc->idx, (unsigned long *)&hwc->config1); +}Can this cause PMIs to be permanently disabled if an ACR group is broken up?
If the original group leader is closed,
perf_group_detach()promotes the siblings to standalone events, making them their own leaders. These new standalone events no longer have thePERF_X86_EVENT_ACRflag (as it was only set on the original leader).Because they lack the flag,
intel_pmu_acr_late_setup()skips them, and their hw.config1 field retains the stale physical counter bitmask from when they were in the ACR group.
Quoted 8 lines
Since
is_acr_self_reload_event()checks hw.config1 without validating if the event is still in an ACR group viais_acr_event_group(), could a detached event that gets assigned to a counter matching the stale bitmask incorrectly return true here?This would cause
intel_pmu_enable_event()to incorrectly clear theARCH_PERFMON_EVENTSEL_INTbit, breaking PMI generation and sampling for a now-normal event.
I'm not sure if the issue could really happen in reality. If the group leader is disabled (I'm not fully understand the what does the "closed" mean, I suppose it means disable), all ACR events would be disabled as well.
But it's fine to add a sanity check whether the event is an ACR event in the is_acr_self_reload_event().
Thanks.
Quoted 4 lines
Quoted 4 lines
arch/x86/events/perf_event.h +0
-0struct amd_nb {int nb_id;/* NorthBridge id */ int refcnt;/* reference count */
[tip: perf/core] perf/x86/intel: Disable PMI for self-reloaded ACR events
In reply to Dapeng MiThe following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 1271aeccc307066315b2d3b0d5af2510e27018b5 Gitweb: https://git.kernel.org/tip/1271aeccc307066315b2d3b0d5af2510e27018b5 Author: Dapeng Mi <[email protected]> AuthorDate: Thu, 30 Apr 2026 08:25:56 +08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 05 May 2026 12:47:21 +02:00
perf/x86/intel: Disable PMI for self-reloaded ACR events
On platforms with Auto Counter Reload (ACR) support, such as NVL, a "NMI received for unknown reason 30" warning is observed when running multiple events in a group with ACR enabled:
$ perf record -e '{instructions/period=20000,acr_mask=0x2/u,\
cycles/period=40000,acr_mask=0x3/u}' ./testThe warning occurs because the Performance Monitoring Interrupt (PMI) is enabled for the self-reloaded event (the cycles event in this case). According to the Intel SDM, the overflow bit (IA32_PERF_GLOBAL_STATUS.PMCn_OVF) is never set for self-reloaded events. Since the bit is not set, the perf NMI handler cannot identify the source of the interrupt, leading to the "unknown reason" message.
Furthermore, enabling PMI for self-reloaded events is unnecessary and can lead to extraneous records that pollute the user's requested data.
Disable the interrupt bit for all events configured with ACR self-reload.
--- arch/x86/events/intel/core.c | 17 +++++++++++++---- arch/x86/events/perf_event.h | 10 ++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-)
arch/x86/events/intel/core.c +13 -4
@@ -3118,11 +3118,11 @@ static void intel_pmu_enable_fixed(struct perf_event *event)intel_set_masks (event, idx);/* -* Enable IRQ generation (0x8), if not PEBS, -* and enable ring-3 counting (0x2) and ring-0 counting (0x1) -* if requested: +* Enable IRQ generation (0x8), if not PEBS or self-reloaded +* ACR event, and enable ring-3 counting (0x2) and ring-0 +* counting (0x1) if requested: */ -if (!event->attr.precise_ip) +if (!event->attr.precise_ip && !is_acr_self_reload_event (event)) bits |=INTEL_FIXED_0_ENABLE_PMI ;if (hwc->config &ARCH_PERFMON_EVENTSEL_USR ) bits |=INTEL_FIXED_0_USER ;
@@ -3306,6 +3306,15 @@ static void intel_pmu_enable_event(struct perf_event *event)intel_set_masks (event, idx);static_call_cond (intel_pmu_enable_acr_event)(event);static_call_cond (intel_pmu_enable_event_ext)(event); +/* +* For self-reloaded ACR event, don't enable PMI since +* HW won't set overflow bit in GLOBAL_STATUS. Otherwise, +* the PMI would be recognized as a suspicious NMI. +*/ +if (is_acr_self_reload_event (event)) + hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT ; +else if (!event->attr.precise_ip) + hwc->config |=ARCH_PERFMON_EVENTSEL_INT ;__x86_pmu_enable_event (hwc, enable_mask);break ; case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1:
arch/x86/events/perf_event.h +10 -0
@@ -137,6 +137,16 @@ static inline bool is_acr_event_group(struct perf_event *event)return check_leader_group (event->group_leader,PERF_X86_EVENT_ACR ); } +static inline bool is_acr_self_reload_event (struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <0 ) +return false; + +return test_bit (hwc->idx, (unsigned long *)&hwc->config1); +} +struct amd_nb {int nb_id;/* NorthBridge id */ int refcnt;/* reference count */
PATCH v4 4/5 perf/x86/intel: Enable auto counter reload for DMR
In reply to Dapeng MiPanther cove µarch starts to support auto counter reload (ACR), but the static_call intel_pmu_enable_acr_event() is not updated for the Panther Cove µarch used by DMR. It leads to the auto counter reload is not really enabled on DMR.
Update static_call intel_pmu_enable_acr_event() in intel_pmu_init_pnc().
--- arch/x86/events/intel/core.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/events/intel/core.c +1 -0
@@ -7518,6 +7518,7 @@ static __always_inline void intel_pmu_init_pnc(struct pmu *pmu)hybrid (pmu, event_constraints) = intel_pnc_event_constraints;hybrid (pmu, pebs_constraints) = intel_pnc_pebs_event_constraints;hybrid (pmu, extra_regs) = intel_pnc_extra_regs; +static_call_update (intel_pmu_enable_acr_event, intel_pmu_enable_acr); } static __always_inline void intel_pmu_init_skt(struct pmu *pmu)
Signature · 1 line
2.34.1
[tip: perf/core] perf/x86/intel: Enable auto counter reload for DMR
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: aa4384bc8f4360167f3c3d5322121fe892289ea2 Gitweb: https://git.kernel.org/tip/aa4384bc8f4360167f3c3d5322121fe892289ea2 Author: Dapeng Mi <[email protected]> AuthorDate: Thu, 30 Apr 2026 08:25:57 +08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 05 May 2026 12:47:22 +02:00
perf/x86/intel: Enable auto counter reload for DMR
Panther cove µarch starts to support auto counter reload (ACR), but the static_call intel_pmu_enable_acr_event() is not updated for the Panther Cove µarch used by DMR. It leads to the auto counter reload is not really enabled on DMR.
Update static_call intel_pmu_enable_acr_event() in intel_pmu_init_pnc().
--- arch/x86/events/intel/core.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/events/intel/core.c +1 -0
@@ -7531,6 +7531,7 @@ static __always_inline void intel_pmu_init_pnc(struct pmu *pmu)hybrid (pmu, event_constraints) = intel_pnc_event_constraints;hybrid (pmu, pebs_constraints) = intel_pnc_pebs_event_constraints;hybrid (pmu, extra_regs) = intel_pnc_extra_regs; +static_call_update (intel_pmu_enable_acr_event, intel_pmu_enable_acr); } static __always_inline void intel_pmu_init_skt(struct pmu *pmu)
PATCH v4 5/5 perf/x86/intel: Consolidate MSR_IA32_PERF_CFG_C tracking
In reply to Dapeng MiBoth Auto Counter Reload (ACR) and Architectural PEBS use the PERF_CFG_C MSRs to configure event behavior. Currently, the driver maintains two independent variables acr_cfg_c and cfg_c_val to cache the values intended for these MSRs.
Using separate variables to track a single hardware register state is error-prone and can lead to configuration conflicts. Consolidate the tracking into a single cfg_c_val variable to ensure a unified and consistent view of the PERF_CFG_C MSR state.
--- arch/x86/events/intel/core.c | 13 +++++++------ arch/x86/events/perf_event.h | 4 +--- 2 files changed, 8 insertions(+), 9 deletions(-)
arch/x86/events/intel/core.c +7 -6
@@ -3169,10 +3169,10 @@ static void intel_pmu_config_acr(int idx, u64 mask, u32 reload)wrmsrl (msr_b + msr_offset, mask); cpuc->acr_cfg_b[idx] = mask; } -/* Only need to update the reload value when there is a valid config value. */ -if (mask && cpuc->acr_cfg_c[idx] != reload) { +/* Only update CFG_C reload when ACR is actively enabled (mask != 0) */ +if (mask && ((cpuc->cfg_c_val[idx] &ARCH_PEBS_RELOAD ) != reload)) {wrmsrl (msr_c + msr_offset, reload); - cpuc->acr_cfg_c[idx] = reload; + cpuc->cfg_c_val[idx] = reload; } }
@@ -3198,14 +3198,15 @@ static void intel_pmu_enable_event_ext(struct perf_event *event) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events);struct hw_perf_event *hwc = &event->hw; -union arch_pebs_index old, new; -struct arch_pebs_cap cap;u64 ext =0 ; - cap =hybrid (cpuc->pmu, arch_pebs_cap); +if (is_acr_event_group (event)) + ext |= (-hwc->sample_period) &ARCH_PEBS_RELOAD ;if (event->attr.precise_ip) {u64 pebs_data_cfg =intel_get_arch_pebs_data_config (event); +struct arch_pebs_cap cap =hybrid (cpuc->pmu, arch_pebs_cap); +union arch_pebs_index old, new; ext |=ARCH_PEBS_EN ;if (hwc->flags &PERF_X86_EVENT_AUTO_RELOAD )
arch/x86/events/perf_event.h +1 -3
@@ -322,10 +322,8 @@ struct cpu_hw_events {u64 fixed_ctrl_val;u64 active_fixed_ctrl_val; -/* Intel ACR configuration */ +/* Intel ACR/arch-PEBS configuration */ u64 acr_cfg_b[X86_PMC_IDX_MAX ]; -u64 acr_cfg_c[X86_PMC_IDX_MAX ]; -/* Cached CFG_C values */ u64 cfg_c_val[X86_PMC_IDX_MAX ];/*
Signature · 1 line
2.34.1
[tip: perf/core] perf/x86/intel: Consolidate MSR_IA32_PERF_CFG_C tracking
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 5c3cdc74af25fc7f64a3ed260b4f6eb8313a3b75 Gitweb: https://git.kernel.org/tip/5c3cdc74af25fc7f64a3ed260b4f6eb8313a3b75 Author: Dapeng Mi <[email protected]> AuthorDate: Thu, 30 Apr 2026 08:25:58 +08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 05 May 2026 12:47:24 +02:00
perf/x86/intel: Consolidate MSR_IA32_PERF_CFG_C tracking
Both Auto Counter Reload (ACR) and Architectural PEBS use the PERF_CFG_C MSRs to configure event behavior. Currently, the driver maintains two independent variables acr_cfg_c and cfg_c_val to cache the values intended for these MSRs.
Using separate variables to track a single hardware register state is error-prone and can lead to configuration conflicts. Consolidate the tracking into a single cfg_c_val variable to ensure a unified and consistent view of the PERF_CFG_C MSR state.
--- arch/x86/events/intel/core.c | 13 +++++++------ arch/x86/events/perf_event.h | 4 +--- 2 files changed, 8 insertions(+), 9 deletions(-)
arch/x86/events/intel/core.c +7 -6
@@ -3169,10 +3169,10 @@ static void intel_pmu_config_acr(int idx, u64 mask, u32 reload)wrmsrl (msr_b + msr_offset, mask); cpuc->acr_cfg_b[idx] = mask; } -/* Only need to update the reload value when there is a valid config value. */ -if (mask && cpuc->acr_cfg_c[idx] != reload) { +/* Only update CFG_C reload when ACR is actively enabled (mask != 0) */ +if (mask && ((cpuc->cfg_c_val[idx] &ARCH_PEBS_RELOAD ) != reload)) {wrmsrl (msr_c + msr_offset, reload); - cpuc->acr_cfg_c[idx] = reload; + cpuc->cfg_c_val[idx] = reload; } }
@@ -3198,14 +3198,15 @@ static void intel_pmu_enable_event_ext(struct perf_event *event) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events);struct hw_perf_event *hwc = &event->hw; -union arch_pebs_index old, new; -struct arch_pebs_cap cap;u64 ext =0 ; - cap =hybrid (cpuc->pmu, arch_pebs_cap); +if (is_acr_event_group (event)) + ext |= (-hwc->sample_period) &ARCH_PEBS_RELOAD ;if (event->attr.precise_ip) {u64 pebs_data_cfg =intel_get_arch_pebs_data_config (event); +struct arch_pebs_cap cap =hybrid (cpuc->pmu, arch_pebs_cap); +union arch_pebs_index old, new; ext |=ARCH_PEBS_EN ;if (hwc->flags &PERF_X86_EVENT_AUTO_RELOAD )
arch/x86/events/perf_event.h +1 -3
@@ -322,10 +322,8 @@ struct cpu_hw_events {u64 fixed_ctrl_val;u64 active_fixed_ctrl_val; -/* Intel ACR configuration */ +/* Intel ACR/arch-PEBS configuration */ u64 acr_cfg_b[X86_PMC_IDX_MAX ]; -u64 acr_cfg_c[X86_PMC_IDX_MAX ]; -/* Cached CFG_C values */ u64 cfg_c_val[X86_PMC_IDX_MAX ];/*