Re: [RFC PATCH 2/7] fs/resctrl: Add the L2 monitor events

From: Ben Horgan

Date: Mon Oct 26 2026 - 08:15:36 EST


Hi Jinjie,

On 22/10/2026 09:48, Jinjie Ruan wrote:
> Add the L2 cache occupancy (l2c_occupancy) and L2 bandwidth
> (mbm_core_bytes) monitor events, and route RDT_RESOURCE_L2 through the
> same per-domain read path as the L3.
>
> As ARM MPAM Specification said, MPAM resource monitors are associated
> with a shared partitionable resource in an MSC, not with a particular
> cache level: the level comes from firmware's description of the MSC.
> L2 monitors were only missing a resctrl scope. The events are
> exposed once an architecture reports the L2 resource
> mon_capable; x86 never does.
>
> Update Documentation/arch/arm64/mpam.rst to mention L2.
>
> Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
> ---
> Documentation/arch/arm64/mpam.rst | 23 ++++++++++++++---------
> fs/resctrl/monitor.c | 9 +++++++++
> include/linux/resctrl_types.h | 13 ++++++++++++-
> 3 files changed, 35 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/arch/arm64/mpam.rst b/Documentation/arch/arm64/mpam.rst
> index 67fe515ed501..f0697dedde03 100644
> --- a/Documentation/arch/arm64/mpam.rst
> +++ b/Documentation/arch/arm64/mpam.rst
> @@ -32,8 +32,9 @@ Because the user interface to MPAM is via resctrl, only MPAM features that are
> compatible with resctrl can be exposed to user-space.
>
> MSC are considered as a group based on the topology. MSC that correspond with
> -the L3 cache are considered together, it is not possible to mix MSC between L2
> -and L3 to 'cover' a resctrl schema.
> +the L3 cache are considered together, as are MSC that correspond with the L2
> +cache; it is not possible to mix MSC between L2 and L3 to 'cover' a resctrl
> +schema.
>
> The supported features are:
>
> @@ -61,9 +62,11 @@ The supported features are:
> When the MPAM driver finds multiple groups of MSC it can use for the 'MB'
> schema, it prefers the group closest to the L3 cache.
>
> -* Cache Storage Usage (CSU) counters can expose the 'llc_occupancy' provided
> - there is at least one CSU monitor on each MSC that makes up the L3 group.
> - Exposing CSU counters from other caches or devices is not supported.
> +* Cache Storage Usage (CSU) counters expose the occupancy of the cache they
> + monitor: 'llc_occupancy' for the L3 group and 'l2c_occupancy' for the L2
> + group, provided there is at least one CSU monitor on each MSC that makes up
> + the group. Exposing CSU counters from other caches or devices is not
> + supported.
>
> * Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
> L3 cache-id to identify where the memory bandwidth is measured. For this
> @@ -82,10 +85,12 @@ The supported features are:
> have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
> cannot distinguish local traffic from global traffic.
>
> - All these restrictions based on L3 cache are due to resctrl, currently, only
> - supporting monitoring at the L3 scope. It is expected that going forward more
> - MBWU monitors can be exposed to the user after support for more monitoring
> - scopes is added to resctrl.
> + MBWU monitors on an L2 MSC expose the bandwidth the cache sees as the
> + 'mbm_core_bytes' event on the L2 resource.
> +
> + These restrictions are due to resctrl only supporting monitoring at the L2
> + and L3 cache scopes. MBWU monitors on caches at other levels, or on devices,
> + are not exposed.
>
> Reporting Bugs
> ==============
> diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
> index f9f4d4486c1b..ee296c27c6e8 100644
> --- a/fs/resctrl/monitor.c
> +++ b/fs/resctrl/monitor.c
> @@ -543,6 +543,13 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
> return __mon_event_count_one_domain(rdtgrp, rr);
> else
> return __l3_mon_event_count_sum(rdtgrp, rr);
> + case RDT_RESOURCE_L2:
> + WARN_ON_ONCE(rr->evt->any_cpu);
> + if (WARN_ON_ONCE(!rr->hdr)) {
> + rr->err = -EINVAL;
> + return -EINVAL;
> + }
> + return __mon_event_count_one_domain(rdtgrp, rr);
> case RDT_RESOURCE_PERF_PKG: {
> u64 tval = 0;
>
> @@ -1032,6 +1039,8 @@ struct mon_evt mon_event_all[QOS_NUM_EVENTS] = {
> MON_EVENT(QOS_L3_OCCUP_EVENT_ID, "llc_occupancy", RDT_RESOURCE_L3, false),
> MON_EVENT(QOS_L3_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", RDT_RESOURCE_L3, false),
> MON_EVENT(QOS_L3_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", RDT_RESOURCE_L3, false),
> + MON_EVENT(QOS_L2_OCCUP_EVENT_ID, "l2c_occupancy", RDT_RESOURCE_L2, false),
> + MON_EVENT(QOS_L2_MBM_CORE_EVENT_ID, "mbm_core_bytes", RDT_RESOURCE_L2, false),
> MON_EVENT(PMT_EVENT_ENERGY, "core_energy", RDT_RESOURCE_PERF_PKG, true),
> MON_EVENT(PMT_EVENT_ACTIVITY, "activity", RDT_RESOURCE_PERF_PKG, true),
> MON_EVENT(PMT_EVENT_STALLS_LLC_HIT, "stalls_llc_hit", RDT_RESOURCE_PERF_PKG, false),
> diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h
> index a5f56faa18d2..f31b8f2ccb8b 100644
> --- a/include/linux/resctrl_types.h
> +++ b/include/linux/resctrl_types.h
> @@ -37,7 +37,14 @@
> /* Number of memory transactions that an MBM event can be configured with */
> #define NUM_MBM_TRANSACTIONS 7
>
> -/* Event IDs */
> +/*
> + * Monitor Event IDs, representative a variety of monitoring events:
> + * QOS_L3_OCCUP_EVENT_ID: L3 Cache Occupancy statistics event
> + * QOS_L3_MBM_TOTAL_EVENT_ID: Global Memory Bandwidth statistics event
> + * QOS_L3_MBM_LOCAL_EVENT_ID: L3 Cache Bandwidth statistics event
> + * QOS_L2_OCCUP_EVENT_ID: L2 Cache Occupancy statistics event
> + * QOS_L2_MBM_CORE_EVENT_ID: L2 Cache Bandwidth statistics event
> + */
> enum resctrl_event_id {
> /* Must match value of first event below */
> QOS_FIRST_EVENT = 0x01,
> @@ -50,6 +57,10 @@ enum resctrl_event_id {
> QOS_L3_MBM_TOTAL_EVENT_ID = 0x02,
> QOS_L3_MBM_LOCAL_EVENT_ID = 0x03,
>
> + /* ARM MPAM L2 Events */
> + QOS_L2_OCCUP_EVENT_ID,
> + QOS_L2_MBM_CORE_EVENT_ID,

These are essentially, L2 versions of L3 events. Does it not make sense to generalize the existing
events to apply in different scopes?

Thanks,

Ben

> +
> /* Intel Telemetry Events */
> PMT_EVENT_ENERGY,
> PMT_EVENT_ACTIVITY,