1. 前言
第二十届中国Linux开发者大会(CLK)的调度,性能与调试分论坛上,腾讯的内核工程师臧春鑫先生分享了他对eevdf算法改进的经验。其PPT中关于CFS,EEVDF和关闭no parity的EEVDF调度策略对调度延时的影响数据令人印象深刻。

(截图自视频录像,大概1:00:00左右。感兴趣可自行查找观看。)
作为研究Linux进程调度器的工程师,本人对CFS,EEVDF都很熟悉,但是开关parity前后对于调度延时的影响还是给在场聆听的我留下了深刻的印象。因为从未实际测量过相关的数据,没有想到这里的影响有这么大。于是整理了一些相关内容做个笔记,谈谈parity对于调度延时的影响。
事实上,所谓NO PARITY,指的是关闭Linux进程调度器特性RUN_TO_PARITY。而演讲者在讲台上讲解的更多是6.17版本之前的Linux内核,后续版本RUN_TO_PARITY在调度器中发挥的功能又有一些不同。
2.RUN_TO_PARITY
要理解RUN_TO_PARITY特性,首先要理解eevdf算法对next进程的选择逻辑。
- 如果rq中只有一个进程,那甭选择了就它了。否则向下。
- 如果当前进程还没用完slice,让当前进程用完。否则向下。
- 如果rq左下角(deadline最小)的进程合格(eligible),就它了。否则向下。
- 在红黑树中找deadline最小的合格进程。
RUN_TO_PARITY与上面第二步最相关。如何做到让当前进程用完时间片?
当然是进行保护(protect)了。如果保护呢?
进程被选中执行后需要被拿出运行队列,同时会利用sched entity的相关字段做个标记,表示这个进程特殊,它正在执行。在eevdf逻辑中,如果判断出是当前进程处于保护状态就进行保护,让它用完时间片。而RUN_TO_PARITY就与这个逻辑紧密关联。
3. 6.17之前
6.17之前,上节第二步的相关代码实现为:

你看,要保护进程的事件片首先要使能进程调度器的RUN_TO_PARITY特性。
相应的,可以推断,RUN_TO_PARITY的开启会保护调度器的吞吐率,但是会延长调度延时。你可以看到臧工列出的PPT上凡是开启RUN_TO_PARITY的调度延迟都比较大。
4. 6.17及之后
6.17的开发过程中,Vincent Guittot提交了对涉及RUN_TO_PARITY的提交。
其描述为:

从这以后,相应的逻辑修改为:

可以看到,eevdf中是否保护时间片不取决于RUN_TO_PARITY特性,主要取决于protect布尔值是true还是false。
RUN_TO_PARITY更多的在set_protect_slice中:

支持RUN_TO_PARITY的内核在计算保护的时间片长短时,会将运行队列中最小时间片拿出来作为计算数值之一,而不支持这一特性的内核则没有这样的逻辑。