CFS调度器学习总结
CFS调度器学习总结
- CFS基本概念
- CFS调度对象
- CFS调度依据
- CFS虚拟时钟
- CFS调度过程
- CFS数据结构
- CFS调度代码
介绍CFS的基本概念和核心数据结构。
CFS基本概念
completely fair scheduler 完全公平调度算法,尽可能使就绪队列中的每个进程占用大致相等的虚拟执行时间。
确保在一定时间段内,当前CPU上所有的就绪进程都会得到至少一次执行。每个进程的虚拟执行时间和进程的权重成正相关,并且能够充分利用CPU资源。
CFS调度对象
用于处理当前CPU上就绪任务中普通进程(优先级在100-130范围内)的调度类。
CFS调度依据
CFS使用进程的虚拟执行时间来作为调度的唯一依据。在相同的实际时间段时,权重越大的进程,虚拟执行时间越小。因此,为了使各个进程的虚拟执行时间大致相等,权重大的进程能够得到更多的执行机会。
为了便于理解使用虚拟执行时间作为调度依据的理由,我们先来看看基于权重划分时间片的调度。
Linux内核中进程调度里时间段是一个动态调整的,其变化可如下函数表示:slice=max{default_slice,default_slice∗NR/5}slice = max \{default\_slice, default\_slice * NR / 5\}slice=max{default_slice,default_slice∗NR/5}
其中, NRNRNR是当前CPU中就绪进程的个数,default_slicedefault\_slicedefault_slice当前的默认值时20ms20ms20ms, 因此,上式又可写成
slice=max{20ms,4∗NR}slice = max \{20ms, 4 * NR \}slice=max{20ms,4∗NR}
将slicesliceslice按照进程的权重划分给每个进程,得到每个进程在当前slicesliceslice内能够执行的最长时间TiT_iTi:
Ti=slice∗Wi∑i=1nWiT_i = slice * \frac{W_i}{\sum_{i=1}^nW_i}Ti=slice∗∑i=1nWiWi
其中,进程的权重和进程优先级是一一对应的,普通进程的优先级范围是[100,139][100, 139][100,139]共40个,Linux内核中定义了一个长度为40的权重数组,详见kernel/sched/core.c:
可根据进程的优先级和nice值获取对应的进程权重, nice值得范围时[−20,19][-20,19][−20,19], 进程的默认优先级是prio是120。index=prio+nice−100index = prio + nice - 100index=prio+nice−100 , 由此可知,当进程处于默认优先级时,权重为1024。nice越小,执行需求越大,优先级数值越低,权重越大。
程序会完全按照划分的时间片执行吗?
考虑如下情形:
- 等待IO过程中进入阻塞队列
- 主动让出CPU
- 被更高优先级进程抢占
此外,并不能保证每个进程时间片结束时一定会有一个时钟中断,会导致时钟中断到来时,程序执行时间已经大于分配到的时间片。也会导致其它进程的实际执行时间小于分配的时间片。
为了解决上述问题,对执行时间大于分配时间片的进程进行惩罚,对执行时间小于分配的时间片进行补贴,实现尽可能的公平调度,CFS引入了虚拟时钟的概念。调度器CFS和各个进程分别有自己的虚拟时钟。
CFS虚拟时钟
进程的虚拟时钟记录了进程已经执行的实际时间对应的虚拟时间。其值可通过下式求得:
VTi=Ti∗1024WiVT_i = T_i * \frac{1024}{W_i}VTi=Ti∗Wi1024
其中,VTiVT_iVTi 是进程iii的虚拟执行时间,TiT_iTi是进程的实际执行时间,显然进程的虚拟执行时间和进程权重成反比。当进程处于默认优先级,且nice值为0时,进程的虚拟执行时间等于实际执行时间。
由于上式包含除法,计算比较耗时,可对上式变形得VTi=Ti∗1024∗232Wi1232VT_i = T_i * 1024 * \frac{2^{32}}{W_i}\frac{1}{2^{32}}VTi=Ti∗1024∗Wi2322321
其中232Wi\frac{2^{32}}{W_i}Wi232可提前算出,详见kernel/sched/core.c。
在实际调度过程中,优先选择虚拟执行时间最小的进程执行。对于同样的实际执行时间来说,进程nice值越低(对CPU的占有欲望越强)->优先级数值越低->执行优先级越高->进程权重越大,就有越多的机会得到执行。
CFS调度过程
假设有三个进程A、B、C, 优先级分别为115, 120, 125…
时间片:slice=20msslice = 20msslice=20ms
就绪进程总权重:W总=4480W_总 = 4480W总=4480,
进程A时间片:Ta=13.9330,权重:Wa=3121T_a = 13.9330, 权重:W_a=3121Ta=13.9330,权重:Wa=3121,
进程B时间片:Tb=4.5714,权重:Wb=1024T_b = 4.5714, 权重:W_b=1024Tb=4.5714,权重:Wb=1024,
进程C时间片:Tc=1.4956,权重:Wc=335T_c = 1.4956, 权重:W_c=335Tc=1.4956,权重:Wc=335,
当实际时间经过时间T=1msT=1msT=1ms时,CFS调度器的虚拟时间:
VTcfs=T∗1024∗1W总=T∗1024∗232W总∗1232=0.2286VT_{cfs} = T * 1024 * \frac{1}{W_总} = T* 1024 * \frac{2^{32}}{W_总} *\frac{1}{2^{32}} =0.2286VTcfs=T∗1024∗W总1=T∗1024∗W总232∗2321=0.2286
各进程虚拟时间:
VTa=T∗1024Wa=T∗1024∗2323121∗1232=0.3281VT_a = T * \frac{1024}{W_a} = T * 1024 * \frac{2^{32}}{3121} *\frac{1}{2^{32}} = 0.3281VTa=T∗Wa1024=T∗1024∗3121232∗2321=0.3281
VTb=T∗1024Wb=T∗1024∗2321024∗1232=1VT_b = T * \frac{1024}{W_b} = T * 1024 * \frac{2^{32}}{1024} *\frac{1}{2^{32}} = 1VTb=T∗Wb1024=T∗1024∗1024232∗2321=1
VTc=T∗1024Wc=T∗1024∗232335∗1232=3.0567VT_c = T * \frac{1024}{W_c} = T * 1024 * \frac{2^{32}}{335} *\frac{1}{2^{32}} = 3.0567VTc=T∗Wc1024=T∗1024∗335232∗2321=3.0567
实际时钟 | csf的虚拟时钟 | 进程A的虚拟时钟 | 进程B的虚拟时钟 | 进程C的虚拟时钟 | 备注 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | A 优先级最高,先执行 |
1 | 0.2286 | 0.3281 | 0 | 0 | VTa>VTVT_a > VTVTa>VT, B优先级大于C选择B执行 |
2 | 0.4572 | 0.3281 | 1 | 0 | VTb>VTVT_b > VTVTb>VT, 选择C执行 |
3 | 0.6858 | 0.3281 | 1 | 3.0567 | VTc>VTVT_c > VTVTc>VT, 选择A执行 |
4 | 0.9144 | 0.6562 | 1 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 选择奖励A继续执行 |
5 | 1.1430 | 0.9843 | 1 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 选择奖励A继续执行 |
6 | 1.3716 | 1.3124 | 1 | 3.0567 | VTa>VTbVT_a > VTbVTa>VTb, 选择B执行 |
7 | 1.6002 | 1.3124 | 2 | 3.0567 | VTb>VTVT_b > VTVTb>VT, 选择A继续执行 |
8 | 1.8288 | 1.6405 | 2 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
9 | 2.0574 | 1.9686 | 2 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
10 | 2.2860 | 2.2967 | 2 | 3.0567 | VTa>VTVT_a > VTVTa>VT, 选择B继续执行 |
11 | 2.5146 | 2.2967 | 3 | 3.0567 | VTb>VTVT_b > VTVTb>VT, 选择A继续执行 |
12 | 2.7432 | 2.6248 | 3 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
13 | 2.9718 | 2.9529 | 3 | 3.0567 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
14 | 3.2004 | 3.2810 | 3 | 3.0567 | VTa>VTVT_a > VTVTa>VT, 选择B继续执行 |
15 | 3.4290 | 3.2810 | 4 | 3.0567 | VTb>VTVT_b > VTVTb>VT, 选择C继续执行 |
16 | 3.6576 | 3.2810 | 4 | 6.1134 | VTc>VTVT_c > VTVTc>VT, 选择A继续执行 |
17 | 3.8862 | 3.6091 | 4 | 6.1134 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
18 | 4.1148 | 3.9372 | 4 | 6.1134 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
19 | 4.3434 | 4.2653 | 5 | 6.1134 | VTa>VTbVT_a > VT_bVTa>VTb, 选择B继续执行 |
20 | 4.5720 | 4.2653 | 5 | 6.1134 | VTa<VTVT_a < VTVTa<VT, 奖励A继续执行 |
总结上述过程,进程A 优先级最高,占用最多的时间片执行了约13ms,B执行了5ms, C 执行了2ms. 其中A执行的实际时间小于理想时间片TaT_aTa 下一次会优先执行, B和C执行的实际时间大于理想时间片, 下一轮中会被惩罚,让A优先执行。基于虚拟时钟,让各个进程执行的虚拟时间趋于一致,同时令各个进程的实际执行时间接近划分的理想时间。
CFS数据结构
每个CPU都有一个cfs_rq对象 维护着普通进程就绪队列中的总权重,并指向当前运行进程的sched_entity(每个进程的task_struct中有一个sched_entity结构)
CFS调度代码
每次时钟中断会调用scheduler_tick()函数,该函数是调度器的核心。 其内部过程如下:
|> tick_handle_periodic // dev->event_handler
|-> tick_periodic
|–> update_process_times // 在时钟中断处理程序中调用,因此后续都处于中断上下文中
|—> scheduler_tick
|----> curr->sched_class->task_tick(rq, curr, 0);
|----> .task_tick = task_tick_fair // 调度器tick函数 由时钟中断调用
|-----> entity_tick(cfs_rq, se, queued)
|------> update_curr(cfs_rq); // 更新进程的统计信息
|-------> check_preempt_tick //如果需要,唤醒一个新进程,抢占当前进程(发生在 entity_tick最后)
|--------> 如果需要重新调度(执行时间大于理想的执行时间或虚拟执行时间大于cfs_rq中的最小虚拟执行时间)
|---------> resched_curr(rq_of(cfs_rq)); // 只是确保当前进程的TIF_NEED_RESCHED 标志位被设置(并没有发生进程切换)
CFS调度器学习总结相关推荐
- [Linux][内核学习笔记]--CFS调度器
文章目录 1. 进程的状态转换 2. 内核调度器的发展 3. 调度策略 4. 与调度相关的系统调用 5. 优先级 6. CFS调度器的实现 6.1 相关结构体 6.1.1 sched_entity 结 ...
- 用c语言实现对n个进程采用“短进程优先”算法的进程调度_为什么Linux CFS调度器没有带来惊艳的碾压效果?...
文章转自公众号"人人都是极客" 但凡懂Linux内核的,都知道Linux内核的CFS进程调度算法,无论是从2.6.23将其初引入时的论文,还是各类源码分析,文章,以及Linux内核 ...
- 为什么Linux CFS调度器没有带来惊艳的碾压效果? | CSDN博文精选
任何领域,革命性的碾压式推陈出新并不是没有,但是概率极低,人们普遍的狂妄在于,总是认为自己所置身的环境正在发生着某种碾压式的变革,但其实,最终大概率不过是一场平庸. 作者 | dog250 责编 | ...
- 进程管理(二十二)—CFS调度器
CFS是内核使用的一种调度器或调度类,它主要负责处理三种调度策略:SCHED_NORMAL.SCHED_BATCH和SCHED_IDLE.调度器的核心在挑选下一个运行的进程时有可能会遍历所有的调度类别 ...
- Linux进程调度-CFS调度器原理分析及实现,懂了
1. 概述 (1) Completely Fair Scheduler,完全公平调度器,用于Linux系统中普通进程的调度. (2) CFS采用了红黑树算法来管理所有的调度实体 sched_entit ...
- cpu调度的最小单位_Linux CFS调度器
一直没有写过关于Linux内核调度器的内容,这几天被问起,简单的讲了讲,收到一堆challenge,这次决定做一个通篇总结方便自己整理思路. 要说Linux2.4和2.6最大的差异就在于CFS调度器的 ...
- 【Linux 内核】CFS 调度器 ⑥ ( CFS 调度器就绪队列 cfs_rq | Linux 内核调度实体 sched_entity | “ 红黑树 “ 数据结构 rb_root_cached )
文章目录 一.CFS 调度器就绪队列 cfs_rq 二.Linux 内核调度实体 sched_entity 三." 红黑树 " 数据结构 rb_root_cached 一.CFS ...
- 【Linux 内核】CFS 调度器 ⑤ ( CFS 调度器类 fair_sched_class 源码 | next 赋值 | enqueue_task 赋值 | dequeue_task 赋值 )
文章目录 一.调度器类 sched_class 简介 二.CFS 调度器类源码 三.next 赋值 四.enqueue_task 赋值 五.dequeue_task 赋值 一.调度器类 sched_c ...
- 【Linux 内核】CFS 调度器 ② ( CFS 调度器 “ 权重 “ 概念 | CFS 调度器调度实例 | 计算进程 “ 实际运行时间 “ )
文章目录 一.CFS 调度器 " 权重 " 概念 二.CFS 调度器调度实例 ( 计算进程 " 实际运行时间 " ) 一.CFS 调度器 " 权重 & ...
最新文章
- 聊聊网易技术如何帮教育行业开出花
- POJ2195 Going Home 最小费用最大流
- Yii2几个要注意的小地方
- mac idea在mybatis xml文件里引入全限定类名报红解决
- java线程“生产/消费”模型2
- 180118 有趣的人工智能对话小程序
- LeetCode 2090. 半径为 k 的子数组平均值(滑窗)
- php上传文件 报的错误 $_FILES[‘file’]['error']
- 两个方法事务调用问题
- 海豚浏览器历年笔试题
- php实现禁止缓存,高手莫来
- 简易sql词法分析器和语法分析器
- 关于卸载office的问题:office无法卸载的办法(附office安装和注册表查看)
- [Github] You‘ve successfully authenticated, but GitHub does not provide shell access.
- 过账期间未清和关帐过帐期间设置
- App uni.downloadFile ios问题
- pc控制iphone的软件_评论:苹果M1芯片版MacBook和Mac Mini将颠覆整个PC行业?
- android+usb+摄像头+app+开源,Android 使用摄像头拍照
- 山水印|竹林野茶:秋冬之际,喝这些茶补水润肺
- 最近在逛知乎的时候发现一个有趣的问题:公司规定所有接口都用 post 请求,这是为什么?
热门文章
- python学习爬取数据二级页面的数据
- 智能客服赛道:网易七鱼、微洱科技打法迥异
- 财会法规与职业道德【4】
- RTP H264 NAL
- GBDT,XGBoost和LightBoost对比
- 客户说发货慢怎么回复_拼多多买家催发货怎么回复(拼多多客户催货应对技巧)...
- Python自动发短信
- WPF 在编译时 显示 CS0426	类型“xxx”中不存在类型名“xxx”
- com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method XXX in the service
- python自动化(五)接口自动化:4.接口自动化框架搭建实战