cfs调度类深入解刨——最新内核细节分析1

上一篇《cfs调度类深入解刨------核心结构细节分析》中将cfs基础版本和6.6 eevdf版本的核心概念做了精细化总结,本篇开始进入kernel 7.0及以上版本的分析,有其它版本更新时会有相关标注。

在kernel 7.0及以上版本中(较于kernel 6.6),cfs调度类重点关注权重溢出导致的任务运行异常,优先级反转引起的cpu死锁等问题。因为这些问题在之后的服务器会越来越严重,目前主流服务器逻辑cpu已经达到了512核心,展现出来的问题如cpu负载不均衡,更加频繁的优先级反转导致cpu需要手工干预方式治理等等。

本篇文章做为kernel 7.0及以上版本的开胃菜,先分享一些基础知识。

cfs基础知识
系列文章列表

cfs基础知识

热任务

sysctl_sched_migration_cost = 500000UL

热任务阀值为0.5毫秒,如果一个任务最近一次执行结束(切出)的时间距离现在小于这个值,调度器就认为它的数据还在 CPU 缓存(L1/L2/L3)里,属于"热"任务。

最小虚拟运行时间(min_vruntime)

6.6 eevdf版本中cfs_rq队列的最小虚拟运行时间(min_vruntime)用于key * 权重与虚拟运行时间平均值的运行资格比较(任务入列,出列等情况下更新cfs_rq队列的最小虚拟运行时间,与队列中最小的虚拟运行时间的任务调度实体保持一致)相关的工作,而7.0及以上版本中则将cfs_rq队列的最小虚拟运行时间移植到了调度实体结构中(se->min_vruntime),并且调度实体的最小虚拟运行时间应用在下一个任务选取函数中。

零虚拟运行时间(zero_vruntime)

7.0及以上版本中cfs_rq队列通过零虚拟运行时间(zero_vruntime)取缔最小虚拟运行时间(min_vruntime),累计逻辑与6.6 eevdf版本基本一致。

受保护的截止时间(vprot)

7.0及以上版本中为任务增加受保护的截止时间(vprot),在选取下一个任务或cfs抢占函数中(短抢占不受保护限制,PREEMPT_WAKEUP_SHORT),需要首先满足任务运行的时间达到受保护的截止时间。

计算方式

  1. 开启RUN_TO_PARITY特性的情况,slice = cfs_rq_min_slice(cfs_rq); 返回cfs_rq队列的最小时间片,从cfs_rq队列的当前运行的任务调度实体的时间片和红黑树根节点调度实体的最小时间片中选出。
  2. slice=min(slice,se->slice); 从最小时间片和调度实体时间片(存在默认时间片和自定义时间片两种情况)中选出最小时间片。
  3. se->vprot = min_vruntime(se->vprot, se->vruntime + calc_delta_fair(slice, se)); 调度实体受保护的截止时间赋值,从调度实体受保护的截止时间和"调度实体的虚拟运行时间+cfs_rq队列的最小时间片根据调度实体权重转换出的虚拟运行时间"中选出最小虚拟运行时间。
虚拟运行时间权重总和(sum_w_vruntime)及偏执平均值特性(PARANOID_AVG)

6.6 eevdf版本中出现了cfs_rq队列的虚拟运行时间平均值的概念,选取下一个任务时,"任务的调度实体key(vruntime - cfs_rq->min_vruntime) * 任务的调度实体实际权重"小于这个值表示满足运行资格。

7.0及以上版本中为了解决虚拟运行时间平均值持续增长导致的直接求和容易导致溢出或数值不平衡问题,修改为虚拟运行时间权重总和(sum_w_vruntime)。在求和运算函数中,启动偏执平均值特性(PARANOID_AVG)增加了检查key或cfs_rq队列虚拟运行时间权重总和加法是否溢出,溢出则跳到溢出分支缩放cfs_rq队列所有权重之后再次跳到函数开始位置(again分支)重新运行。

key计算方式:调度实体的虚拟运行时间 - cfs_rq队列的零虚拟运行时间。

溢出分支

  1. cfs_rq队列的偏移量(sum_shift,最小为2,最大为9)+ 1。
  2. cfs_rq队列的虚拟运行时间权重总和及cfs_rq队列的总权重清零,用于重新累计。
  3. cfs_rq队列最左侧节点开始遍历,遍历所有节点对应的调度实体,调度实体右移sum_shift位得到相对权重(代表当前调度实体任务的权重,相当于所有已入列任务根据cfs_rq队列负载进行等比例缩放权重)用于后续计算。
  4. cfs_rq队列的虚拟运行时间权重总累计方式:cfs_rq->sum_w_vruntime += key * 相对权重。
  5. cfs_rq队列的总权重累计方式:cfs_rq->sum_weight += 相对权重。

