内核调度:CFS、绑核与 uclamp
2026/8/9大约 3 分钟内核Android 14调度CFSuclamp
内核调度:CFS、绑核与 uclamp
上一章看了内存。这一章回答:内核怎么调度线程,Android 如何影响调度(cpuset、 uclamp),与“卡顿”有什么关系?
Runnable 不等于正在 CPU 上运行
| 常见误解 | 正确理解 |
|---|---|
| 线程优先级决定一切 | 调度还受 cpuset、负载与 uclamp 综合影响 |
| 多核等于随便跑 | 不同核有性能差异,Android 用 cpuset/拓扑管理 |
| 卡顿都是应用问题 | 调度延迟(可运行没被调度)同样是常见原因 |
核心结论
- CFS 按虚拟时间公平调度可运行线程。
- cpuset 把 CPU 分组(top-app、background 等),决定可用核。
- uclamp 钳制任务的最低/最高利用率,配合频率决策。
- Android 前台任务通过分组与钳制获得优先调度。
- 调度延迟表现为“R+ 状态”,是卡顿的高频原因。
调度控制主链
逐步解释:
- 可运行:线程进入就绪队列。
- 分组:cpuset 决定可用 CPU。
- 排队:CFS 按虚拟时间排序。
- 钳制:uclamp 影响频率与抢占。
- 执行:最终获得 CPU。
为什么“R+”值得关注
线程状态 R+ 表示“可运行但没被调度”。多核满载或分组限制时,低优任务会被延后, 表现为掉帧与卡顿。Perfetto 里看到 R+ 长时间出现,先查调度分组与负载。
源码证据
阅读目标:确认调度相关实现。
正文指针:kernel/sched/fair.c(CFS);kernel/sched/cpuset.c; kernel/sched/uclamp.c。
// kernel/sched/fair.c(伪代码,行号以 r75 为准)
// CFS 调度队列与虚拟运行时间这段代码证明: CFS 是基础调度器;Android 的进程分组(cpuset)与 uclamp 在 其上层施加控制,最终影响线程获得 CPU 的时机。
验证与排障
环境:开发设备或模拟器;查看分组需要 root。
adb shell cat /proc/<pid>/cpuset
adb shell cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
adb shell su 0 cat /sys/kernel/debug/sched/debug | head -30先看进程所在 cpuset 与可用核,再看频率策略;配合 Perfetto 的 sched 轨道确认调度 延迟。卡顿先确认是否 R+ 状态与调度相关。
常见误区
- “nice 决定一切”:cpuset/uclamp 都在起作用。
- “多核随便跑”:分核与拓扑约束。
- “卡顿都是应用代码”:调度延迟常见。
- “调高优先级万能”:还可能受分组限制。
延伸问题
- Android 的进程分组如何映射到 cpuset?
- uclamp 与频率调节如何协作?
- EEVDF 相比 CFS 改变了什么?
- 大核/小核拓扑如何影响调度?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
kernel/sched/fair.c | CFS | 公平调度 |
kernel/sched/cpuset.c | 分组 | 选核 |
kernel/sched/uclamp.c | 钳制 | 利用率 |
/proc/<pid>/cpuset | 状态 | 排障 |
公共路径:内核 kernel/sched/。行号以 r75 检索为准。
调度及驱动异常如何保存现场,见 内核调试。