sched discussion
[PATCH v6 0/6] sched: Fix cluster scheduling in the presence of asymmetric capacity
LLM 分析
sched:非对称容量场景下的集群调度修复(v6)
系列概况
- 标题:[PATCH v6 0/6] sched: Fix cluster scheduling in the presence of asymmetric capacity
- 作者:Ricardo Neri ricardo.neri-calderon@linux.intel.com
- 版本:v6(前置 v1~v5 链接齐全)
- 规模:6 patches- 修改文件:
include/linux/sched/sd_flags.h、kernel/sched/fair.c、kernel/sched/topology.c - 代码统计:3 文件,+49 / -24
- Message-ID:20260720-rneri-fix-cas-clusters-v6-0-bb500bf4afd4@linux.intel.com
- 完整性:完整;tip-bot2 已确认全部 6 个 patch 进入
sched/coretip 分支(commitf2c2ba72、7fd540b1、0fbd428d、50b101f6、6060d61d、180ff97c,committer Peter Zijlstra,2026-08-07)
补丁目的
在 big.LITTLE/hybrid CPU 拓扑(Alder Lake、Lunar Lake、Panther Lake 等)里,调度器需要保证 misfit 任务落在大核,把剩余任务均匀铺到小核 cluster 的多个 L2 组。本系列修复了阻止这一行为的五个相互关联的 bug(cover letter 中 a~e),让 SD_PREFER_SIBLING 与 CONFIG_SCHED_CLUSTER 的语义在小核集群之间真正生效。
旧流程的问题
update_sd_pick_busiest()选 busiest 时做了容量判断,但顺序过晚,类型比较会把 equal-capacityfully_busy组错误胜出。- 小核 cluster 之间互相把对方识别成
misfit_task,阻挡跨 cluster 拉平。 sched_balance_find_src_rq()用 "~5% 容量差" 跳过 identical-capacity源 CPU,违背CONFIG_SCHED_CLUSTER设计。sg_overloaded在SD_ASYM_CPUCAPACITY路径里缺少balancing_at_rdgating,浪费统计。- SMT 兄弟忙时本应被选中的源 CPU 被错误跳过。
SD_PREFER_SIBLING在SD_ASYM_CPUCAPACITY子域里被强制清掉,兄弟 cluster 无法均衡。
新流程
按 patch 顺序组合后:
- patch 1 用
smt_degraded_cap在源 CPU 侧先判定 SMT 兄弟; - patch 2 把
sg_overloaded的写入收敛到balancing_at_rd; - patch 3 把
capacity_greater检查前置到 group_type 比较之前; - patch 4 仅在
dst_cpu大于组内最大容量时累加 misfit,但保留sg_overloaded=1; - patch 5 引入
cluster_equal_cap,identical capacity 不再被 ~5% 规则跳过; - patch 6 恢复
SD_PREFER_SIBLING,让 newly-idle 平衡能在 cluster 之间迁移任务。
Patch 概览
| # | 主题 | 文件 | 关键点 |
|---|---|---|---|
| 1 | SMT busy sibling 不跳过 | fair.c | smt_degraded_cap 局部变量 |
| 2 | gating sg_overloaded | fair.c | balancing_at_rd 检查 |
| 3 | 容量比较前置 | fair.c | update_sd_pick_busiest 顺序 |
| 4 | 条件性 misfit 累加 | fair.c | dst_cpu > max_capacity 才累加 |
| 5 | identical capacity 允许迁移 | fair.c | cluster_equal_cap + sched_cluster_active |
| 6 | 恢复 SD_PREFER_SIBLING | topology.c + sd_flags.h | 删清 flag 的逻辑 |
关键实现
patch 3(核心顺序调整):
if ((env->sd->flags & SD_ASYM_CPUCAPACITY) &&
(sgs->group_type <= group_fully_busy) &&
(capacity_greater(sg->sgc->min_capacity, capacity_of(env->dst_cpu))))
return false;
patch 4(条件 misfit 累加):
if (rq->misfit_task_load) {
if (balancing_at_rd)
*sg_overloaded = 1;
if (capacity_greater(capacity_of(env->dst_cpu),
group->sgc->max_capacity) &&
(sgs->group_misfit_task_load < rq->misfit_task_load))
sgs->group_misfit_task_load = rq->misfit_task_load;
}
patch 5(identical capacity 例外):
bool cluster_equal_cap = static_branch_unlikely(&sched_cluster_active) &&
(get_actual_cpu_capacity(env->dst_cpu) ==
get_actual_cpu_capacity(i));
if (!smt_degraded_cap && !cluster_equal_cap &&
!capacity_greater(capacity_of(env->dst_cpu), capacity))
continue;
patch 6(topology 改动):
// 删除 sd_init 里的清 flag 代码// if ((sd->flags & SD_ASYM_CPUCAPACITY) && sd->child)
// sd->child->flags &= ~SD_PREFER_SIBLING;
ASCII流程图
+-------- Big CPU (capacity_high) ---------+
| B0 |
| B1 |
+-----------------------------------------++-------- Small cluster0 --------+ +-------- Small cluster 1 --------+
| s0 s1 s2 s3 (L2) | | s4 s5 s6 s7 (L2) |
+--------------------------------+ +--------------------------------+
old flow:
update_sd_pick_busiest --> pick fully_busy on cluster 0
misfit load accounting --> cluster 1 marked misfit_task
sched_balance_find_src_rq --> identical cap skipped
SD_PREFER_SIBLING --> cleared under ASYM_CAPACITY
=> tasks pile up on cluster 0
new flow (v6):
1) SMT sibling busy? smt_degraded_cap (patch 1)
2) gating overloaded? balancing_at_rd only (patch 2)
3) capacity_greater check FIRST (patch 3)
4) skip misfit load if dst <= max_cap (patch 4)
5) cluster_equal_cap -> allow migration (patch 5)
6) SD_PREFER_SIBLING restored (patch 6)
=> cluster 0 and cluster 1 share load
update_sd_pick_busiest() decision tree candidate sg |
v SD_ASYM_CPUCAPACITY && type<=fully_busy
&& capacity_greater(sgc->min, dst) ? ----yes----> return false
|
no
v compare group_type vs busiest
|
v
pick busiest, then find src_rq
(smt/cluster_equal_cap aware)
类比
把 CPU 想象成办公室的两类员工:资深员工(大核)处理大项目,初级员工(小核)按 4 人一组(cluster)共用复印机(L2)。bug a~e 就像经理挑人的规则出问题:要么不向闲人派活,要么把所有活都堆给资深,要么不让小组之间互相借调。本系列让经理按规则把活真正均匀分到各小组,复印机不再被某个小组累垮。
Highlight:风险与注意点
- patch 3 把容量检查前置,可能影响纯大核/小核的非 cluster 系统,需配合 patch 6 一并回归。
- patch 4 把 misfit 累加条件化,要确认 newly_idle 路径仍能挑出 misfit 并交给大核。
- patch 5 用
get_actual_cpu_capacity()取代arch_scale_cpu_capacity(),对 cpufreq 压力更敏感,低频场景需观察抖动。 - patch 6 修改
SD_PREFER_SIBLING是行为变更,建议在 Raptor/Meteor Lake 等更多 hybrid 拓扑上验证。 - v6 评审尚未完全落幕(Vincent/Christian 的 reply仅有引文),后续可能还有微调 patch 5/6 的讨论。
版本变化
- v1 → v2:patch 2 修复
sched_reduced_capacity互斥;patch 3 改用arch_scale_cpu_capacity();patch 5 描述改写。 - v2 → v3:patch 3 反转容量检查;patch 4 描述扩展 overloaded/low-capacity 行为。
- v3 → v4:patch 1 修 SMT 多 busy 兄弟 bug;patch 2 修多余
sg_overloaded更新;patch 5 用局部变量。 - v4 → v5:patch 1 仅按需判断 SMT busy;patch 5 仅按需检查 architectural capacity。
- v5 → v6:patch 5 改用
get_actual_cpu_capacity();patch 6 扩展为所有 asymmetric 域恢复SD_PREFER_SIBLING;新增 Vincent/Andrea 的 Reviewed/Tested tag。
一句话总结
v6 通过修补 update_sd_pick_busiest 顺序、misfit 累加、identical-capacity 判定以及恢复 SD_PREFER_SIBLING,让 hybrid CPU 的小核 cluster 真正能跨 L3 平摊负载,并已被 Peter Zijlstra 收进 sched/core tip。