perf/x86/intel/uncore: Add per-scheduler IMC CAS count events
Subsystems (3)
PATCH 1/1 perf/x86/intel/uncore: Add per-scheduler IMC CAS count events
IMC on SPR and EMR does not support sub-channels. In contrast, CPUs that use gnr_uncores[] (e.g. Granite Rapids and Sierra Forest) implement two command schedulers (SCH0/SCH1) per memory channel, providing logically independent command and data paths.
Do not reuse the spr_uncore_imc[] configuration for these CPUs. Instead, introduce a dedicated gnr_uncore_imc[] with per-scheduler events, so userspace can monitor SCH0 and SCH1 independently.
On these CPUs, replace cas_count_{read,write} with cas_count_{read,write}_sch{0,1}. This may break existing userspace that relies on cas_count_{read,write}, prompting it to switch to the per-scheduler events, as the legacy event reports only partial traffic (SCH0).
--- arch/x86/events/intel/uncore_snbep.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
arch/x86/events/intel/uncore_snbep.c +27 -1
@@ -6640,6 +6640,32 @@ static struct intel_uncore_type gnr_uncore_ubox = { .attr_update = uncore_alias_groups, }; +static struct uncore_event_desc gnr_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0x01,umask=0x00" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0,"event=0x05,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1,"event=0x06,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0,"event=0x05,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1,"event=0x06,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.unit,"MiB" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_type gnr_uncore_imc = { +SPR_UNCORE_MMIO_COMMON_FORMAT (), + .name ="imc" , + .fixed_ctr_bits =48 , + .fixed_ctr =SNR_IMC_MMIO_PMON_FIXED_CTR , + .fixed_ctl =SNR_IMC_MMIO_PMON_FIXED_CTL , + .event_descs = gnr_uncore_imc_events, +}; +static struct intel_uncore_type gnr_uncore_pciex8 = {SPR_UNCORE_PCI_COMMON_FORMAT (), .name ="pciex8" ,
@@ -6687,7 +6713,7 @@ static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = {NULL , &spr_uncore_pcu, &gnr_uncore_ubox, - &spr_uncore_imc, + &gnr_uncore_imc,NULL , &gnr_uncore_upi, NULL,
Signature · 1 line
2.52.0
Quoted 62 lines · Zide Chen
IMC on SPR and EMR does not support sub-channels. In contrast, CPUs that use gnr_uncores[] (e.g. Granite Rapids and Sierra Forest) implement two command schedulers (SCH0/SCH1) per memory channel, providing logically independent command and data paths.
Do not reuse the spr_uncore_imc[] configuration for these CPUs. Instead, introduce a dedicated gnr_uncore_imc[] with per-scheduler events, so userspace can monitor SCH0 and SCH1 independently.
On these CPUs, replace cas_count_{read,write} with cas_count_{read,write}_sch{0,1}. This may break existing userspace that relies on cas_count_{read,write}, prompting it to switch to the per-scheduler events, as the legacy event reports only partial traffic (SCH0).
Reported-by Reinette Chatre <[email protected]>Fixes 632c4bf6d007 ("perf/x86/intel/uncore: Support Granite Rapids")Fixes cb4a6ccf3583 ("perf/x86/intel/uncore: Support Sierra Forest and Grand Ridge")Signed-off-by Zide Chen <[email protected]>--- arch/x86/events/intel/uncore_snbep.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)arch/x86/events/intel/uncore_snbep.c +26
-0@@ -6640,6 +6640,32 @@ static struct intel_uncore_type gnr_uncore_ubox = { .attr_update = uncore_alias_groups, }; +static struct uncore_event_desc gnr_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0x01,umask=0x00" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0,"event=0x05,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1,"event=0x06,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0,"event=0x05,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1,"event=0x06,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.unit,"MiB" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_type gnr_uncore_imc = { +SPR_UNCORE_MMIO_COMMON_FORMAT (), + .name ="imc" , + .fixed_ctr_bits =48 , + .fixed_ctr =SNR_IMC_MMIO_PMON_FIXED_CTR , + .fixed_ctl =SNR_IMC_MMIO_PMON_FIXED_CTL , + .event_descs = gnr_uncore_imc_events, +}; +static struct intel_uncore_type gnr_uncore_pciex8 = {SPR_UNCORE_PCI_COMMON_FORMAT (), .name ="pciex8" ,
arch/x86/events/intel/uncore_snbep.c static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = { · line 6719
Quoted 8 lines
arch/x86/events/intel/uncore_snbep.c +1
-1@@ -6687,7 +6713,7 @@ static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = {NULL , &spr_uncore_pcu, &gnr_uncore_ubox, - &spr_uncore_imc, + &gnr_uncore_imc,NULL , &gnr_uncore_upi, NULL,
Quoted 15 lines · Zide Chen
IMC on SPR and EMR does not support sub-channels. In contrast, CPUs that use gnr_uncores[] (e.g. Granite Rapids and Sierra Forest) implement two command schedulers (SCH0/SCH1) per memory channel, providing logically independent command and data paths.
Do not reuse the spr_uncore_imc[] configuration for these CPUs. Instead, introduce a dedicated gnr_uncore_imc[] with per-scheduler events, so userspace can monitor SCH0 and SCH1 independently.
On these CPUs, replace cas_count_{read,write} with cas_count_{read,write}_sch{0,1}. This may break existing userspace that relies on cas_count_{read,write}, prompting it to switch to the per-scheduler events, as the legacy event reports only partial traffic (SCH0).
Quoted 6 lines
Reported-by Reinette Chatre <[email protected]>Fixes 632c4bf6d007 ("perf/x86/intel/uncore: Support Granite Rapids")Fixes cb4a6ccf3583 ("perf/x86/intel/uncore: Support Sierra Forest and Grand Ridge")Signed-off-by Zide Chen <[email protected]>---
The resctrl selftests compare the read memory bandwidth reported by iMC PMUs against resctrl's memory bandwidth monitoring (MBM) numbers. These tests are failing on Granite Rapids and Sierra Forest because the tests use the event/umask obtained from
/sys/bus/event_source/devices/uncore_imc_N/events/cas_count_read
that only measures about half the bandwidth reported by MBM.
When using this patch and adapting [1] the resctrl selftests to use the new interface to learn about the additional events it is possible to get the accurate iMC PMU memory bandwidth measurements that match values reported by MBM.
Thank you very much!
Reinette
The following commit has been merged into the perf/urgent branch of tip:
The following commit has been merged into the perf/urgent branch of tip:
Commit-ID: 6a8a48644c4b804123e59dbfc5d6cd29a0194046 Gitweb: https://git.kernel.org/tip/6a8a48644c4b804123e59dbfc5d6cd29a0194046 Author: Zide Chen <[email protected]> AuthorDate: Mon, 09 Feb 2026 16:52:25 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 23 Feb 2026 11:19:25 +01:00
perf/x86/intel/uncore: Add per-scheduler IMC CAS count events
IMC on SPR and EMR does not support sub-channels. In contrast, CPUs that use gnr_uncores[] (e.g. Granite Rapids and Sierra Forest) implement two command schedulers (SCH0/SCH1) per memory channel, providing logically independent command and data paths.
Do not reuse the spr_uncore_imc[] configuration for these CPUs. Instead, introduce a dedicated gnr_uncore_imc[] with per-scheduler events, so userspace can monitor SCH0 and SCH1 independently.
On these CPUs, replace cas_count_{read,write} with cas_count_{read,write}_sch{0,1}. This may break existing userspace that relies on cas_count_{read,write}, prompting it to switch to the per-scheduler events, as the legacy event reports only partial traffic (SCH0).
--- arch/x86/events/intel/uncore_snbep.c | 28 ++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
arch/x86/events/intel/uncore_snbep.c +27 -1
@@ -6497,6 +6497,32 @@ static struct intel_uncore_type gnr_uncore_ubox = { .attr_update = uncore_alias_groups, }; +static struct uncore_event_desc gnr_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0x01,umask=0x00" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0,"event=0x05,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1,"event=0x06,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0,"event=0x05,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1,"event=0x06,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.unit,"MiB" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_type gnr_uncore_imc = { +SPR_UNCORE_MMIO_COMMON_FORMAT (), + .name ="imc" , + .fixed_ctr_bits =48 , + .fixed_ctr =SNR_IMC_MMIO_PMON_FIXED_CTR , + .fixed_ctl =SNR_IMC_MMIO_PMON_FIXED_CTL , + .event_descs = gnr_uncore_imc_events, +}; +static struct intel_uncore_type gnr_uncore_pciex8 = {SPR_UNCORE_PCI_COMMON_FORMAT (), .name ="pciex8" ,
@@ -6544,7 +6570,7 @@ static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = {NULL , &spr_uncore_pcu, &gnr_uncore_ubox, - &spr_uncore_imc, + &gnr_uncore_imc,NULL , &gnr_uncore_upi, NULL,