Re: [PATCH 0/4] powerpc/topology: Introduce llc_override debugfs
flat view
From: Shrikanth Hegde <sshegde@linux.ibm.com>
Date: 2026-10-14 03:16:56
Also in:
lkml
On 10/14/26 2:14 AM, Tim Chen wrote:
On Tue, 2026-10-13 at 15:28 +0530, Shrikanth Hegde wrote:quoted
[snip]quoted
One way to fix it is with a change like below. But more thoughts after the patch. --- arch/powerpc/include/asm/topology.h | 7 +------ arch/powerpc/kernel/smp.c | 23 +++++++++++++++++++++++ include/linux/sched.h | 2 +- kernel/sched/topology.c | 7 +++++++ 4 files changed, 32 insertions(+), 7 deletions(-)diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 44ec416fa489..f4555632e692 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h@@ -135,12 +135,7 @@ struct cpumask *cpu_coregroup_mask(int cpu); const struct cpumask *cpu_die_mask(int cpu); int cpu_die_id(int cpu); -/* - * Points to where the LLC is. On power9 this will point at CACHE - * domain, On others it will point to SMT domain. In all cases - * cpu_l2_cache_mask points to where LLC is - */ -#define arch_llc_mask(cpu) cpu_l2_cache_mask(cpu) +const struct cpumask *arch_llc_mask(int cpu);You will need to add #define arch_llc_mask arch_llc_mask
Yes.
here. Otherwise kernel/sched/topology.c looks for a macro: # ifndef arch_llc_mask #define arch_llc_mask(cpu) cpu_coregroup_mask(cpu) # endif With the #define gone, the generic code falls back to cpu_coregroup_mask().quoted
#ifdef CONFIG_PPC64 #include <asm/smp.h>diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 6a4ee7d3b8e5..139c54fc3e2d 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c@@ -1864,6 +1864,28 @@ void __noreturn arch_cpu_idle_dead(void) #endif +/* + * Points to where the LLC is. On power9 this will point at CACHE + * domain, On others it will point to SMT domain. In all cases + * cpu_l2_cache_mask points to where LLC is. + * + * If there is llc_override debug knob, return appropriate mask + */ +const struct cpumask *arch_llc_mask(int cpu) +{ + switch (READ_ONCE(llc_override)) { + case LLC_OVERRIDE_SMT: + return cpu_smt_mask(cpu); + case LLC_OVERRIDE_MC: + return cpu_coregroup_mask(cpu); + case LLC_OVERRIDE_PKG: + return cpu_die_mask(cpu); + case LLC_OVERRIDE_DISABLED: + default: + return cpu_l2_cache_mask(cpu); + } +} +The mask here has to match the span of the highest SD_SHARE_LLC domain, and there seems to be some mismatches. - PKG: On power pc, seems like cpu_die_mask() returns cpu_coregroup_map when coregroups are supported, if (has_coregroup_support()) return per_cpu(cpu_coregroup_map, cpu); else return cpu_node_mask(cpu); so this is the MC span while sd_llc sits at PKG. It should be cpu_node_mask(), the same as tl_pkg_mask().
facepalm :/
quoted hunk ↗ jump to hunk
- SMT: patch 3 adds SD_SHARE_LLC only to MC/PKG, so for "smt" the flags are as before. I think it is possible for P9 to have shared_caches between two cores: /* * P9 has a slightly odd architecture where pairs of cores share an L2 cache. * This topology makes it *much* cheaper to migrate tasks between adjacent cores * since the migrated task remains cache hot. We want to take advantage of this * at the scheduler level so an extra topology level is required. */ the CACHE level also has SD_SHARE_LLC, and highest_flag_domain() picks it, so sd_llc spans cpu_l2_cache_map. shared_caches is only set when that map is wider than the core's threads, e.g. a P9 core pair sharing an L2: CPU: 0 1 2 3 | 4 5 6 7 cpu_smt_mask(): core A | core B sd_llc (CACHE): 0-7 The ids follow cpu_smt_mask(), so 0-3 and 4-7 get different ids while sd_llc and sd_llc_size cover all eight, and cpus_share_cache(0, 4) is false, which is incorrect.
Yes. I doubt anyone wants to try this experiment on Power9. But yes, functionally updating the flags is needed. @srikar, That is also the reason for having the disabled. By default on P9, llc will be at CACHE domain. But, one may want to experiment with =smt which i doubt anyone will ever do.
quoted
int arch_update_cpu_topology(void) { if (READ_ONCE(llc_override_changed)) {@@ -1923,6 +1945,7 @@ static ssize_t llc_override_set(struct file *file, const char __user *ubuf, pr_info("sched LLC override set to %s. Rebuilding sched domains\n", llc_override_str[override]); + sched_reset_llc_id();The reset here seems racy without taking cpus_read_lock, and taking sched_domains_mutex for each CPU and you could have a cpu hot plug event or cpu set rebuild in between. That's why I would go with the boot parameter. The llc ids are assigned once, with the right mask, so there is nothing to reset or rebuild, no change to kernel/sched/, and everything stays in arch/powerpc. Since this is an experiment knob, needing a reboot to change it is a small cost, and every run starts from a clean state. Tim
Yes. That is what i prefer at this moment too. It will be cleaner. Only thing is, need to get the masks right in different domains.
quoted
rebuild_sched_domains(); }diff --git a/include/linux/sched.h b/include/linux/sched.h index 7b91cae4a59c..4d7e2ee841a9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h@@ -2505,5 +2505,5 @@ extern void migrate_enable(void); #endif /* MODULE */ DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) - +void sched_reset_llc_id(void); #endifdiff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index dd2b1d70ec9d..63c9bca4c5eb 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c@@ -3087,6 +3087,13 @@ void sched_domains_free_llc_id(int cpu) sched_domains_mutex_unlock(); } +void sched_reset_llc_id(void) +{ + int cpu; + + for_each_online_cpu(cpu) + sched_domains_free_llc_id(cpu); +} /* * Build sched domains for a given set of CPUs and attach the sched domains * to the individual CPUs