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_tick、update_curr、pick_next_entity
include/linux/sched.h task_struct、sched_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_ns、kernel.sched_min_granularity_ns。

5. 设计意图与踩坑

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

Checklist

  • 能指出 schedule → __schedule → pick_next_task → CFS 的文件位置
  • 解释 vruntime 与 nice 权重的关系,并用 /proc/<pid>/sched 对照
  • 区分 fair / rt 调度类,避免用 CFS 参数调实时任务
  • 用 perf sched latency 或 schedstat 看到排队延迟
  • 排查高 load 时先区分 RUN 排队 vs D 状态等盘
  • 容器场景检查 cpu / cpuset 限额,避免无界争抢
相关推荐
Knight_AL36 分钟前
基于 Netty 实现的 WebSocket 服务端
网络·websocket·网络协议
机核研创社43 分钟前
睡裤明橡筋自动化选型指南与落地四步走
运维·自动化
志栋智能44 分钟前
超自动化运维,告别复杂系统的新范式
运维·自动化
零基础1231 小时前
Ubuntu 常用命令汇总
linux·运维·开发语言
Android系统攻城狮1 小时前
Linux Gstreamer深度解析之gst_audio_sink_get_type调用流程与实战(六十五)
linux·运维·服务器·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
xiaoqiMikko1 小时前
Linux 实战(一):CentOS 7、Rocky 9、Ubuntu 24.04 三台真机实测 —— 认清系统、换源、装包的版本坑
linux·centos
迷途之人不知返1 小时前
【基础IO】-1-预备知识与准备工作
linux
xiaoqiMikko1 小时前
Linux 实战(二):端口不通 —— CentOS 7、Rocky 9、Ubuntu 24.04 上防火墙和 SELinux 的实测差异
linux·centos
大鹏的NLP博客2 小时前
WSL Ubuntu 26.04 升级与环境整理记录
linux·ubuntu·wsl
wuyk5552 小时前
《WiFi 嵌入式物联网开发全套实战》| 第 31 章 休眠唤醒 WiFi 断连、时间同步、网络恢复机制
网络·物联网·php