[RFC PATCH v2 01/23] sched/topology: Add llc_to_node() to translate LLC id to NUMA node
From: Jianyong Wu <hidden>
Date: 2026-08-27 12:33:20
Also in:
lkml
Subsystem:
scheduler, the rest · Maintainers:
Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Linus Torvalds
Building an LLC affinity/distance matrix requires knowing which NUMA node each LLC belongs to. Add a per-LLC-id -> NUMA-node map (llc_to_node_map) derived from the possible CPU set, and expose it via llc_to_node(). Signed-off-by: Jianyong Wu <redacted> --- include/linux/topology.h | 4 +++ kernel/sched/topology.c | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+)
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 709a2dcf4c73..9967739a180c 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h@@ -177,6 +177,10 @@ static inline int cpu_to_mem(int cpu) #endif /* [!]CONFIG_HAVE_MEMORYLESS_NODES */ +#ifdef CONFIG_SCHED_CACHE +int llc_to_node(int llc); +#endif + #if defined(topology_die_id) && defined(topology_die_cpumask) #define TOPOLOGY_DIE_SYSFS #endif
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 622e2e01974c..c6928c6b17b6 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c@@ -685,6 +685,11 @@ DEFINE_PER_CPU(struct sched_domain __rcu *, sd_asym_cpucapacity); DEFINE_STATIC_KEY_FALSE(sched_asym_cpucapacity); DEFINE_STATIC_KEY_FALSE(sched_cluster_active); +#ifdef CONFIG_SCHED_CACHE +static int __rcu *llc_to_node_map; +static void rebuild_llc_node_map(int size); +#endif + static void update_top_cache_domain(int cpu) { struct sched_domain_shared *sds = NULL;
@@ -856,6 +861,56 @@ DEFINE_STATIC_KEY_FALSE(sched_cache_active); /* user wants cache aware scheduling [0 or 1] */ int sysctl_sched_cache_user = 1; +int llc_to_node(int llc) +{ + int node = -1; + int *map = NULL; + + rcu_read_lock(); + map = rcu_dereference(llc_to_node_map); + if (map && llc >= 0 && llc <= max_lid) + node = map[llc]; + rcu_read_unlock(); + + return node; +} + +static void rebuild_llc_node_map(int size) +{ + int *new_map, *old_map; + u8 *seen_llc; + int cpu, llc; + + new_map = kcalloc(size, sizeof(int), GFP_KERNEL); + if (!new_map) + return; + seen_llc = kcalloc(size, sizeof(*seen_llc), GFP_KERNEL); + if (!seen_llc) { + kfree(new_map); + return; + } + + /* + * for_each_possible_cpu() revisits the same LLC non-consecutively + * under SMT (each node's LLCs are walked once per thread), so + * dedup by llc id via seen_llc[], not by comparing against the + * immediately preceding CPU's llc. + */ + for_each_possible_cpu(cpu) { + llc = per_cpu(sd_llc_id, cpu); + if (llc < 0 || llc >= size || seen_llc[llc]) + continue; + seen_llc[llc] = 1; + new_map[llc] = cpu_to_node(cpu); + } + kfree(seen_llc); + + old_map = rcu_dereference_protected(llc_to_node_map, true); + rcu_assign_pointer(llc_to_node_map, new_map); + synchronize_rcu(); + kfree(old_map); +} + /* * Get the effective LLC size in bytes that @cpu's bottom sched_domain * can use. A CPU within a cpuset partition can only use a proportion
@@ -925,6 +980,7 @@ static bool alloc_sd_llc(const struct cpumask *cpu_map, } } + rebuild_llc_node_map(max_lid + 1); return true; err: for_each_cpu(i, cpu_map) {
--
2.34.1