Re: Cache-aware scheduling does not work well with amd big/little cores

From: Tim Chen

Date: Fri Sep 25 2026 - 15:21:22 EST


On Fri, 2026-09-25 at 10:59 +0200, Klaus Kusche wrote:
> On 24/09/2026 01:47, Tim Chen wrote:
> > Hi Klaus,
> >
> > I wonder if you can try this alternate patch to Chen Yu's.
> > This patch does not require turning off cache aware scheduling
> > entirely as in the previous patch when using the asym packing
> > mechanism to prioritize big core.
>
> Hello,
>
> 1.) This patch applies with quite some fuzz to 7.2.7 (for example,
> the context of the -10847,6+10849,10 hunk is obviously different),
> and the resulting fair.c fails to compile:
> call to undeclared function 'sched_use_asym_prio'
> conflicting types for 'sched_use_asym_prio'
> (sched_use_asym_prio is called before being declared)
> use of undeclared identifier 'env'


Thanks a lot for applying the patch and reporting back so quickly.

You are right, and the fuzz is the cause of the build failure. I
generated the original patch on top of Peter's sched/urgent tree,
where fair.c is laid out differently
from 7.2.7. The interface to can_migrate_llc() has been
modified to use "env" in Peter's tree.

I rebased the change onto v7.2.7 for you to test. It now applies cleanly with
git am and builds. Two things differ on v7.2.7, so this is a real
backport rather than the same diff:

- can_migrate_llc_task() takes (src_cpu, dst_cpu, p) here instead of
an lb_env, so I pass the sched_domain in explicitly and update its
one caller.
- llc_balance() has no SD_ASYM_CPUCAPACITY misfit early-out on v7.2.7,
so the new asym check is placed after the SD_SHARE_LLC check.

You can either test with the previous patch on sched/urgent
(https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/log/?h=sched/urgent)
or use the backported patch attached to the end of the mail.

>
> 2.) As far as I know, "inline" does not look ahead in C.
> So I think the call to sched_asym you added in hunk -10847,6+10849,10
> will result in a real call, not in inline code
> (at least without optimization), because the code of sched_asym
> is not yet known at the position of that call.


Good point to raise, but that part is not the problem. Whether the call
is inlined is only an optimization and should not affect whether the code
compiles: a static inline function that is forward-declared and defined
later in the same file is valid C. I checked my disassembled code
and find that sched_asym() in indeed inlined.

There are other function in fair.c already with similar declaration
for cfs_rq_max_slice(), account_mm_sched(), and others.

Could you give it a try on your system?

Thanks again for testing on your hardware.

Tim

---
From: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>
Date: Wed, 23 Sep 2026 14:28:40 -0700
Subject: [PATCH] sched/cache: Honor asym packing over cache aware scheduling
on hybrid system

A regression was reported on an AMD Ryzen AI HX 370 running a cache
intensive Clang full-LTO link. The little cores run at a much lower
frequency (3.3 GHz vs 5.1 GHz) and have only half of the L3 cache
(8 MB vs 16 MB), so pinning such a task to the little-core LLC hurts
twice, and full-LTO builds slow down dramatically compared to
pre-cache-aware-scheduling kernels.

Asym packing and cache aware scheduling express conflicting placement
strategy. Asym packing wants a task to run on the highest priority
CPU, whereas CAS wants to co-locate the tasks of a process on one LLC
regardless of the priority of CPUs in that LLC. When asym packing
is turned on, it is trying to migrate task to an empty core that has
higher priority than source cpu, let asym packing win.

Reported-by: Klaus Kusche <klaus.kusche@xxxxxxxxxxxxxxx>
Closes: https://lore.kernel.org/lkml/2180ea5a-eb28-4152-8d4d-cd00b0c24b2e@xxxxxxxxxxxxxxx/
Signed-off-by: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>

[ Backport to v7.2.7: can_migrate_llc_task() takes (src_cpu, dst_cpu, p)
here rather than lb_env, so pass the sched_domain in explicitly. Drop
context from task_misfits_asym_cpu() and the SD_ASYM_CPUCAPACITY
misfit check in llc_balance(), which are not present in v7.2.7. ]

---
kernel/sched/fair.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index bb8a5f358ee19..2dae60ad09276 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10575,11 +10575,14 @@ static enum llc_mig can_migrate_llc(int src_cpu, int dst_cpu,
return mig_llc;
}

+static inline bool sched_asym(struct sched_domain *sd, int dst_cpu, int src_cpu);
+
/*
* Check if task p can migrate from source LLC to
* destination LLC in terms of cache aware load balance.
*/
-static enum llc_mig can_migrate_llc_task(int src_cpu, int dst_cpu,
+static enum llc_mig can_migrate_llc_task(struct sched_domain *sd,
+ int src_cpu, int dst_cpu,
struct task_struct *p)
{
struct mm_struct *mm;
@@ -10594,6 +10597,10 @@ static enum llc_mig can_migrate_llc_task(int src_cpu, int dst_cpu,
if (cpu < 0 || cpus_share_cache(src_cpu, dst_cpu))
return mig_unrestricted;

+ /* Prioritize asym packing over cache awareness */
+ if (sched_asym(sd, dst_cpu, src_cpu))
+ return mig_unrestricted;
+
/* skip cache aware load balance for too many threads */
if (invalid_llc_nr(mm, p, dst_cpu) ||
exceed_llc_capacity(mm, dst_cpu)) {
@@ -10689,7 +10696,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu))
return true;

- if (can_migrate_llc_task(env->src_cpu,
+ if (can_migrate_llc_task(env->sd, env->src_cpu,
env->dst_cpu, p) != mig_forbid)
return false;

@@ -11753,6 +11760,15 @@ static inline bool llc_balance(struct lb_env *env, struct sg_lb_stats *sgs,
if (env->sd->flags & SD_SHARE_LLC)
return false;

+ /*
+ * On asym packing domains, if the destination CPU
+ * has higher priority than all CPUs in the source group,
+ * prioritize asym packing.
+ */
+ if ((env->sd->flags & SD_ASYM_PACKING) &&
+ sgs->group_asym_packing)
+ return false;
+
/*
* Skip cache aware tagging if nr_balanced_failed is sufficiently high.
* Threshold of cache_nice_tries is set to 1 higher than nr_balance_failed
@@ -13140,12 +13156,12 @@ static int need_active_balance(struct lb_env *env)
{
struct sched_domain *sd = env->sd;

- if (alb_break_llc(env))
- return 0;
-
if (asym_active_balance(env))
return 1;

+ if (alb_break_llc(env))
+ return 0;
+
if (imbalanced_active_balance(env))
return 1;

--
2.32.0