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 限额,避免无界争抢
相关推荐
GeW1 小时前
红帽RHCE从挂科边缘到一次过,我做对了什么
linux
时空自由民.1 小时前
WSL解决USB 串口连接问题与linux串口权限问题
linux·单片机
OpenPomeloxCommunity1 小时前
Linux驱动基础(三):firmware的声明与加载
linux·操作系统
云计算练习生1 小时前
什么是系统调用?为什么程序访问硬件必须经过它
linux·windows·操作系统·系统调用·操作系统原理
boxiansheng1632 小时前
408计算机网络
网络·计算机网络·智能路由器
闲云野鹤在人间2 小时前
docker 入门 | 第7章 容器监控 和 第8章 容器日志 详解
运维·docker·容器·架构·云计算
亚川楼宇自控系统数据中心厂家2 小时前
IBMS 集成如何打通数据中心的子系统数据孤
运维
玄芯散人2 小时前
【筑基·059】Linux命令行入门:工程师的操作系统
linux·操作系统·命令行
闲云野鹤在人间2 小时前
docker 入门 | 第5章 网络详解
网络·docker·架构·华为云·php
半仙白桑2 小时前
内核篇第二讲:Linux exec 函数族详解
linux·linux驱动