CFS调度源码:从 schedule() 到pick_next_entity 的vruntime 公平

线上 CPU 打满、延迟抖动、D 状态误判,根因常在调度路径。本文沿 schedule()__schedule() → CFS pick_next_entity() 走通一次选路,用真实文件定位 vruntime 与红黑树,方便对照 perf sched / schedstat 验证。

源码锚点

路径 作用
kernel/sched/core.c schedule()__schedule()、上下文切换入口
kernel/sched/fair.c CFS:entity_tickupdate_currpick_next_entity
include/linux/sched.h task_structsched_entity
include/linux/sched/sysctl.h 调度相关 sysctl
Documentation/scheduler/sched-design-CFS.rst CFS 设计说明

核心结构(节选概念):

c 复制代码
/* include/linux/sched.h --- sched_entity */
struct sched_entity {
	struct load_weight	load;
	struct rb_node		run_node;
	u64			vruntime;
	/* ... */
};

struct task_struct {
	struct sched_entity	se;
	const struct sched_class *sched_class;
	/* ... */
};

选路骨架:

c 复制代码
/* kernel/sched/core.c --- 概念路径 */
asmlinkage __visible void __sched schedule(void)
{
	struct task_struct *tsk = current;
	sched_submit_work(tsk);
	__schedule(SM_NONE);
	sched_update_worker(tsk);
}

调用链

text 复制代码
用户态阻塞 / 时间片耗尽 / 抢占点
  → schedule()                     /* core.c */
      → __schedule(sched_mode)
          → pick_next_task(rq, prev, &rf)
              → 按优先级扫 sched_class
                  → fair_sched_class.pick_next_task
                      → pick_next_entity(cfs_rq)
                          → 红黑树最左 = 最小 vruntime
              → context_switch(prev, next)
                  → switch_mm / switch_to

时钟滴答侧:

text 复制代码
scheduler_tick
  → task_tick_fair
      → entity_tick → update_curr
          → 累加 delta_exec,换算进 se->vruntime

重点知识

1. vruntime 是公平的尺子

CFS 不按固定时间片轮转,而按 虚拟运行时间 排序。nice 通过权重放大/缩小同一墙上时间对应的 vruntime 增量:nice 越小,同等墙钟时间里 vruntime 涨得越慢,树中越靠左,越容易被再次选中。

2. 红黑树只存可运行实体

cfs_rq->tasks_timeline 上每个可运行 sched_entity 一个节点;pick_next_entity 取最左。入队 enqueue_entity、出队 dequeue_entity 必须与状态机一致,否则会出现「看起来 RUN 却不在树上」。

3. 调度类分层

stop > dl > rt > fair > idle。普通业务几乎都在 fair;实时任务走 rt/dl,不会与 CFS 争同一把 vruntime 尺。排障时先分清任务是否被绑到 RT。

4. 配置与观测

bash 复制代码
# 调度统计(需 CONFIG_SCHEDSTATS)
grep -E 'sched_' /proc/self/sched
cat /proc/schedstat | head
# 延迟剖析
perf sched record -a -- sleep 5
perf sched latency
# nice / 亲和
chrt -m
taskset -pc <pid>

常见 sysctl(名称随内核略有差异,以本机 sysctl -a | grep sched 为准):kernel.sched_latency_nskernel.sched_min_granularity_ns

5. 设计意图与踩坑

  • 意图:多任务长期公平,短任务延迟可控。
  • :把 DTASK_UNINTERRUPTIBLE)当 CPU 忙------它常在等 I/O,加核无效。
  • :容器未设 cpu.max / cpuset,与宿主机抢同一 CFS 池。
  • :持锁过久导致调度延迟,表现为尾延迟而非平均 CPU。

Checklist

  • 能指出 schedule__schedulepick_next_task → CFS 的文件位置
  • 解释 vruntime 与 nice 权重的关系,并用 /proc/<pid>/sched 对照
  • 区分 fair / rt 调度类,避免用 CFS 参数调实时任务
  • perf sched latencyschedstat 看到排队延迟
  • 排查高 load 时先区分 RUN 排队 vs D 状态等盘
  • 容器场景检查 cpu / cpuset 限额,避免无界争抢
相关推荐
@insist12318 分钟前
系统集成项目管理工程师-采购、风险与干系人管理
网络·软考·系统集成项目管理工程师·软考中项·软件水平考试
bu_shuo23 分钟前
Linux中修改demo.c文件的权限
linux·c语言
0+11126 分钟前
Linux --库制作与原理
linux·运维·服务器
uxiang_blog27 分钟前
Linux修改计算名字和添加删除用户名。
linux·运维·服务器
大模型码小白39 分钟前
MCP协议开发实战:从零搭建AI Agent工具链
运维·人工智能·算法·机器学习·自动化
Syc1102g42 分钟前
在 Linux CentOS 系统中设置静态 IP
linux·网络·计算机网络·个人开发
2601_9622035142 分钟前
Nginx 安装配置
运维·nginx
YQ_0143 分钟前
ROS 2 Humble Nav2 生命周期教程:启动流程、状态监控、超时诊断与自愈设计
linux·机器人·ros2·nav2
loong_XL1 小时前
Windows WSL2 Ubuntu 搭建 Xvfb 虚拟桌面环境,完美支持多 Agent 隔离
linux·windows·ubuntu