* [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
@ 2026-08-01 12:17 Lu Wang
0 siblings, 0 replies; 16+ messages in thread
From: Lu Wang @ 2026-08-01 12:17 UTC (permalink / raw)
To: linux-kernel
Cc: mingo, peterz, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, Lu Wang
A passive load-balance pass marks group_llc_balance as migrate_llc_task
and queues active balance when it cannot move a task. The CPU stopper
callback constructs a fresh lb_env, so preserve the migration type on
the runqueue across the asynchronous boundary.
For CAS-directed active balance, reject a candidate whose preferred LLC
does not match the destination LLC. This keeps the fallback from moving
a task away from its preferred LLC.
Fixes: e4c9a4cb244a ("sched/cache: Add migrate_llc_task migration type for cache-aware balancing")
Signed-off-by: Lu Wang <wanglu.priv@gmail.com>
---
kernel/sched/fair.c | 25 ++++++++++++++++++++++---
kernel/sched/sched.h | 1 +
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6..cf036a8a0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10645,6 +10645,18 @@ alb_break_llc(struct lb_env *env)
return false;
}
+/*
+ * Returns true if p's preferred LLC does not match the destination CPU,
+ * meaning this task should not be migrated under migrate_llc_task semantics.
+ */
+static inline bool
+migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
+{
+ return sched_cache_enabled() &&
+ env->migration_type == migrate_llc_task &&
+ READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu);
+}
+
/*
* Check if migrating task p from env->src_cpu to
* env->dst_cpu breaks LLC localiy.
@@ -10673,8 +10685,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
* run on env->dst_cpu, skip the tasks do not prefer
* env->dst_cpu, and find the one that prefers.
*/
- if (env->migration_type == migrate_llc_task &&
- READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu))
+ if (migrate_llc_task_wrong_dst(p, env))
return true;
if (can_migrate_llc_task(env->src_cpu,
@@ -10697,6 +10708,12 @@ alb_break_llc(struct lb_env *env)
return false;
}
+static inline bool
+migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
+{
+ return false;
+}
+
static inline bool
migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
{
@@ -10796,7 +10813,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
* 4) too many balance attempts have failed.
*/
if (env->flags & LBF_ACTIVE_LB)
- return 1;
+ return !migrate_llc_task_wrong_dst(p, env);
degrades = migrate_degrades_locality(p, env);
if (!degrades) {
@@ -13485,6 +13502,7 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
if (!busiest->active_balance) {
busiest->active_balance = 1;
busiest->push_cpu = this_cpu;
+ busiest->active_balance_type = env.migration_type;
active_balance = 1;
}
@@ -13654,6 +13672,7 @@ static int active_load_balance_cpu_stop(void *data)
.src_rq = busiest_rq,
.idle = CPU_IDLE,
.flags = LBF_ACTIVE_LB,
+ .migration_type = (enum migration_type)busiest_rq->active_balance_type,
};
schedstat_inc(sd->alb_count);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 56acf502b..82084d405 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1266,6 +1266,7 @@ struct rq {
/* For active balancing */
int active_balance;
int push_cpu;
+ int active_balance_type; /* enum migration_type */
struct cpu_stop_work active_balance_work;
/* CPU of this runqueue: */
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
@ 2026-08-01 12:22 Lu Wang
2026-08-03 4:20 ` Chen, Yu C
2026-08-06 15:35 ` Chen, Yu C
0 siblings, 2 replies; 16+ messages in thread
From: Lu Wang @ 2026-08-01 12:22 UTC (permalink / raw)
To: linux-kernel
Cc: tim.c.chen, yu.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, Lu Wang
A passive load-balance pass marks group_llc_balance as migrate_llc_task
and queues active balance when it cannot move a task. The CPU stopper
callback constructs a fresh lb_env, so preserve the migration type on
the runqueue across the asynchronous boundary.
For CAS-directed active balance, reject a candidate whose preferred LLC
does not match the destination LLC. This keeps the fallback from moving
a task away from its preferred LLC.
Fixes: e4c9a4cb244a ("sched/cache: Add migrate_llc_task migration type for cache-aware balancing")
Signed-off-by: Lu Wang <wanglu.priv@gmail.com>
---
v2: add Tim Chen and Chen Yu to Cc
kernel/sched/fair.c | 25 ++++++++++++++++++++++---
kernel/sched/sched.h | 1 +
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6..cf036a8a0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10645,6 +10645,18 @@ alb_break_llc(struct lb_env *env)
return false;
}
+/*
+ * Returns true if p's preferred LLC does not match the destination CPU,
+ * meaning this task should not be migrated under migrate_llc_task semantics.
+ */
+static inline bool
+migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
+{
+ return sched_cache_enabled() &&
+ env->migration_type == migrate_llc_task &&
+ READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu);
+}
+
/*
* Check if migrating task p from env->src_cpu to
* env->dst_cpu breaks LLC localiy.
@@ -10673,8 +10685,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
* run on env->dst_cpu, skip the tasks do not prefer
* env->dst_cpu, and find the one that prefers.
*/
- if (env->migration_type == migrate_llc_task &&
- READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu))
+ if (migrate_llc_task_wrong_dst(p, env))
return true;
if (can_migrate_llc_task(env->src_cpu,
@@ -10697,6 +10708,12 @@ alb_break_llc(struct lb_env *env)
return false;
}
+static inline bool
+migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
+{
+ return false;
+}
+
static inline bool
migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
{
@@ -10796,7 +10813,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
* 4) too many balance attempts have failed.
*/
if (env->flags & LBF_ACTIVE_LB)
- return 1;
+ return !migrate_llc_task_wrong_dst(p, env);
degrades = migrate_degrades_locality(p, env);
if (!degrades) {
@@ -13485,6 +13502,7 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
if (!busiest->active_balance) {
busiest->active_balance = 1;
busiest->push_cpu = this_cpu;
+ busiest->active_balance_type = env.migration_type;
active_balance = 1;
}
@@ -13654,6 +13672,7 @@ static int active_load_balance_cpu_stop(void *data)
.src_rq = busiest_rq,
.idle = CPU_IDLE,
.flags = LBF_ACTIVE_LB,
+ .migration_type = (enum migration_type)busiest_rq->active_balance_type,
};
schedstat_inc(sd->alb_count);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 56acf502b..82084d405 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1266,6 +1266,7 @@ struct rq {
/* For active balancing */
int active_balance;
int push_cpu;
+ int active_balance_type; /* enum migration_type */
struct cpu_stop_work active_balance_work;
/* CPU of this runqueue: */
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-01 12:22 [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance Lu Wang
@ 2026-08-03 4:20 ` Chen, Yu C
2026-08-03 10:02 ` Lu Wang
2026-08-06 15:35 ` Chen, Yu C
1 sibling, 1 reply; 16+ messages in thread
From: Chen, Yu C @ 2026-08-03 4:20 UTC (permalink / raw)
To: Lu Wang
Cc: tim.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, linux-kernel, chen.yu@linux.dev
Hi Wang,
Thanks for taking a look at cas,
On 8/1/2026 8:22 PM, Lu Wang wrote:
> A passive load-balance pass marks group_llc_balance as migrate_llc_task
> and queues active balance when it cannot move a task. The CPU stopper
> callback constructs a fresh lb_env, so preserve the migration type on
> the runqueue across the asynchronous boundary.
>
> For CAS-directed active balance, reject a candidate whose preferred LLC
> does not match the destination LLC. This keeps the fallback from moving
> a task away from its preferred LLC.
>
[ ... ]
> static inline bool
> migrate_degrades_llc(struct task_struct *p, struct lb_env *env)
> {
> @@ -10796,7 +10813,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
> * 4) too many balance attempts have failed.
> */
> if (env->flags & LBF_ACTIVE_LB)
> - return 1;
> + return !migrate_llc_task_wrong_dst(p, env);
>
When checking whether active load balance is needed in
need_active_balance(),
alb_break_llc() is called to determine if the balance would break LLC
locality
(i.e., prevent a task from being migrated away from its preferred
LLC). Later
in need_active_balance(), if LLC locality is not broken and the task is of
migrate_llc_task type, we force an active load balance. This means that
once
active load balance reaches can_migrate_task(), we want it to always
return true
- this helps the case where the task is the only running one on the
src_cpu. Given
this logic, I do not see the need for the duplicated LLC-locality check in
can_migrate_task() for active load balance. Am I missing anything here?
thanks,
Chenyu
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-03 4:20 ` Chen, Yu C
@ 2026-08-03 10:02 ` Lu Wang
2026-08-04 0:10 ` Tim Chen
0 siblings, 1 reply; 16+ messages in thread
From: Lu Wang @ 2026-08-03 10:02 UTC (permalink / raw)
To: yu.c.chen
Cc: tim.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, linux-kernel, chen.yu, Lu Wang
Thanks for the review, Chenyu.
I got interested in CAS because it strikes a good balance between
generic CFS load balancing and strict LLC/CPU affinity.
My understanding is that migrate_llc_task encodes the target
direction of the balance pass, not just "ALB was triggered by CAS".
alb_break_llc() only vetoes ALB when every task on src_rq prefers
staying put (nr_pref_llc_running == cfs.h_nr_runnable); once tasks
have mixed preferences it lets ALB through without checking which
one gets picked. active_load_balance_cpu_stop() then walks
src_rq->cfs_tasks in reverse and takes the first task accepted by
can_migrate_task() — with multiple tasks on src_rq, that's not
necessarily the one whose preferred_llc matches the destination.
My patch threads migration_type through to the stopper and, only
for migrate_llc_task, rejects a candidate whose preferred_llc
doesn't match the destination LLC.
Regarding:
> this helps the case where the task is the only running one on the
> src_cpu
If that single task already prefers the destination LLC, my check
still returns true, so this case is unaffected. The disagreement is
really about what happens when it does not prefer the destination.
That comes down to how we read the semantics of migrate_llc_task:
(a) "migrate a task toward the destination LLC selected by
calculate_imbalance()", or
(b) "this ALB was triggered by CAS's LLC-balance logic, so any
generally-eligible task on src_rq may be pushed"
If (a), the per-task check is needed.
Happy to discuss further.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-03 10:02 ` Lu Wang
@ 2026-08-04 0:10 ` Tim Chen
2026-08-04 8:17 ` Chen, Yu C
2026-08-04 8:30 ` Lu Wang
0 siblings, 2 replies; 16+ messages in thread
From: Tim Chen @ 2026-08-04 0:10 UTC (permalink / raw)
To: Lu Wang, yu.c.chen
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu
On Mon, 2026-08-03 at 18:02 +0800, Lu Wang wrote:
> Thanks for the review, Chenyu.
>
> I got interested in CAS because it strikes a good balance between
> generic CFS load balancing and strict LLC/CPU affinity.
>
> My understanding is that migrate_llc_task encodes the target
> direction of the balance pass, not just "ALB was triggered by CAS".
> alb_break_llc() only vetoes ALB when every task on src_rq prefers
> staying put (nr_pref_llc_running == cfs.h_nr_runnable); once tasks
> have mixed preferences it lets ALB through without checking which
> one gets picked. active_load_balance_cpu_stop() then walks
> src_rq->cfs_tasks in reverse and takes the first task accepted by
> can_migrate_task() — with multiple tasks on src_rq, that's not
> necessarily the one whose preferred_llc matches the destination.
>
> My patch threads migration_type through to the stopper and, only
> for migrate_llc_task, rejects a candidate whose preferred_llc
> doesn't match the destination LLC.
>
> Regarding:
> > this helps the case where the task is the only running one on the
> > src_cpu
>
> If that single task already prefers the destination LLC, my check
> still returns true, so this case is unaffected. The disagreement is
> really about what happens when it does not prefer the destination.
> That comes down to how we read the semantics of migrate_llc_task:
>
> (a) "migrate a task toward the destination LLC selected by
> calculate_imbalance()", or
> (b) "this ALB was triggered by CAS's LLC-balance logic, so any
> generally-eligible task on src_rq may be pushed"
The policy of when to break LLC preference locality whether it is in regular
load balance or in active load balance are both encoded in
can_migrate_llc(). Sometimes when an LLC is overloaded, you may
want to move the task off its preferred LLC. Moving a task off its
preferred LLC is not always wrong. Looks like you patch
stop that with migrate_llc_task_wrong_dst().
There is a comment section above can_migrate_llc() to
explain the policy details.
Tim
>
> If (a), the per-task check is needed.
>
> Happy to discuss further.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-04 0:10 ` Tim Chen
@ 2026-08-04 8:17 ` Chen, Yu C
2026-08-04 15:07 ` Lu Wang
2026-08-04 8:30 ` Lu Wang
1 sibling, 1 reply; 16+ messages in thread
From: Chen, Yu C @ 2026-08-04 8:17 UTC (permalink / raw)
To: Tim Chen, Lu Wang
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu
On 8/4/2026 8:10 AM, Tim Chen wrote:
> On Mon, 2026-08-03 at 18:02 +0800, Lu Wang wrote:
>> Thanks for the review, Chenyu.
>>
>> I got interested in CAS because it strikes a good balance between
>> generic CFS load balancing and strict LLC/CPU affinity.
>>
>> My understanding is that migrate_llc_task encodes the target
>> direction of the balance pass, not just "ALB was triggered by CAS".
>> alb_break_llc() only vetoes ALB when every task on src_rq prefers
>> staying put (nr_pref_llc_running == cfs.h_nr_runnable); once tasks
>> have mixed preferences it lets ALB through without checking which
>> one gets picked. active_load_balance_cpu_stop() then walks
>> src_rq->cfs_tasks in reverse and takes the first task accepted by
>> can_migrate_task() — with multiple tasks on src_rq, that's not
>> necessarily the one whose preferred_llc matches the destination.
>>
>> My patch threads migration_type through to the stopper and, only
>> for migrate_llc_task, rejects a candidate whose preferred_llc
>> doesn't match the destination LLC.
>>
>> Regarding:
>>> this helps the case where the task is the only running one on the
>>> src_cpu
>>
>> If that single task already prefers the destination LLC, my check
>> still returns true, so this case is unaffected. The disagreement is
>> really about what happens when it does not prefer the destination.
>> That comes down to how we read the semantics of migrate_llc_task:
>>
>> (a) "migrate a task toward the destination LLC selected by
>> calculate_imbalance()", or
>> (b) "this ALB was triggered by CAS's LLC-balance logic, so any
>> generally-eligible task on src_rq may be pushed"
>
> The policy of when to break LLC preference locality whether it is in regular
> load balance or in active load balance are both encoded in
> can_migrate_llc(). Sometimes when an LLC is overloaded, you may
> want to move the task off its preferred LLC. Moving a task off its
> preferred LLC is not always wrong. Looks like you patch
> stop that with migrate_llc_task_wrong_dst().
> There is a comment section above can_migrate_llc() to
> explain the policy details.
>
Yes. Besides, if I understand correctly, I suppose Lu Wang was
referring to the following scenario:
src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
set because src_rq has at least one task, p1, that wants to migrate
to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
thus moves p2 out of its preferred LLC.
Here is the reason that it might not happen IMO:
Firstly, before ALB is triggered, the generic (passive) load balance is
triggered.
It iterates over p1 and p2 on src_rq to see if it can move any one of
them to
dst_rq, and in most cases it succeeds in moving p1 to dst_cpu. As a
result, ALB
will not be triggered. So the scenario Lu Wang was worried about will
not happen.
On the other hand, even if there is only p2 running on src_cpu and it
prefers
src_cpu (src_llc), the passive load balance will fail, and ALB will be
triggered.
However, alb_break_llc() will return true because p2 wants to stay and
it is the
only running task, so ALB will not be triggered neither. So the scenario
Lu Wang
worried about will not happen.
thanks,
Chenyu
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-04 0:10 ` Tim Chen
2026-08-04 8:17 ` Chen, Yu C
@ 2026-08-04 8:30 ` Lu Wang
1 sibling, 0 replies; 16+ messages in thread
From: Lu Wang @ 2026-08-04 8:30 UTC (permalink / raw)
To: tim.c.chen
Cc: bsegall, chen.yu, dietmar.eggemann, juri.lelli, kprateek.nayak,
linux-kernel, mgorman, mingo, peterz, rostedt, vincent.guittot,
vschneid, yu.c.chen, Lu Wang
Thanks, Tim.
On Mon, 2026-08-03 at 17:10 -0700, Tim Chen wrote:
> On Mon, 2026-08-03 at 18:02 +0800, Lu Wang wrote:
> > Thanks for the review, Chenyu.
> >
> > I got interested in CAS because it strikes a good balance between
> > generic CFS load balancing and strict LLC/CPU affinity.
> >
> > My understanding is that migrate_llc_task encodes the target
> > direction of the balance pass, not just "ALB was triggered by CAS".
> > alb_break_llc() only vetoes ALB when every task on src_rq prefers
> > staying put (nr_pref_llc_running == cfs.h_nr_runnable); once tasks
> > have mixed preferences it lets ALB through without checking which
> > one gets picked. active_load_balance_cpu_stop() then walks
> > src_rq->cfs_tasks in reverse and takes the first task accepted by
> > can_migrate_task() — with multiple tasks on src_rq, that's not
> > necessarily the one whose preferred_llc matches the destination.
> >
> > My patch threads migration_type through to the stopper and, only
> > for migrate_llc_task, rejects a candidate whose preferred_llc
> > doesn't match the destination LLC.
> >
> > Regarding:
> > > this helps the case where the task is the only running one on the
> > > src_cpu
> >
> > If that single task already prefers the destination LLC, my check
> > still returns true, so this case is unaffected. The disagreement is
> > really about what happens when it does not prefer the destination.
> > That comes down to how we read the semantics of migrate_llc_task:
> >
> > (a) "migrate a task toward the destination LLC selected by
> > calculate_imbalance()", or
> > (b) "this ALB was triggered by CAS's LLC-balance logic, so any
> > generally-eligible task on src_rq may be pushed"
>
> The policy of when to break LLC preference locality whether it is in
> regular load balance or in active load balance are both encoded in
> can_migrate_llc(). Sometimes when an LLC is overloaded, you may
> want to move the task off its preferred LLC. Moving a task off its
> preferred LLC is not always wrong. Looks like you patch
> stop that with migrate_llc_task_wrong_dst().
> There is a comment section above can_migrate_llc() to
> explain the policy details.
To clarify the scope: my patch only adds a stricter check for the
migrate_llc_task type during migration.
llc_balance() triggers this classification as long as there are
tasks whose preferred LLC is the destination, independent of load
or utilization. So it sits at the end of the balancing priority
chain. The comment above group_llc_balance's priority assignment,
which you wrote, says:
"The priority of group_llc_balance is lower than that of
[other types]... This is because group_llc_balance may
exacerbate load imbalance."
This makes clear that group_llc_balance was not designed to correct
load imbalance — it explicitly acknowledges it may worsen it.
For the other migration types that do address load imbalance
(migrate_load, migrate_util, migrate_task, migrate_misfit), my patch
doesn't change their logic at all — the check only fires when
env->migration_type == migrate_llc_task.
Is my understanding incorrect here?
Wang
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-04 8:17 ` Chen, Yu C
@ 2026-08-04 15:07 ` Lu Wang
2026-08-04 19:42 ` Tim Chen
0 siblings, 1 reply; 16+ messages in thread
From: Lu Wang @ 2026-08-04 15:07 UTC (permalink / raw)
To: yu.c.chen
Cc: tim.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, linux-kernel, chen.yu, Lu Wang
Thanks, Chenyu.
On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
> Yes. Besides, if I understand correctly, I suppose Lu Wang was
> referring to the following scenario:
>
> src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
> while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
> set because src_rq has at least one task, p1, that wants to migrate
> to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
> thus moves p2 out of its preferred LLC.
That's exactly the scenario I had in mind.
> Firstly, before ALB is triggered, the generic (passive) load balance is
> triggered. It iterates over p1 and p2 on src_rq to see if it can move any
> one of them to dst_rq, and in most cases it succeeds in moving p1 to
> dst_cpu. As a result, ALB will not be triggered.
My question is whether p1 is guaranteed to be moved out in passive
LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
with nr_balance_failed still below cache_nice_tries, or
can_migrate_llc_task() returning something other than mig_forbid due
to capacity constraints on dst_llc at that instant. If passive LB
rejects p1 for any of these, ALB is still triggered with p1 and p2
both present on src_rq.
Can we conclude that p1 and p2 never end up on src_rq together when
ALB fires? Or would it help to set up a simple experiment and trace
this path to see whether it actually occurs in practice?
Wang
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-04 15:07 ` Lu Wang
@ 2026-08-04 19:42 ` Tim Chen
2026-08-05 2:38 ` wanglu15
0 siblings, 1 reply; 16+ messages in thread
From: Tim Chen @ 2026-08-04 19:42 UTC (permalink / raw)
To: Lu Wang, yu.c.chen
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu
On Tue, 2026-08-04 at 23:07 +0800, Lu Wang wrote:
> Thanks, Chenyu.
>
> On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
> > Yes. Besides, if I understand correctly, I suppose Lu Wang was
> > referring to the following scenario:
> >
> > src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
> > while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
> > set because src_rq has at least one task, p1, that wants to migrate
> > to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
> > thus moves p2 out of its preferred LLC.
>
> That's exactly the scenario I had in mind.
>
> > Firstly, before ALB is triggered, the generic (passive) load balance is
> > triggered. It iterates over p1 and p2 on src_rq to see if it can move any
> > one of them to dst_rq, and in most cases it succeeds in moving p1 to
> > dst_cpu. As a result, ALB will not be triggered.
>
> My question is whether p1 is guaranteed to be moved out in passive
> LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
> several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
> with nr_balance_failed still below cache_nice_tries, or
> can_migrate_llc_task() returning something other than mig_forbid due
> to capacity constraints on dst_llc at that instant. If passive LB
> rejects p1 for any of these, ALB is still triggered with p1 and p2
> both present on src_rq.
>
> Can we conclude that p1 and p2 never end up on src_rq together when
> ALB fires? Or would it help to set up a simple experiment and trace
> this path to see whether it actually occurs in practice?
>
>
With 2 tasks on rq with different preference, active load balance could
pick the wrong task as can_migrate_task() checked in active load balance
will not consult migrate_degrades_llc(). How about the following patch
to fix this issue.
Tim
---
sched/cache: skip active load balance for LLC-motivated imbalance
For a migrate_llc_task imbalance, ALB runs detach_one_task() with
LBF_ACTIVE_LB set, which makes can_migrate_task() return early before
migrate_degrades_llc() is consulted. The victim is then the first
eligible task at the tail of cfs_tasks, regardless of LLC preference, so
ALB can pull a task that prefers the source LLC - the opposite of the
intent.
Skip ALB for migrate_llc_task when more than one CFS task is runnable,
and let a later balance pass pull a task that prefers the destination
LLC. With a single runnable task ALB is retained: that task prefers the
destination LLC and cannot migrate otherwise. Other ALB reasons (asym,
misfit, imbalanced, capacity) arrive with a different migration_type and
are unaffected.
Reported-by: Lu Wang <wanglu.priv@gmail.com>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
---
kernel/sched/fair.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..615c9aeab621 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10642,6 +10642,19 @@ alb_break_llc(struct lb_env *env)
return true;
}
+ /*
+ * When the imbalance is for migrate_llc_task, the ALB victim is
+ * chosen by can_migrate_task() under LBF_ACTIVE_LB, which ignores
+ * LLC preference and may pull a task that prefers the source LLC.
+ * Skip ALB when more than one CFS task is runnable, and let a
+ * later balance pass pull a task that prefers the destination LLC
+ * instead. With a single runnable task, ALB is still needed: that
+ * task prefers the destination LLC and cannot migrate otherwise.
+ */
+ if (env->migration_type == migrate_llc_task &&
+ env->src_rq->cfs.h_nr_runnable > 1)
+ return true;
+
return false;
}
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-04 19:42 ` Tim Chen
@ 2026-08-05 2:38 ` wanglu15
2026-08-05 16:04 ` Tim Chen
0 siblings, 1 reply; 16+ messages in thread
From: wanglu15 @ 2026-08-05 2:38 UTC (permalink / raw)
To: tim.c.chen
Cc: yu.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, linux-kernel, chen.yu, Lu Wang
From: Lu Wang <wanglu.priv@gmail.com>
Thanks, Tim.
On Tue, 2026-08-04 at 12:42 -0700, Tim Chen wrote:
> On Tue, 2026-08-04 at 23:07 +0800, Lu Wang wrote:
> > Thanks, Chenyu.
> >
> > On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
> > > Yes. Besides, if I understand correctly, I suppose Lu Wang was
> > > referring to the following scenario:
> > >
> > > src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
> > > while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
> > > set because src_rq has at least one task, p1, that wants to migrate
> > > to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
> > > thus moves p2 out of its preferred LLC.
> >
> > That's exactly the scenario I had in mind.
> >
> > > Firstly, before ALB is triggered, the generic (passive) load balance is
> > > triggered. It iterates over p1 and p2 on src_rq to see if it can move any
> > > one of them to dst_rq, and in most cases it succeeds in moving p1 to
> > > dst_cpu. As a result, ALB will not be triggered.
> >
> > My question is whether p1 is guaranteed to be moved out in passive
> > LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
> > several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
> > with nr_balance_failed still below cache_nice_tries, or
> > can_migrate_llc_task() returning something other than mig_forbid due
> > to capacity constraints on dst_llc at that instant. If passive LB
> > rejects p1 for any of these, ALB is still triggered with p1 and p2
> > both present on src_rq.
> >
> > Can we conclude that p1 and p2 never end up on src_rq together when
> > ALB fires? Or would it help to set up a simple experiment and trace
> > this path to see whether it actually occurs in practice?
>
> With 2 tasks on rq with different preference, active load balance could
> pick the wrong task as can_migrate_task() checked in active load balance
> will not consult migrate_degrades_llc(). How about the following patch
> to fix this issue.
>
> [...]
>
> + if (env->migration_type == migrate_llc_task &&
> + env->src_rq->cfs.h_nr_runnable > 1)
> + return true;
> +
> return false;
> }
Your approach is simpler than mine — it avoids threading
migration_type across the CPU stopper boundary and doesn't need any
new rq field.
One thing I'd like to flag, IMO: this approach skips the ALB path
entirely for migrate_llc_task whenever more than one task is
runnable, deferring the fix to the next passive LB pass. So it
trades "delay" for a simpler implementation.
Wang
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-05 2:38 ` wanglu15
@ 2026-08-05 16:04 ` Tim Chen
2026-08-05 16:43 ` Chen, Yu C
0 siblings, 1 reply; 16+ messages in thread
From: Tim Chen @ 2026-08-05 16:04 UTC (permalink / raw)
To: wanglu15
Cc: yu.c.chen, peterz, mingo, juri.lelli, vincent.guittot,
dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, linux-kernel, chen.yu
On Wed, 2026-08-05 at 10:38 +0800, wanglu15 wrote:
> From: Lu Wang <wanglu.priv@gmail.com>
>
> Thanks, Tim.
>
> On Tue, 2026-08-04 at 12:42 -0700, Tim Chen wrote:
> > On Tue, 2026-08-04 at 23:07 +0800, Lu Wang wrote:
> > > Thanks, Chenyu.
> > >
> > > On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
> > > > Yes. Besides, if I understand correctly, I suppose Lu Wang was
> > > > referring to the following scenario:
> > > >
> > > > src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
> > > > while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
> > > > set because src_rq has at least one task, p1, that wants to migrate
> > > > to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
> > > > thus moves p2 out of its preferred LLC.
> > >
> > > That's exactly the scenario I had in mind.
> > >
> > > > Firstly, before ALB is triggered, the generic (passive) load balance is
> > > > triggered. It iterates over p1 and p2 on src_rq to see if it can move any
> > > > one of them to dst_rq, and in most cases it succeeds in moving p1 to
> > > > dst_cpu. As a result, ALB will not be triggered.
> > >
> > > My question is whether p1 is guaranteed to be moved out in passive
> > > LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
> > > several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
> > > with nr_balance_failed still below cache_nice_tries, or
> > > can_migrate_llc_task() returning something other than mig_forbid due
> > > to capacity constraints on dst_llc at that instant. If passive LB
> > > rejects p1 for any of these, ALB is still triggered with p1 and p2
> > > both present on src_rq.
> > >
> > > Can we conclude that p1 and p2 never end up on src_rq together when
> > > ALB fires? Or would it help to set up a simple experiment and trace
> > > this path to see whether it actually occurs in practice?
> >
> > With 2 tasks on rq with different preference, active load balance could
> > pick the wrong task as can_migrate_task() checked in active load balance
> > will not consult migrate_degrades_llc(). How about the following patch
> > to fix this issue.
> >
> > [...]
> >
> > + if (env->migration_type == migrate_llc_task &&
> > + env->src_rq->cfs.h_nr_runnable > 1)
> > + return true;
> > +
> > return false;
> > }
>
> Your approach is simpler than mine — it avoids threading
> migration_type across the CPU stopper boundary and doesn't need any
> new rq field.
>
> One thing I'd like to flag, IMO: this approach skips the ALB path
> entirely for migrate_llc_task whenever more than one task is
> runnable, deferring the fix to the next passive LB pass. So it
> trades "delay" for a simpler implementation.
>
If we cannot pull a task from this rq for a migrate_llc_task imbalance
with more than one runnable task, can_migrate_task() has already
rejected the candidates — either the task preferring the dst LLC
is cache-hot or capacity-constrained, or the only movable task
prefers the source LLC. Forcing ALB here would ignore that.
We keep ALB only for the single-task case, where that
lone task prefers the dst LLC and has no other way to migrate.
I think this is the right thing to do because we shouldn't
force the tasks to move when can_migrate_task() is already
telling us not to.
Tim
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-05 16:04 ` Tim Chen
@ 2026-08-05 16:43 ` Chen, Yu C
2026-08-06 16:21 ` Tim Chen
0 siblings, 1 reply; 16+ messages in thread
From: Chen, Yu C @ 2026-08-05 16:43 UTC (permalink / raw)
To: Tim Chen, wanglu15
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu
On 8/6/2026 12:04 AM, Tim Chen wrote:
> On Wed, 2026-08-05 at 10:38 +0800, wanglu15 wrote:
>> From: Lu Wang <wanglu.priv@gmail.com>
>>
>> Thanks, Tim.
>>
>> On Tue, 2026-08-04 at 12:42 -0700, Tim Chen wrote:
>>> On Tue, 2026-08-04 at 23:07 +0800, Lu Wang wrote:
>>>> Thanks, Chenyu.
>>>>
>>>> On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
>>>>> Yes. Besides, if I understand correctly, I suppose Lu Wang was
>>>>> referring to the following scenario:
>>>>>
>>>>> src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
>>>>> while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
>>>>> set because src_rq has at least one task, p1, that wants to migrate
>>>>> to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
>>>>> thus moves p2 out of its preferred LLC.
>>>>
>>>> That's exactly the scenario I had in mind.
>>>>
>>>>> Firstly, before ALB is triggered, the generic (passive) load balance is
>>>>> triggered. It iterates over p1 and p2 on src_rq to see if it can move any
>>>>> one of them to dst_rq, and in most cases it succeeds in moving p1 to
>>>>> dst_cpu. As a result, ALB will not be triggered.
>>>>
>>>> My question is whether p1 is guaranteed to be moved out in passive
>>>> LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
>>>> several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
>>>> with nr_balance_failed still below cache_nice_tries, or
>>>> can_migrate_llc_task() returning something other than mig_forbid due
>>>> to capacity constraints on dst_llc at that instant. If passive LB
>>>> rejects p1 for any of these, ALB is still triggered with p1 and p2
>>>> both present on src_rq.
>>>>
>>>> Can we conclude that p1 and p2 never end up on src_rq together when
>>>> ALB fires? Or would it help to set up a simple experiment and trace
>>>> this path to see whether it actually occurs in practice?
I see. It is possible for p1 and p2 to coexist on src_rq. Previously,
I thought that if task migration failed due to CPU affinity, then dst_cpu
or src_cpu would be changed because of env.flags & LBF_DST_PINNED or
env.flags & LBF_ALL_PINNED. So ALB would be skipped. But a more common
scenario seems to be when p1 is the running task. Then can_migrate_task()
will gate it anyway. That is a common migration failure.
>>>
>>> With 2 tasks on rq with different preference, active load balance could
>>> pick the wrong task as can_migrate_task() checked in active load balance
>>> will not consult migrate_degrades_llc(). How about the following patch
>>> to fix this issue.
>>>
>>> [...]
>>>
>>> + if (env->migration_type == migrate_llc_task &&
>>> + env->src_rq->cfs.h_nr_runnable > 1)
>>> + return true;
>>> +
>>> return false;
>>> }
>>
>> Your approach is simpler than mine — it avoids threading
>> migration_type across the CPU stopper boundary and doesn't need any
>> new rq field.
>>
>> One thing I'd like to flag, IMO: this approach skips the ALB path
>> entirely for migrate_llc_task whenever more than one task is
>> runnable, deferring the fix to the next passive LB pass. So it
>> trades "delay" for a simpler implementation.
>>
>
> If we cannot pull a task from this rq for a migrate_llc_task imbalance
> with more than one runnable task, can_migrate_task() has already
> rejected the candidates — either the task preferring the dst LLC
> is cache-hot or capacity-constrained, or the only movable task
> prefers the source LLC. Forcing ALB here would ignore that.
In passive load balance, if there are 2 tasks, p1 prefers dst_llc,
and if p1 is the running task, then p1 can not be migrated to
dst_cpu in can_migrate_task():
if (task_on_cpu(env->src_rq, p))
return 0;
and in this case we might have to rely on ALB to migrate p1(not
ignore it)
thanks,
Chenyu
>
> We keep ALB only for the single-task case, where that
> lone task prefers the dst LLC and has no other way to migrate.
>
> I think this is the right thing to do because we shouldn't
> force the tasks to move when can_migrate_task() is already
> telling us not to.
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-01 12:22 [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance Lu Wang
2026-08-03 4:20 ` Chen, Yu C
@ 2026-08-06 15:35 ` Chen, Yu C
2026-08-06 17:22 ` Tim Chen
1 sibling, 1 reply; 16+ messages in thread
From: Chen, Yu C @ 2026-08-06 15:35 UTC (permalink / raw)
To: Lu Wang, tim.c.chen
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu@linux.dev
Hi Lu Wang, Tim,
On 8/1/2026 8:22 PM, Lu Wang wrote:
> A passive load-balance pass marks group_llc_balance as migrate_llc_task
> and queues active balance when it cannot move a task. The CPU stopper
> callback constructs a fresh lb_env, so preserve the migration type on
> the runqueue across the asynchronous boundary.
>
> For CAS-directed active balance, reject a candidate whose preferred LLC
> does not match the destination LLC. This keeps the fallback from moving
> a task away from its preferred LLC.
>
It looks like this proposal provides fine-grain control on per-task base
migration strategy is promising.
> +static inline bool
> +migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
> +{
> + return sched_cache_enabled() &&
> + env->migration_type == migrate_llc_task &&
> + READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu);
> +}
> +
[ ... ]
> @@ -13654,6 +13672,7 @@ static int active_load_balance_cpu_stop(void *data)
> .src_rq = busiest_rq,
> .idle = CPU_IDLE,
> .flags = LBF_ACTIVE_LB,
> + .migration_type = (enum migration_type)busiest_rq->active_balance_type,
If we overwrite migration_type for ALB (default is 0, i.e. migrate_load),
then in can_migrate_task() a delayed task might not be migrated in ALB:
if ((p->se.sched_delayed) && (env->migration_type != migrate_load))
return 0;
So an enhanced approach I'm thinking of is to pass
migrate_llc_task information via env->flags:
> };
>
> schedstat_inc(sd->alb_count);
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index 56acf502b..82084d405 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -1266,6 +1266,7 @@ struct rq {
> /* For active balancing */
> int active_balance;
> int push_cpu;
> + int active_balance_type; /* enum migration_type */
We can set env->flags by invoking different callbacks of
stop_one_cpu_nowait(),
thus avoiding the need to introduce active_balance_type into rq - which
could
cause false sharing if cache-line alignment is broken.
something like:
#define LBF_ACTIVE_LB_LLC 0x40
-static int active_load_balance_cpu_stop(void *data)
+static int __active_load_balance_cpu_stop(void *data, unsigned int
lb_flags)
-static int active_load_balance_cpu_stop(void *data)
+static int __active_load_balance_cpu_stop(void *data, unsigned int
lb_flags)
{
struct rq *busiest_rq = data;
int busiest_cpu = cpu_of(busiest_rq);
@@ -13659,7 +13687,7 @@ static int active_load_balance_cpu_stop(void *data)
.src_cpu = busiest_rq->cpu,
.src_rq = busiest_rq,
.idle = CPU_IDLE,
- .flags = LBF_ACTIVE_LB,
+ .flags = LBF_ACTIVE_LB | lb_flags,
};
and in migrate_llc_task_wrong_dst(), we check env->flags & LBF_ACTIVE_LB_LLC
instead.
static int active_load_balance_cpu_stop(void *data)
{
return __active_load_balance_cpu_stop(data, 0);
}
static int active_load_balance_llc_cpu_stop(void *data)
{
return __active_load_balance_cpu_stop(data, LBF_ACTIVE_LB_LLC);
<-- new flag
}
static inline cpu_stop_fn_t alb_stop_fn(struct lb_env *env)
{
if (env->migration_type == migrate_llc_task)
return active_load_balance_llc_cpu_stop;
return active_load_balance_cpu_stop;
}
if (active_balance) {
stop_one_cpu_nowait(cpu_of(busiest),
alb_stop_fn(&env), busiest,
&busiest->active_balance_work);
}
thanks,
Chenyu
> struct cpu_stop_work active_balance_work;
>
> /* CPU of this runqueue: */
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-05 16:43 ` Chen, Yu C
@ 2026-08-06 16:21 ` Tim Chen
0 siblings, 0 replies; 16+ messages in thread
From: Tim Chen @ 2026-08-06 16:21 UTC (permalink / raw)
To: Chen, Yu C, wanglu15
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu
On Thu, 2026-08-06 at 00:43 +0800, Chen, Yu C wrote:
> On 8/6/2026 12:04 AM, Tim Chen wrote:
> > On Wed, 2026-08-05 at 10:38 +0800, wanglu15 wrote:
> > > From: Lu Wang <wanglu.priv@gmail.com>
> > >
> > > Thanks, Tim.
> > >
> > > On Tue, 2026-08-04 at 12:42 -0700, Tim Chen wrote:
> > > > On Tue, 2026-08-04 at 23:07 +0800, Lu Wang wrote:
> > > > > Thanks, Chenyu.
> > > > >
> > > > > On Tue, 2026-08-04 at 16:17 +0800, Chen, Yu C wrote:
> > > > > > Yes. Besides, if I understand correctly, I suppose Lu Wang was
> > > > > > referring to the following scenario:
> > > > > >
> > > > > > src_rq has 2 runnable tasks, p1 and p2. p1 prefers dst_rq (dst_llc),
> > > > > > while p2 prefers src_rq (src_llc). In this case, migrate_llc_task is
> > > > > > set because src_rq has at least one task, p1, that wants to migrate
> > > > > > to dst_rq. In ALB, can_migrate_task() found p2 and returns true for p2
> > > > > > thus moves p2 out of its preferred LLC.
> > > > >
> > > > > That's exactly the scenario I had in mind.
> > > > >
> > > > > > Firstly, before ALB is triggered, the generic (passive) load balance is
> > > > > > triggered. It iterates over p1 and p2 on src_rq to see if it can move any
> > > > > > one of them to dst_rq, and in most cases it succeeds in moving p1 to
> > > > > > dst_cpu. As a result, ALB will not be triggered.
> > > > >
> > > > > My question is whether p1 is guaranteed to be moved out in passive
> > > > > LB. can_migrate_task()/migrate_degrades_llc() can reject p1 for
> > > > > several independent reasons — p1 pinned by cpus_ptr, p1 cache-hot
> > > > > with nr_balance_failed still below cache_nice_tries, or
> > > > > can_migrate_llc_task() returning something other than mig_forbid due
> > > > > to capacity constraints on dst_llc at that instant. If passive LB
> > > > > rejects p1 for any of these, ALB is still triggered with p1 and p2
> > > > > both present on src_rq.
> > > > >
> > > > > Can we conclude that p1 and p2 never end up on src_rq together when
> > > > > ALB fires? Or would it help to set up a simple experiment and trace
> > > > > this path to see whether it actually occurs in practice?
>
> I see. It is possible for p1 and p2 to coexist on src_rq. Previously,
> I thought that if task migration failed due to CPU affinity, then dst_cpu
> or src_cpu would be changed because of env.flags & LBF_DST_PINNED or
> env.flags & LBF_ALL_PINNED. So ALB would be skipped. But a more common
> scenario seems to be when p1 is the running task. Then can_migrate_task()
> will gate it anyway. That is a common migration failure.
>
> > > >
> > > > With 2 tasks on rq with different preference, active load balance could
> > > > pick the wrong task as can_migrate_task() checked in active load balance
> > > > will not consult migrate_degrades_llc(). How about the following patch
> > > > to fix this issue.
> > > >
> > > > [...]
> > > >
> > > > + if (env->migration_type == migrate_llc_task &&
> > > > + env->src_rq->cfs.h_nr_runnable > 1)
> > > > + return true;
> > > > +
> > > > return false;
> > > > }
> > >
> > > Your approach is simpler than mine — it avoids threading
> > > migration_type across the CPU stopper boundary and doesn't need any
> > > new rq field.
> > >
> > > One thing I'd like to flag, IMO: this approach skips the ALB path
> > > entirely for migrate_llc_task whenever more than one task is
> > > runnable, deferring the fix to the next passive LB pass. So it
> > > trades "delay" for a simpler implementation.
> > >
> >
> > If we cannot pull a task from this rq for a migrate_llc_task imbalance
> > with more than one runnable task, can_migrate_task() has already
> > rejected the candidates — either the task preferring the dst LLC
> > is cache-hot or capacity-constrained, or the only movable task
> > prefers the source LLC. Forcing ALB here would ignore that.
>
> In passive load balance, if there are 2 tasks, p1 prefers dst_llc,
> and if p1 is the running task, then p1 can not be migrated to
> dst_cpu in can_migrate_task():
> if (task_on_cpu(env->src_rq, p))
> return 0;
> and in this case we might have to rely on ALB to migrate p1(not
> ignore it)
Considering the case above, then what Lu Wang proposed is probably the better
option.
Tim
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-06 15:35 ` Chen, Yu C
@ 2026-08-06 17:22 ` Tim Chen
2026-08-07 6:48 ` Chen, Yu C
0 siblings, 1 reply; 16+ messages in thread
From: Tim Chen @ 2026-08-06 17:22 UTC (permalink / raw)
To: Chen, Yu C, Lu Wang
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu@linux.dev
On Thu, 2026-08-06 at 23:35 +0800, Chen, Yu C wrote:
> Hi Lu Wang, Tim,
>
> On 8/1/2026 8:22 PM, Lu Wang wrote:
> > A passive load-balance pass marks group_llc_balance as migrate_llc_task
> > and queues active balance when it cannot move a task. The CPU stopper
> > callback constructs a fresh lb_env, so preserve the migration type on
> > the runqueue across the asynchronous boundary.
> >
> > For CAS-directed active balance, reject a candidate whose preferred LLC
> > does not match the destination LLC. This keeps the fallback from moving
> > a task away from its preferred LLC.
> >
>
> It looks like this proposal provides fine-grain control on per-task base
> migration strategy is promising.
>
> > +static inline bool
> > +migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
> > +{
> > + return sched_cache_enabled() &&
> > + env->migration_type == migrate_llc_task &&
> > + READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu);
> > +}
> > +
>
> [ ... ]
>
> > @@ -13654,6 +13672,7 @@ static int active_load_balance_cpu_stop(void *data)
> > .src_rq = busiest_rq,
> > .idle = CPU_IDLE,
> > .flags = LBF_ACTIVE_LB,
> > + .migration_type = (enum migration_type)busiest_rq->active_balance_type,
>
> If we overwrite migration_type for ALB (default is 0, i.e. migrate_load),
> then in can_migrate_task() a delayed task might not be migrated in ALB:
>
> if ((p->se.sched_delayed) && (env->migration_type != migrate_load))
This is a good catch.
It may be easier to create a migrate_llc_task_alb type and pass that
in migration type. Then modify the above as
if ((p->se.sched_delayed) && env->migration_type != migrate_load
&& env->migration_type != migrate_llc_task_alb)
return 0
That avoids creating two cpu stop functions.
Tim
> return 0;
> So an enhanced approach I'm thinking of is to pass
> migrate_llc_task information via env->flags:
> > };
> >
> > schedstat_inc(sd->alb_count);
> > diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> > index 56acf502b..82084d405 100644
> > --- a/kernel/sched/sched.h
> > +++ b/kernel/sched/sched.h
> > @@ -1266,6 +1266,7 @@ struct rq {
> > /* For active balancing */
> > int active_balance;
> > int push_cpu;
> > + int active_balance_type; /* enum migration_type */
>
> We can set env->flags by invoking different callbacks of
> stop_one_cpu_nowait(),
> thus avoiding the need to introduce active_balance_type into rq - which
> could
> cause false sharing if cache-line alignment is broken.
>
> something like:
>
> #define LBF_ACTIVE_LB_LLC 0x40
>
> -static int active_load_balance_cpu_stop(void *data)
> +static int __active_load_balance_cpu_stop(void *data, unsigned int
> lb_flags)
> -static int active_load_balance_cpu_stop(void *data)
> +static int __active_load_balance_cpu_stop(void *data, unsigned int
> lb_flags)
> {
> struct rq *busiest_rq = data;
> int busiest_cpu = cpu_of(busiest_rq);
> @@ -13659,7 +13687,7 @@ static int active_load_balance_cpu_stop(void *data)
> .src_cpu = busiest_rq->cpu,
> .src_rq = busiest_rq,
> .idle = CPU_IDLE,
> - .flags = LBF_ACTIVE_LB,
> + .flags = LBF_ACTIVE_LB | lb_flags,
> };
>
> and in migrate_llc_task_wrong_dst(), we check env->flags & LBF_ACTIVE_LB_LLC
> instead.
>
> static int active_load_balance_cpu_stop(void *data)
> {
> return __active_load_balance_cpu_stop(data, 0);
> }
>
> static int active_load_balance_llc_cpu_stop(void *data)
> {
> return __active_load_balance_cpu_stop(data, LBF_ACTIVE_LB_LLC);
> <-- new flag
> }
>
> static inline cpu_stop_fn_t alb_stop_fn(struct lb_env *env)
> {
> if (env->migration_type == migrate_llc_task)
> return active_load_balance_llc_cpu_stop;
>
> return active_load_balance_cpu_stop;
> }
>
> if (active_balance) {
> stop_one_cpu_nowait(cpu_of(busiest),
> alb_stop_fn(&env), busiest,
> &busiest->active_balance_work);
> }
>
>
> thanks,
> Chenyu
>
> > struct cpu_stop_work active_balance_work;
> >
> > /* CPU of this runqueue: */
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance
2026-08-06 17:22 ` Tim Chen
@ 2026-08-07 6:48 ` Chen, Yu C
0 siblings, 0 replies; 16+ messages in thread
From: Chen, Yu C @ 2026-08-07 6:48 UTC (permalink / raw)
To: Tim Chen, Lu Wang
Cc: peterz, mingo, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel,
chen.yu@linux.dev
On 8/7/2026 1:22 AM, Tim Chen wrote:
> On Thu, 2026-08-06 at 23:35 +0800, Chen, Yu C wrote:
>> Hi Lu Wang, Tim,
>>
>> On 8/1/2026 8:22 PM, Lu Wang wrote:
>>> A passive load-balance pass marks group_llc_balance as migrate_llc_task
>>> and queues active balance when it cannot move a task. The CPU stopper
>>> callback constructs a fresh lb_env, so preserve the migration type on
>>> the runqueue across the asynchronous boundary.
>>>
>>> For CAS-directed active balance, reject a candidate whose preferred LLC
>>> does not match the destination LLC. This keeps the fallback from moving
>>> a task away from its preferred LLC.
>>>
>>
>> It looks like this proposal provides fine-grain control on per-task base
>> migration strategy is promising.
>>
>>> +static inline bool
>>> +migrate_llc_task_wrong_dst(struct task_struct *p, struct lb_env *env)
>>> +{
>>> + return sched_cache_enabled() &&
>>> + env->migration_type == migrate_llc_task &&
>>> + READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu);
>>> +}
>>> +
>>
>> [ ... ]
>>
>>> @@ -13654,6 +13672,7 @@ static int active_load_balance_cpu_stop(void *data)
>>> .src_rq = busiest_rq,
>>> .idle = CPU_IDLE,
>>> .flags = LBF_ACTIVE_LB,
>>> + .migration_type = (enum migration_type)busiest_rq->active_balance_type,
>>
>> If we overwrite migration_type for ALB (default is 0, i.e. migrate_load),
>> then in can_migrate_task() a delayed task might not be migrated in ALB:
>>
>> if ((p->se.sched_delayed) && (env->migration_type != migrate_load))
>
> This is a good catch.
>
> It may be easier to create a migrate_llc_task_alb type and pass that
> in migration type. Then modify the above as
>
> if ((p->se.sched_delayed) && env->migration_type != migrate_load
> && env->migration_type != migrate_llc_task_alb)
> return 0
>
We still need a channel to carry migrate_llc_task/migrate_llc_task_alb
into the alb, since the stopper builds a fresh lb_env - hence
rq->active_balance_type was introduced in Lu Wang's proposal. We can
reuse the callback slot in active_balance_work instead, pick
active_load_balance_llc_cpu_stop() at kick time, thus no new rq field
is needed.
thanks,
Chenyu
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-08-07 6:49 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-01 12:22 [PATCH] sched/cache: honor migrate_llc_task semantics in active load balance Lu Wang
2026-08-03 4:20 ` Chen, Yu C
2026-08-03 10:02 ` Lu Wang
2026-08-04 0:10 ` Tim Chen
2026-08-04 8:17 ` Chen, Yu C
2026-08-04 15:07 ` Lu Wang
2026-08-04 19:42 ` Tim Chen
2026-08-05 2:38 ` wanglu15
2026-08-05 16:04 ` Tim Chen
2026-08-05 16:43 ` Chen, Yu C
2026-08-06 16:21 ` Tim Chen
2026-08-04 8:30 ` Lu Wang
2026-08-06 15:35 ` Chen, Yu C
2026-08-06 17:22 ` Tim Chen
2026-08-07 6:48 ` Chen, Yu C
-- strict thread matches above, loose matches on Subject: below --
2026-08-01 12:17 Lu Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox