上一篇《cfs调度类深入解刨------核心结构的用意》中将cfs基础版本和6.6 eevdf版本的核心概念做了总结,本篇较上一篇技术上增加细节区别。
在kernel 7.0及以上版本中,eevdf做了较大的修改,增加了避免优先级反转(代理调度运行)等技术手段,之后文章会做详细分析。
cfs基础版本与eevdf版本细节分析
调度策略
cfs调度类主要包括sched_normal和sched_batch策略,其中sched_normal策略表示默认普通任务,在cfs的抢占函数逻辑中,高优先级任务运行或唤醒时允许抢占目标cpu中运行的sched_normal策略任务,通过在目标cpu的rq->curr中设置TIF_NEED_RESCHED标志达到下一个调度时刻的任务切换,从而达到cpu抢占目标。而sched_batch策略任务更倾向于运行完整的时间片,cfs的抢占函数逻辑中不允许抢占sched_batch策略任务,从而达到更少的任务切换次数,更长的运行时间等特点,在cpu密集型,非交互式等任务中通常使用这类策略,保持缓存的热度,提高指令执行效率。
调度选取任务
cfs基础版本(eevdf之前版本)普通任务在运行过程中被抢占,此时更新本身的虚拟运行时间(累计本次实际运行时间根据任务权重转换的虚拟运行时间)和所在cfs_rq的最小虚拟运行时间,当任务所在的cfs_rq队列选取下一个任务时,cfs基础版本调度类很可能错过上次被抢占的任务,因为上次被抢占的任务更新虚拟运行时间之后存在不是cfs_rq队列最小虚拟时间的情况,因此实时性方面不太友好。
cfs eevdf版本调度类中增加deadline概念(选择任务标准:1. 支持NEXT_BUDDY特性并且next具有运行资格,选取next,2. cfs_rq队列中属于最小deadline的任务),虽然任务被抢占更新了虚拟运行时间,但只要任务的虚拟运行时间不超过任务的deadline基本不更新deadline(超过则更新为下一个deadline周期),因此cfs_rq队列选取的下一个任务还是这个被抢占的任务(支持NEXT_BUDDY特性的情况需要next任务已被清除,通常在抢占的任务出列、主动让出cpu、更新deadline周期等场景下清除),实时性方面得到了较大的改进。
惩罚和补充
cfs基础版本任务入列或出列及迁移入列到其它cpu时的部分条件下更新虚拟运行时间,通过任务的调度实体虚拟运行时间累加或累减cfs队列最小虚拟运行时间达到虚拟运行时间的归一化,用于快速确定cfs任务的运行时期是cfs_rq队列的当前周期还是下一个周期。cfs基础版本新创建的任务基本在下一个周期或之后才能得到运行,而唤醒的任务在支持GENTLE_FAIR_SLEEPERS特性的情况下,得到二分之一虚拟运行时间周期补偿(sysctl_sched_latency)提前运行。
cfs eevdf版本调度类中通过虚拟运行时间平均值减去虚拟滞后值(lag,(调度实体的虚拟滞后值 * cfs_rq所有任务的实际权重之和) / cfs_rq所有任务的实际权重之和(包括调度实体自身))得到调度实体的虚拟运行时间。通过通用实际时间(如默认0.75毫秒)转换为虚运行时间方式得到虚拟时间片,新创建的任务支持PLACE_DEADLINE_INITIAL特性并且是入列初始化补偿半个虚拟时间片(vslice/=2;)。