sched discussion
[PATCH v3] sched/cache: honor migrate_llc_task semantics in active load balance
LLM 分析
sched/cache:在 ALB 中保留 migrate_llc_task 语义
系列概况
- 标题:
[PATCH v3] sched/cache: honor migrate_llc_task semantics in active load balance(v4 标题大小写改为Honor) - 作者:Lu Wang
<wanglu.priv@gmail.com> - 版本:v3 → v4(链接中可见 v1、v2 前期版本)
- 规模:单文件改动
kernel/sched/fair.c,约 51 处新增、6 处删除 - 修改文件:
kernel/sched/fair.c - 代码统计:57 行 hunk 总量,+51/-6
- Message-ID:
20260813045241.3039862-1-wanglu.priv@gmail.com(v3)20260824023324.3663800-1-wanglu.priv@gmail.com(v3 之后的 ping 回复)20260903020656.3793626-1-wanglu.priv@gmail.com(v4 rebase)
- 完整性:3 封邮件,覆盖 v3 patch、作者对 maintainer 的提醒 ping、v4 rebase patch;v4 仅 rebase,无功能改动
补丁目的
Cache-Aware Scheduling(CAS)新增的 migrate_llc_task 迁移类型,本意是把任务推向其 preferred_llc。但当被动负载均衡(passive LB)将任务 migrate_llc_task 作为目标时,若进一步回退到 Active Load Balance(ALB),ALB 内部会构造一份新的 lb_env,其中的 migration_type 不再携带 migrate_llc_task,于是 can_migrate_task() 可能放过一个“留在原 LLC 更合适”的候选任务,把它反向赶出 preferred LLC。补丁的目标是把“任务应当迁往哪个 LLC”这层语义穿过 ALB 的 cpu_stopper 边界保留下来。
旧流程的问题
源 runqueue 上有两个可运行任务 p1、p2:
p1的preferred_llc=dst_llc(想去 dst_rq 所在的 LLC);p2的preferred_llc=src_llc(愿意留在 src_rq)。
+----------------------+ +----------------------+
| src_rq (src_llc) | | dst_rq (dst_llc) |
| p1 (wants dst_llc) | ---> | |
| p2 (prefers src_llc)| | |
+----------------------+ +----------------------+
被动 LB 检测到 src_rq 上至少有一个任务(p1)想去 dst_llc,于是把 migration_type 设为 migrate_llc_task 发起均衡,触发 ALB。ALB 的 stopper 在被踢起时重新构造 lb_env,没有把 migrate_llc_task 传过来——can_migrate_task() 顺着 src_rq 扫描,看到 p2 也满足可迁移条件,便把 p2 搬走;这恰恰违背了 p2 的 LLC 偏好。
新流程
新增 LBF_ACTIVE_LB_LLC = 0x40 标志位。在 ALB 触发点 sched_balance_rq() 中通过 alb_stop_fn(env) 选择 cpu stopper 回调:
migration_type == migrate_llc_task→active_load_balance_llc_cpu_stop(携带LBF_ACTIVE_LB_LLC标志);- 其它情况 → 旧的
active_load_balance_cpu_stop。
两个 stopper 都委托给新拆出的 __active_load_balance_cpu_stop(data, lb_flags),后者把 lb_flags 合并到 lb_env.flags。migrate_llc_task_wrong_dst() 这个共用 helper 同时识别 env->migration_type == migrate_llc_task(被动 LB 路径)和 env->flags & LBF_ACTIVE_LB_LLC(ALB 路径),从而在 migrate_degrades_llc() 与 can_migrate_task() 中恢复“目标 LLC 不匹配就拒绝迁移”的行为。
passive LB (sets migrate_llc_task)
|
v
need_active_balance() -> sched_balance_rq()
|
alb_stop_fn(env) 选择 stopper
|
+------------------------+------------------------+
| |
migrate_llc_task == true 其余情况
| |
v v
active_load_balance_llc_cpu_stop active_load_balance_cpu_stop
| |
+----------> __active_load_balance_cpu_stop(data, lb_flags)
|
lb_env.flags |= LBF_ACTIVE_LB_LLC ?
|
v
can_migrate_task() 看到 LBF_ACTIVE_LB_LLC
拒绝“preferred_llc 与 dst_llc 不一致”的候选
Patch 概览
- 新增
LBF_ACTIVE_LB_LLC = 0x40标志; - 新增共用 helper
migrate_llc_task_wrong_dst(),兼容被动 LB(看migration_type)与 ALB(看flags); - 把
active_load_balance_cpu_stop拆为两层:薄壳 +__active_load_balance_cpu_stop(data, lb_flags); - 新增
active_load_balance_llc_cpu_stop,调用__active_load_balance_cpu_stop(data, LBF_ACTIVE_LB_LLC); - 在
sched_balance_rq()中通过alb_stop_fn(&env)选择 stopper 回调; - 在
alb_break_llc()不命中的#else分支保留return false的 stub,避免破坏!CONFIG_CFS编译。
关键实现
#define LBF_ACTIVE_LB_LLC 0x40
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);
}
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 __active_load_balance_cpu_stop(void *data, unsigned int lb_flags)
{
...
.flags = LBF_ACTIVE_LB | lb_flags,
...
}
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);
}
设计要点是“选 callback 而非带 migration_type 穿过 stopper”:补丁作者明确解释过,stopper 是异步边界,如果直接把 migrate_llc_task 透传到 ALB,会与 delayed-dequeue 任务对 migration_type 的语义检查相冲突,因此选 (b) 方案:用一个 flag 把意图钉在 lb_env.flags 上。
类比
把 LLC 想象成“图书馆分馆”:每个读者(任务)有自己习惯去的分馆(preferred_llc)。前台(passive LB)看到读者甲想换去总馆借书,于是派人去把他请过去。可如果前台人手不够,又请了一位临时工(ALB stopper)来搬运——临时工没有拿到“只搬运甲”的小纸条,结果把同样站在门口的读者乙也一起顺走了。补丁相当于给临时工发了一张“只搬去总馆偏好者”的纸条:要么选带小纸条的搬运工 active_load_balance_llc_cpu_stop,要么派普通搬运工 active_load_balance_cpu_stop,从源头分单,就不会误搬乙。
Highlight:风险与注意点
LBF_ACTIVE_LB_LLC与已有LBF_SOME_PINNED/LBF_ACTIVE_LB/LBF_LLC_PINNED共用位图(0x08/0x10/0x20),新值0x40不冲突,但继续增加位时要防止溢出。alb_stop_fn()在sched_balance_rq()中基于调用现场的env决策,避免在 stopper 内部再次判断migration_type,从而隔离异步边界——但这也意味着所有未来可能新增的“带 LLC 语义”的 ALB 入口都要在这里登记。migrate_degrades_llc()已替换为共用 helper;若后续再拆出第三种migration_type,需要同步扩展migrate_llc_task_wrong_dst()的判定。- v4 是单纯 rebase(基于
ef9293b3b7,含 Tim Chenf0d243a96f26“避免 cache-aware balancing 制造 misfit”),没有功能改动;review 关注点仍是 v3 时确认的语义正确性。 - 仅有作者发起的 ping,未见 maintainer 回复;
Fixes:tag 指向e4c9a4cb244a(CAS 引入 commit),说明这是上游引入的回归。
版本变化
- v1 → v2:在 kick 时选 stopper 回调,避免
migration_type穿过 stopper 影响 delayed-dequeue 任务的语义(即方案 b)。 - v2 → v3:仅改写 commit message 与 helper 注释,无代码改动。
- v3 → v4:rebase 到
ef9293b3b7(包含 Tim Chen 的 misfit 修复f0d243a96f26),无功能改动。
一句话总结
通过新增 LBF_ACTIVE_LB_LLC 标志位与两个 cpu stopper 回调(普通版与 LLC 版),让 ALB 在被动 LB 触发后仍能识别“该按 preferred LLC 选任务”的意图,避免把不该搬的任务赶出其 preferred LLC。