Linux: sched: pick_next_task_fair 这个函数的功能

文章目录

Cursor的总结

问题:kernel/sched/fair.c,帮总结pick_next_task_fair 这个函数的功能,并且画出流程图,以及抽象的组织结构体

pick_next_task_fair 在做什么

它是 CFS(SCHED_NORMAL/SCHED_BATCH) 在 schedule() 里选"下一个谁跑" 的入口:在 CPU 的 rq 上,从 CFS 红黑树里选出 vruntime 最该运行 的实体,一路下到 叶子任务 ;必要时把 上一个任务 从树里"卸下"、把 新选中 的挂上;若没有可运行 CFS 任务则走 idle / newidle_balance 路径。

核心代码:

7191:7332:c:\open_source\linux-5.14.1\kernel\sched\fair.c 复制代码
struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{
	struct cfs_rq *cfs_rq = &rq->cfs;
	struct sched_entity *se;
	struct task_struct *p;
	int new_tasks;

again:
	if (!sched_fair_runnable(rq))
		goto idle;
	// ... CONFIG_FAIR_GROUP_SCHED 快速路径 vs simple ...
	// done: 链表/hrtick/misfit,return p
idle:
	if (!rf)
		return NULL;
	new_tasks = newidle_balance(rq, rf);
	// RETRY_TASK / goto again / NULL
}

要点:

  1. sched_fair_runnable(rq)

    等价于 rq->cfs.nr_running > 0。为假时 CFS 侧无人可跑,进入 idle。

  2. CONFIG_FAIR_GROUP_SCHED 时的"快速路径" (prev 存在且仍是 fair_sched_class)

    • 不先整棵调用 put_prev_task,而是沿 cgroup 层级 用 pick_next_entity 选下一个实体,并 update_curr / check_cfs_rq_runtime。
    • 若选出的任务 prev != p ,只在 新旧路径在树上的分叉处 成对调用 put_prev_entity / set_next_entity,减少整层遍历。
    • 若 prev == p,相当于继续跑当前任务,几乎不动树。
  3. simple 路径

    • 若有 prev,先 put_prev_task(rq, prev) (整链 put_prev_entity)。
    • 自根 cfs_rq 起循环:pick_next_entity → set_next_entity → group_cfs_rq(se) ,直到叶子,p = task_of(se)。
  4. 返回前(done)

    • SMP:把 p 的 se.group_node 移到 rq->cfs_tasks 前(MRU)。
    • 可选 hrtick_start_fair 、update_misfit_status。
    • 返回 p。
  5. idle 分支

    • rf == NULL :无法做 newidle 平衡,直接 NULL (例如 __pick_next_task_fair 里 prev 为 NULL)。
    • 否则 newidle_balance :
      • < 0 → 返回 RETRY_TASK(锁被释放过,需重新选);
      • > 0 → goto again;
      • 0 → update_idle_rq_clock_pelt ,返回 NULL(CPU 将 idle)。

流程图(Mermaid)

否
是
是
是
否
否
否
是
< 0
> 0
0
进入 pick_next_task_fair
rq->cfs.nr_running > 0?
idle 分支
CONFIG_FAIR_GROUP_SCHED 且 prev 为 fair?
快速路径: 沿层 pick_next_entity / update_curr / check_cfs_rq_runtime
prev != 选中的 p?
在分叉处 put_prev_entity / set_next_entity
MRU 链表 / hrtick / update_misfit_status
simple: put_prev_task 若有 prev
pick_next_entity -> set_next_entity 直到叶子
return p
rf != NULL?
return NULL
newidle_balance
new_tasks
return RETRY_TASK
goto again
update_idle_rq_clock_pelt
return NULL


抽象组织结构(数据关系)

从 "选下一个任务" 的角度,可以看成下面几层:

抽象 含义
struct rq 每个逻辑 CPU 一条 运行队列 ;rq->cfs 是这条 CPU 上的 CFS 根队列。
struct cfs_rq CFS 红黑树 + 当前 curr ;组调度时 子 cgroup 对应 子 cfs_rq ,挂在父实体的 group_cfs_rq 链上向下走。
struct sched_entity 调度实体:普通任务 一个 task_struct 里一个 se;cgroup 则是一组任务在树上的 组实体 ,用 pick_next_entity 在树里选 最小 vruntime 的下一个。
struct task_struct 最终选中的 进程/线程 ;task_of(se) 从叶子 se 得到。

关系示意:

text 复制代码
                    per-CPU
                 +----------+
                 |   rq     |
                 +----------+
                       |
                 +----------+
                 |  cfs_rq  |  <- rq->cfs,CFS 根
                 | (rb-tree)|
                 +----------+
                    /    \
            sched_entity ...  (task 或 group)
                 |
    [组调度] group_cfs_rq(se) -> 子 cfs_rq -> 再 pick_next_entity ...
                 |
    [叶子]       task_of(se) -> task_struct (下一个运行的 p)

一句话 :pick_next_task_fair 在 rq->cfs 为根的 CFS 树(及组调度时的子 cfs_rq 链) 上选出下一个 sched_entity ,落到 task_struct ,并和 prev 一起决定是走 增量 put/set 还是 整链 put_prev_task + set_next_entity ;无人可跑则配合 newidle_balance 尝试拉任务或返回 idle/重试。

相关推荐
一去不复返的通信er16 小时前
力扣-图论-岛屿数量
算法·leetcode·图论
0+11117 小时前
Linux --从 poll 到 epoll多路转接
linux·服务器·1024程序员节
青瓦梦滋17 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
桌面运维家17 小时前
旧电脑跑不动课程软件,VDI云桌面怎样接着用?
运维·服务器·虚拟化·pve·vdi·云桌面
zhang1338308907518 小时前
传统机械三杯式风速传感器易磨损冻堵?CG-88金属超声波风速风向传感器给出免运维方案
运维·服务器·网络·人工智能·自动化
知已难寻18 小时前
第 2 篇 · 云的地基:服务器、存储、网络三大基础设施
运维·服务器·网络·云原生·云计算·负载均衡·1024程序员节
程序 代码狂人19 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
HDU-Dade20 小时前
【校招笔试真题】简要介绍 Self-Attention 的前沿算法
人工智能·算法
2601_9498477520 小时前
bcrypt.js 跨端三方库仓颉适配全流程
linux·运维·ubuntu
m0_6399069420 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端