[PATCH v2] sched/cache: honor migrate_llc_task semantics in active load balance

Lu Wang posted 1 patch 1 month, 2 weeks ago
There is a newer version of this series
kernel/sched/fair.c | 56 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 50 insertions(+), 6 deletions(-)
[PATCH v2] sched/cache: honor migrate_llc_task semantics in active load balance
Posted by Lu Wang 1 month, 2 weeks ago
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 select the stopper callback when
queueing active balance to preserve the migration semantics 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\")
Suggested-by: \"Chen, Yu C\" <yu.c.chen@intel.com>
Signed-off-by: Lu Wang <wanglu.priv@gmail.com>
---
Changes in v2:
 - Select the stopper callback at kick time to preserve
   migrate_llc_task semantics in active load balance without passing
   migration_type across the stopper, which affects delayed-dequeue tasks.
 - Link to V1: https://lore.kernel.org/all/20260801122252.2476258-1-wanglu.priv@gmail.com/

 kernel/sched/fair.c | 56 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 6 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6..37a470c41 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10254,6 +10254,7 @@ enum migration_type {
 #define LBF_SOME_PINNED	0x08
 #define LBF_ACTIVE_LB	0x10
 #define LBF_LLC_PINNED	0x20
+#define LBF_ACTIVE_LB_LLC	0x40
 
 struct lb_env {
 	struct sched_domain	*sd;
@@ -10645,6 +10646,20 @@ alb_break_llc(struct lb_env *env)
 	return false;
 }
 
+/*
+ * Returns true if p's preferred LLC does not match the destination CPU
+ * under migrate_llc_task semantics. Passive LB passes migrate_llc_task
+ * in migration_type, while active LB carries it in LBF_ACTIVE_LB_LLC.
+ */
+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 ||
+		env->flags & LBF_ACTIVE_LB_LLC) &&
+	       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 +10688,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 +10711,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 +10816,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) {
@@ -13156,6 +13176,20 @@ static int need_active_balance(struct lb_env *env)
 }
 
 static int active_load_balance_cpu_stop(void *data);
+static int active_load_balance_llc_cpu_stop(void *data);
+
+/*
+ * migration_type is checked elsewhere to decide migration policy, so
+ * it shouldn't be repurposed just to flag an LLC-directed active
+ * balance across the stopper. Pick the callback here instead.
+ */
+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;
+}
 
 static int should_we_balance(struct lb_env *env)
 {
@@ -13492,7 +13526,7 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
 			raw_spin_rq_unlock_irqrestore(busiest, flags);
 			if (active_balance) {
 				stop_one_cpu_nowait(cpu_of(busiest),
-					active_load_balance_cpu_stop, busiest,
+					alb_stop_fn(&env), busiest,
 					&busiest->active_balance_work);
 			}
 			preempt_enable();
@@ -13603,7 +13637,7 @@ update_next_balance(struct sched_domain *sd, unsigned long *next_balance)
  * least 1 task to be running on each physical CPU where possible, and
  * avoids physical / logical imbalances.
  */
-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);
@@ -13653,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,
 		};
 
 		schedstat_inc(sd->alb_count);
@@ -13681,6 +13715,16 @@ static int active_load_balance_cpu_stop(void *data)
 	return 0;
 }
 
+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);
+}
+
 /*
  * Scale the max sched_balance_rq interval with the number of CPUs in the system.
  * This trades load-balance latency on larger machines for less cross talk.
-- 
2.43.0
Re: [PATCH v2] sched/cache: honor migrate_llc_task semantics in active load balance
Posted by Chen, Yu C 1 month, 2 weeks ago
On 8/9/2026 6:53 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 select the stopper callback when
> queueing active balance to preserve the migration semantics across the
> asynchronous boundary.
> 

Worthy adding a [Problem Statement] section to describe what issue this 
patch tries to fix
(with polish):
src_rq has two 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() finds p2 
and returns true for
it, thus moving p2 out of its preferred LLC.

> 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\")
> Suggested-by: \"Chen, Yu C\" <yu.c.chen@intel.com>
> Signed-off-by: Lu Wang <wanglu.priv@gmail.com>
> ---
> Changes in v2:
>   - Select the stopper callback at kick time to preserve
>     migrate_llc_task semantics in active load balance without passing
>     migration_type across the stopper, which affects delayed-dequeue tasks.

Maybe move the above reasoning about why the new stopper function is needed
into the commit log for future reference.

> @@ -10645,6 +10646,20 @@ alb_break_llc(struct lb_env *env)
>   	return false;
>   }
>   
> +/*
> + * Returns true if p's preferred LLC does not match the destination CPU
> + * under migrate_llc_task semantics. Passive LB passes migrate_llc_task
> + * in migration_type, while active LB carries it in LBF_ACTIVE_LB_LLC.

"while active LB carries LBF_ACTIVE_LB_LLC in env->flags to avoid 
overwriting
env->migrate_type."

Per my understanding,

Reviewed-by: Chen Yu <yu.c.chen@intel.com>

thanks,
Chenyu
Re: [PATCH v2] sched/cache: honor migrate_llc_task semantics in active load balance
Posted by Lu Wang 1 month, 2 weeks ago
Hi Chenyu,

Thanks for the review and the suggestions.

On 8/11/2026 6:23 PM, Chen, Yu C wrote:
> On 8/9/2026 6:53 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 select the stopper callback when
>> queueing active balance to preserve the migration semantics across the
>> asynchronous boundary.
>>
> Worthy adding a [Problem Statement] section to describe what issue this
> patch tries to fix
> (with polish):
> src_rq has two 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() finds p2 and returns true for it, thus moving p2
> out of its preferred LLC.
>
>> Changes in v2:
>> - Select the stopper callback at kick time to preserve
>>   migrate_llc_task semantics in active load balance without passing
>>   migration_type across the stopper, which affects delayed-dequeue tasks.
> Maybe move the above reasoning about why the new stopper function is needed
> into the commit log for future reference.

Thanks. I will add the p1/p2 problem statement and move the rationale for
selecting the stopper callback at kick time into the commit log.

>> +/*
>> + * Returns true if p's preferred LLC does not match the destination CPU
>> + * under migrate_llc_task semantics. Passive LB passes migrate_llc_task
>> + * in migration_type, while active LB carries it in LBF_ACTIVE_LB_LLC.
> "while active LB carries LBF_ACTIVE_LB_LLC in env->flags to avoid
> overwriting env->migrate_type."

Thanks. I will update the helper comment accordingly.

I will include these commit-log and comment-only updates in v3.

Thanks,
Lu Wang
Re: [PATCH v2] sched/cache: honor migrate_llc_task semantics in active load balance
Posted by Tim Chen 1 month, 2 weeks ago
On Sun, 2026-08-09 at 18:53 +0800, 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 select the stopper callback when
> queueing active balance to preserve the migration semantics 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.

Thanks. This version looks good to me.

Reviewed-by: Tim Chen <tim.c.chen@linux.intel.com>

Tim

> 
> Fixes: e4c9a4cb244a (\"sched/cache: Add migrate_llc_task migration type for cache-aware balancing\")
> Suggested-by: \"Chen, Yu C\" <yu.c.chen@intel.com>
> Signed-off-by: Lu Wang <wanglu.priv@gmail.com>
> ---