RE: [PATCH v2 7/7] x86/resctrl: Determine if Sub-NUMA Cluster is enabled and initialize.

From: Shaopeng Tan (Fujitsu)
Date: Thu Jun 29 2023 - 03:35:43 EST


Hi Tony,

> There isn't a simple hardware enumeration to indicate to software that a
> system is running with Sub-NUMA Cluster enabled.
>
> Compare the number of NUMA nodes with the number of L3 caches to calculate
> the number of Sub-NUMA nodes per L3 cache.
>
> When Sub-NUMA cluster mode is enabled in BIOS setup the RMID counters are
> distributed equally between the SNC nodes within each socket.
>
> E.g. if there are 400 RMID counters, and the system is configured with two SNC
> nodes per socket, then RMID counter 0..199 are used on SNC node
> 0 on the socket, and RMID counter 200..399 on SNC node 1.
>
> A model specific MSR (0xca0) can change the configuration of the RMIDs when
> SNC mode is enabled.
>
> The MSR controls the interpretation of the RMID field in the IA32_PQR_ASSOC
> MSR so that the appropriate hardware counters within the SNC node are
> updated.
>
> Also initialize a per-cpu RMID offset value. Use this to calculate the value to
> write to the IA32_QM_EVTSEL MSR when reading RMID event values.
>
> N.B. this works well for well-behaved NUMA applications that access memory
> predominantly from the local memory node. For applications that access
> memory across multiple nodes it may be necessary for the user to read counters
> for all SNC nodes on a socket and add the values to get the actual LLC
> occupancy or memory bandwidth. Perhaps this isn't all that different from
> applications that span across multiple sockets in a legacy system.
>
> Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx>
> ---
> arch/x86/include/asm/resctrl.h | 2 +
> arch/x86/kernel/cpu/resctrl/core.c | 99
> ++++++++++++++++++++++++++-
> arch/x86/kernel/cpu/resctrl/monitor.c | 2 +-
> 3 files changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
> index 255a78d9d906..f95e69bacc65 100644
> --- a/arch/x86/include/asm/resctrl.h
> +++ b/arch/x86/include/asm/resctrl.h
> @@ -35,6 +35,8 @@ DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
> DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
> DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
>
> +DECLARE_PER_CPU(int, rmid_offset);
> +
> /*
> * __resctrl_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
> *
> diff --git a/arch/x86/kernel/cpu/resctrl/core.c
> b/arch/x86/kernel/cpu/resctrl/core.c
> index af3be3c2db96..869cfb46e8e4 100644
> --- a/arch/x86/kernel/cpu/resctrl/core.c
> +++ b/arch/x86/kernel/cpu/resctrl/core.c
> @@ -16,11 +16,14 @@
>
> #define pr_fmt(fmt) "resctrl: " fmt
>
> +#include <linux/cpu.h>
> #include <linux/slab.h>
> #include <linux/err.h>
> #include <linux/cacheinfo.h>
> #include <linux/cpuhotplug.h>
> +#include <linux/mod_devicetable.h>
>
> +#include <asm/cpu_device_id.h>
> #include <asm/intel-family.h>
> #include <asm/resctrl.h>
> #include "internal.h"
> @@ -524,6 +527,39 @@ static int get_domain_id(int cpu, enum resctrl_scope
> scope)
> }
> }
>
> +DEFINE_PER_CPU(int, rmid_offset);
> +
> +static void set_per_cpu_rmid_offset(int cpu, struct rdt_resource *r) {
> + this_cpu_write(rmid_offset, (cpu_to_node(cpu) % snc_ways) *
> +r->num_rmid); }
> +
> +/*
> + * This MSR provides for configuration of RMIDs on Sub-NUMA Cluster
> + * systems.
> + * Bit0 = 1 (default) For legacy configuration
> + * Bit0 = 0 RMIDs are divided evenly between SNC nodes.
> + */
> +#define MSR_RMID_SNC_CONFIG 0xCA0
> +
> +static void snc_add_pkg(void)
> +{
> + u64 msrval;
> +
> + rdmsrl(MSR_RMID_SNC_CONFIG, msrval);
> + msrval |= BIT_ULL(0);
> + wrmsrl(MSR_RMID_SNC_CONFIG, msrval);
> +}
> +
> +static void snc_remove_pkg(void)
> +{
> + u64 msrval;
> +
> + rdmsrl(MSR_RMID_SNC_CONFIG, msrval);
> + msrval &= ~BIT_ULL(0);
> + wrmsrl(MSR_RMID_SNC_CONFIG, msrval);
> +}
> +
> /*
> * domain_add_cpu - Add a cpu to a resource's domain list.
> *
> @@ -555,6 +591,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource
> *r)
> cpumask_set_cpu(cpu, &d->cpu_mask);
> if (r->cache.arch_has_per_cpu_cfg)
> rdt_domain_reconfigure_cdp(r);
> + if (r->mon_capable)
> + set_per_cpu_rmid_offset(cpu, r);
> return;
> }
>
> @@ -573,11 +611,17 @@ static void domain_add_cpu(int cpu, struct
> rdt_resource *r)
> return;
> }
>
> - if (r->mon_capable && arch_domain_mbm_alloc(r->num_rmid,
> hw_dom)) {
> - domain_free(hw_dom);
> - return;
> + if (r->mon_capable) {
> + if (arch_domain_mbm_alloc(r->num_rmid, hw_dom)) {
> + domain_free(hw_dom);
> + return;
> + }
> + set_per_cpu_rmid_offset(cpu, r);
> }
>
> + if (r->pkg_actions)
> + snc_add_pkg();
> +
> list_add_tail(&d->list, add_pos);
>
> err = resctrl_online_domain(r, d);
> @@ -613,6 +657,9 @@ static void domain_remove_cpu(int cpu, struct
> rdt_resource *r)
> d->plr->d = NULL;
> domain_free(hw_dom);
>
> + if (r->pkg_actions)
> + snc_remove_pkg();
> +
> return;
> }
>
> @@ -899,11 +946,57 @@ static __init bool get_rdt_resources(void)
> return (rdt_mon_capable || rdt_alloc_capable); }
>
> +static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
> + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, 0),
> + X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, 0),
> + X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, 0),
> + {}
> +};

Cascade Lake and Skylake also seem to support Sub-NUMA cluster.
At least in my environment(Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz),
Sub-NUMA cluster is supported.

Best regards,
Shaopeng TAN