again分支

  1. 调度实体右移sum_shift位得到相对权重。
  2. 计算key * 相对权重赋值到key,没有溢出继续运行。
  3. 计算cfs_rq->sum_w_vruntime += key,没有溢出继续运行。
  4. cfs_rq队列的虚拟运行时间权重总累计。
  5. cfs_rq队列的总权重累计。
多重抢占唤醒方式

7.0及以上版本中cfs抢占函数增加了无抢占(PREEMPT_WAKEUP_NONE),短抢占(PREEMPT_WAKEUP_SHORT),选取抢占(PREEMPT_WAKEUP_PICK),调度抢占(PREEMPT_WAKEUP_RESCHED)四种模式。

短抢占,满足其中一种条件

  1. 贡献任务(代理调度运行中讲述)是空闲任务并且待唤醒的任务不是空闲任务。
  2. 支持短抢占特性(PREEMPT_SHORT)并且待唤醒的任务时间片小于贡献任务时间片。

选取抢占,不满足短抢占条件并且不包含同步唤醒标志,属于正常抢占流程

  1. cfs_rq队列任务数量为1,cfs_rq队列的当前运行的任务存在并且在rq队列中,返回当前运行的任务,否则返回选取的第一个调度实体。
  2. 开启选中下一个主体特性(PICK_BUDDY) 并且 抢占动作不是短抢占(PREEMPT_WAKEUP_SHORT) 并且 cfs_rq队列下一个调度实体存在 并且 在cfs_rq队列中有运行资格,返回cfs_rq队列下一个调度实体。
  3. cfs_rq队列的当前运行的任务存在 并且 抢占动作不是短抢占(PREEMPT_WAKEUP_SHORT) 并且 调度实体已运行足够多(虚拟运行时间大于或等于受保护的截止时间),返回当前运行的任务。
  4. 最左侧调度实体存在并且在cfs_rq队列中有运行资格,从base和curr中选取截止时间最早的返回。
  5. cfs_rq队列的红黑树根节点遍历,找到最小虚拟运行时间的调度实体并且符合运行条件,然后从base和curr中选取截止时间最早的返回。

调度抢占

  1. 任务的调度实体截止时间在贡献任务调度实体截止时间之前并且实际运行时间大于等于热任务阀值。
cfs_rq队列叶子链表节点

cfs_rq队列叶子链表节点的概念一直都存在(在5.10版本也接触过),这次讲述一下它的作用。cfs_rq队列没有被层级限流(throttle_count)的情况下,调用list_add_leaf_cfs_rq函数将当前cfs_rq队列叶子链表节点嵌入到rq队列的叶子链表中,并将on_list设置为1。

通常情况下,rq队列的孤立分支的链表指针(tmp_alone_branch)指向rq队列链表头(leaf_cfs_rq_list),表示链表是正常,完整的。

嵌入规则

  1. cfs_rq队列所在的任务组有父节点 并且 cfs_rq队列所在的任务组的父节点的cfs_rq队列在rq队列的叶子链表中,将cfs_rq队列叶子链表节点嵌入到cfs_rq队列所在的任务组的父节点的cfs_rq队列的叶子链表(节点)中。
  2. cfs_rq队列所在的任务组没有父节点,将cfs_rq队列叶子链表节点嵌入到rq队列的叶子链表中。
  3. cfs队列叶子链表嵌入临时用于孤立分支的链表中,这种属于异常情况。

系列文章列表

《cfs调度类深入解刨------核心结构的用意》
《cfs调度类深入解刨------核心结构细节分析》

相关推荐
MC皮蛋侠客1 小时前
Perf 火焰图深度实战:CPU 性能分析与异常排查完全指南
linux·c++·性能分析·perf·火焰图
maosheng11461 小时前
NFS服务器的搭建有多种类型linux-linux
linux·运维·服务器
普通young man1 小时前
Linux基础开发工具集合
linux·运维·服务器
z200509301 小时前
【Linux学习】Linux中进程终止和进程等待
linux·学习·操作系统
码农阿强1 小时前
OpenAI Codex 全平台详细安装与配置教程(Windows/Mac/Linux)
linux·windows·macos·ai
用户2367829801681 小时前
Linux mv 命令:文件移动与重命名的底层机制
linux
都在酒里2 小时前
Linux字符设备驱动开发(一):从零搭建一个可直接运行的驱动框架(附完整代码)
linux·运维·驱动开发
蓝莓薄荷2 小时前
Ubuntu修改主机名操作指南
linux·ubuntu