linux cfs调度器_理论模型
参考资料:《调度器笔记》Kevin.Liu
《Linux kernel development》
《深入Linux内核架构》
version: 2.6.32.9
下文中对于红黑树或链表组织的就绪队列,统称为用队列组织的就绪队列。
linux中用struct rq将处于ready状态的进程组织在一起。
struct rq结构体包含cfs和rt成员,分别表示两个就绪队列:cfs就绪队列用于组织就绪的普通进程(这个队列上的进程用完全公平调度器进行调度);rt就绪队列用于组织就绪的实时进程(该队列上的进程用实时调度器调度)。
在多核cpu系统中,每个cpu对应一个struct rq结构体实例。
核心调度器分为:
1、周期性调度器 schedule_tick();
周期性调度器不负责进程的切换,只是定时更新调度相关的统计信息,以备主调度器使用。
2、主调度器 schedule();
主调度器的工作是完成进程的切换,将CPU的使用权从一个进程切换到另一个进程。
调度器类:
linux内核把用于处理普通进程调度的函数用struct sched_class结构体实例fair_sched_class组织起来;
把用于处理实时进程调度的函数用struct sched_class结构体实例rt_sched_class组织起来;
把用于处理idle进程调度的函数用struct sched_class结构体实例idle_sched_class组织起来。
linux中如何决定就绪进程在就绪队列中先后顺序的模型建立衍化过程:
A. runtime公平模型
CPU的总时间按就绪进程数目等分给每个进程,每个进程在就绪队列中的先后顺序由它已享用的(runtime)决定,已享用CPU时间短的进程排在队列的最前面,反之排在队列的后面,调度器每次都选则队列的最前面的进程运行。
漏洞:原有A、B、C三个进程在服务器上运行的runtime各自都等于1年,这时进程D被创建,那么接下来的一年内,只进程D在运行,其它进程如同dead一样……
B. min_runtime公平模型
假设系统中有A、B、C三个进程,其已运行时间为:
---------------------|--------|----------|---------
进程 | A | B | C
---------------------|--------|----------|---------
runtime(ms) | | |
---------------------|--------|----------|---------
什么是“公平”???
操作系统应该在“当前”,将时间公平分配给“当前”系统中的每个进程,“当前”意味着:
a)进程A、B、C在系统中经历了100 + 150 + 200 = 450ms,它们应公平享用这段时间,即每个进程应当执行150ms。
b)D进程被创建了,那么从现在起操作系统应该将CPU时间公平分配给这四个进程(从进程创建之时起,它就应该受到“不计其它进程的历史”的待遇,调度器对所有此后运行的进程一视同仁)。
如果将新建进程D的runtime设置为A、B、C中runtime最大的值显然对进程D不公,如果设置为它们中的最小值,那又对进程A不公。我们将进程D的runtime设置为A、B、C中最小的那个值,这就是在runtime公平模型上改进之后得到的min_runtime公平模型。
C. weight优先级模型
不同进程具有不同的重要性,重要的进程尽量被分配多的CPU时间,不重要的进程应该分配少的CPU时间。
为了达到这个目的,我们引入一个权重(weight)参数,即每个进程有一个权重值,进程得到的CPU时间和这个权重值成正比。
假设进程A、B的权重分别是1,2,这就意味着:A进程执行了Nms后以及B进程执行2Nms后它们应当具有相同的先后顺序,即它们的runtime值基本相同。由于runtime表示进程已经运行的时间,显然和上述表述矛盾,因此我们引入另一个参数vruntime(虚拟运行时间)代替它(vruntime仅仅是一个数值,用来作为对进程进行排序的参考,不用来反映进程真实执行时间).
每个进程有一个vruntime值,调度器总是选择vruntime值最小的进程使用CPU资源,并且vruntime增长的速度和weight值成反比.
设单核处理器上有新建的A、B两个进程:
a) 初始的时候两个进程都没有运行,runtime都等于0
-----------------|-------------|-----------
进程 | A | B
-----------------|-------------|-----------
weight | |
-----------------|-------------|-----------
runtime(ms) | |
-----------------|-------------|-----------
vruntime | |
-----------------|-------------|-----------
按vruntime进行排序 | A B
-------------------------------|-----------
b) 调度器选择A,它运行了4ms:
----------------|----------|-----------
进程 | A | B
----------------|----------|-----------
weight | |
----------------|----------|-----------
runtime(ms) | |
----------------|----------|-----------
vruntime | |
----------------|----------|-----------
按vruntime进行排序 | B A
---------------------------|-----------
c) B的vruntime最小,选择B运行,运行了4ms:
-----------------|----------|-----------
进程 | A | B
-----------------|----------|-----------
weight | |
-----------------|----------|-----------
runtime(ms) | |
-----------------|----------|-----------
vruntime | |
-----------------|----------|-----------
按vruntime进行排序 | B A
----------------------------|-----------
d) B的vruntime最小,选择B运行,运行了4ms:
----------------|----------|-----------
进程 | A | B
----------------|----------|-----------
weight | |
----------------|----------|-----------
runtime(ms) | |
----------------|----------|-----------
vruntime | |
----------------|----------|-----------
按vruntime进行排序 | A B
---------------------------|-----------
e) vruntime相同,但是A在前,选择A运行,运行了4ms:
---------------|---------|-----------
进程 | A | B
---------------|---------|-----------
weight | |
---------------|---------|-----------
runtime(ms) | |
---------------|---------|-----------
vruntime | |
---------------|---------|-----------
按vruntime进行排序 | B A
-------------------------|-----------
f) B的vruntime最小,选择B运行,运行了4ms:
----------------|---------|-----------
进程 | A | B
----------------|---------|----------
weight | |
----------------|---------|-----------
runtime(ms) | |
----------------|---------|-----------
vruntime | |
----------------|---------|-----------
按vruntime进行排序 | B A
--------------------------|-----------
D、period模型
早期调度器使用了时间片模型,例如每当4ms后(或着进程还未执行完4ms,就有特殊情况产生了,比如进程要睡眠),主调度器
schedule就会重新选择一个vruntime值最小的进程来执行。
但是现在我们不用时间片的概念了,那么主调度器schedule应该在什么时候启动并选择一个新的进程执行呢???
引入period参数
系统设定一个period值(它表示一段时间),每个进程对应一个ideal_runtime值(称为理想欲运行时间),每个进程的ideal_runtime值的设定方式:所有可运行进程的ideal_runtime值的和等于period,每个进程的ideal_runtime值的大小与它的权重weight成正比。
该模型规定:每个进程每次获得CPU使用权,最多执行它对应的ideal_runtime这样长的时间。
注意:CPU并没有把时间分成长度为period的时间段,系统仅仅限定了每个进程每次执行时间不能超过它对应的ideal_time指定的时间长度。
如果period=20ms,当前系统中只有A、B、C、D四个进程,它们的weight分别为:1、2、3、4。那么A的ideal_runtime = 2ms,B,C,D的ideal_runtime依次为4ms,6ms, 8ms。
a) 初始情况如下:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | A B C D
--------------------|--------------------------------------------
b) 和前一个模型一样,vruntime的行走速度和权重值成反比,设定权重权为1的A进程的vruntime和实际runtime行走速度相同。A先执行,它执行了2ms,此时:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | B C D A
--------------------|--------------------------------------------
c) B的vruntime值最小,选择B运行,假设B运行了3ms:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | 1.5 | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | C D B A
--------------------|--------------------------------------------
d) C的vruntime值最小,选择C运行,假设C运行了3ms:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | 1.5 | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | D C B A
--------------------|--------------------------------------------
e) D的vruntime值最小,选择D运行,假设D运行了8ms:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | 1.5 | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | C B A D
--------------------|--------------------------------------------
f) 进程D运行的时间等于它的ideal_runtime,调度器被激活,重新选择一个进程运行,接着C进程被选中执行。
关键在于: C可以运行多长时间???
根据ideal_runtime的定义,它只是要求,每个进程每次占用CPU的资源不超过它对应的ideal_runtime,上次进程C被调度的时候它只执行了3ms,没有超过它的ideal_runtime(6ms);但是,这次它又可以获得CPU的使用权了,是新的一次调度了,与之前无关。因此,进程C最多可以运行6ms,那么接下来进程C可以连续运行6ms:
--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | | | |
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
runtime(ms) | | | |
--------------------|-----------|----------|----------|----------
vruntime | | 1.5 | |
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | B A D C
--------------------|--------------------------------------------
不要错误地认为:系统将CPU时间划分成一段一段的,每片长度为period,并且将它们按权重分配给每个进程,并且规定它们在该period内最多执行ideal_runtime限定的时间,进入下一个period时间段后,系统又重新为各个进程分配ideal_runtime; 因为CPU并没有把时间分成长度为period的时间段,系统仅仅限定了每个进程每次执行时不能超过它对应的ideal_time指定的时间长度。
该机制的作用是:每个进程在就绪队列中等地的时间不会超过period,因为每个进程获得CPU使用权后,如果它执行的时间等于它的ideal_runtime,那么它的vruntime基本上就比其它所有进程的vruntime值高了,自然会排到队列的后面。
上述基于weight优先级模型和period模型的调度器所实现的效果, 每个进程每次调度运行的时间不在受4ms(例如)的限制了,而是可以运行“任意”长时间:
a) 每个进程每次获得CPU使用权最多可以执行与它对应的ideal_runtime那么长的时间。
b) 如果每个进程每次获得CPU使用权时它都执行了它对应的ideal_runtime那么长的时间,整个就绪队列的顺序保持不变。
c) 如果某个进程某几次获得CPU使用权时运行的时间小于它ideal_time指定的时间(即它被调度时没有享用完它可以享用的最大
时间),按照vruntime进行排序的机制会使得它尽量排在队列的前面,让它尽快把没有享用完的CPU时间弥补起来。
period抽象模型基本上就是对内核cfs调度机制的一个抽象(没有考虑睡眠,抢占等细节):
a) 每个进程有一个权重值(weight),值越大,表示该进程越优先。
b) 每个进程还对应一个vruntime(虚拟时间),它是根据进程实际运行的时间runtime计算出来的。vruntime值不能反映进程执行的真实时间,只是用来作为系统判断接下来应该选择哪个进程使用CPU的依据————调度器总是选择vruntime值最小的进程执行。
c) vruntime行走的速度和进程的weight成反比。
d) 为了保证在某段时间(period)内每个进程至少能执行一次,操作系统引入了ideal_runtime的概念,规定每次获得CPU使用权时,执行时间不能超过它对应的ideal_runtime值。达到该值就会激活调度器,让调度器再选择一个vruntime值最小的进程执行。
e) 每个进程的ideal_runtime长度与它的weight成正比,如果有N个进程,那么:
task[i]->weight
task[i]->ideal_time = -------------------- * period
sum_weight(task, N)
linux cfs调度器_理论模型的更多相关文章
- linux cfs调度器_模型实现
调度器真实模型的主要成员变量及与抽象模型的对应关系 I.cfs_rq结构体 a) struct sched_entity *curr 指向当前正在执行的可调度实体.调度器的调度单位 ...
- linux cfs调度器
在抽象模型中vruntime决定了进程被调度的先后顺序,在真实模型中决定被调度的先后顺序的参数是由函数entity_key决定的. static inline s64 entity_key(str ...
- Linux内核——进程管理之CFS调度器(基于版本4.x)
<奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...
- Linux进程管理 (2)CFS调度器
关键词: 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 Linux进程管理 ( ...
- 【原创】(五)Linux进程调度-CFS调度器
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- CFS调度器(1)-基本原理
首先需要思考的问题是:什么是调度器(scheduler)?调度器的作用是什么?调度器是一个操作系统的核心部分.可以比作是CPU时间的管理员.调度器主要负责选择某些就绪的进程来执行.不同的调度器根据不同 ...
- Linux CFS调度器之pick_next_task_fair选择下一个被调度的进程--Linux进程的管理与调度(二十八)
1. CFS如何选择最合适的进程 每个调度器类sched_class都必须提供一个pick_next_task函数用以在就绪队列中选择一个最优的进程来等待调度, 而我们的CFS调度器类中, 选择下一个 ...
- Linux CFS调度器之虚拟时钟vruntime与调度延迟--Linux进程的管理与调度(二十六)
1 虚拟运行时间(今日内容提醒) 1.1 虚拟运行时间的引入 CFS为了实现公平,必须惩罚当前正在运行的进程,以使那些正在等待的进程下次被调度. 具体实现时,CFS通过每个进程的虚拟运行时间(vrun ...
- Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)
1. 负荷权重 1.1 负荷权重结构struct load_weight 负荷权重用struct load_weight数据结构来表示, 保存着进程权重值weight.其定义在/include/lin ...
随机推荐
- 3. 支持向量机(SVM)拉格朗日对偶性(KKT)
1. 感知机原理(Perceptron) 2. 感知机(Perceptron)基本形式和对偶形式实现 3. 支持向量机(SVM)拉格朗日对偶性(KKT) 4. 支持向量机(SVM)原理 5. 支持向量 ...
- [转]oracle 11g jdbc jar包在哪个文件目录
oracle 11g jdbc jar包在哪个文件目录 一. 如果装了Oracle数据库的话, 大致是这样的目录: D:\oracle\product\11.2.0\client_1\oui\ ...
- rfid 125khz
环境是STVD V4.1.6, 编译器是COSMIC STM8 C Compiler 16K ,Version: 4.3.1 调用的库有:GPIO,TIM2 相关宏定义: //RF数据引脚 #defi ...
- android——字符串string(转)
原文地址:http://www.open-open.com/lib/view/open1387942832078.html String : 字符串类型 一.构造函数 String(byte[ ...
- js中表单数据序列化方式
一共有以下三种: var obj1 = $('#queryForm').serialize(); var obj2 = $('#queryForm').serializeArray(); var ob ...
- hbase源码系列(六)HMaster启动过程
这一章是server端开始的第一章,有兴趣的朋友先去看一下hbase的架构图,我专门从网上弄下来的. 按照HMaster的run方法的注释,我们可以了解到它的启动过程会去做以下的动作. * <l ...
- Listener 监听对象的创建和销毁
HttpSessionListener.ServletContextListener.ServletRequestListener分别用于控制Session.context.request的创建和销毁 ...
- 安卓程序代写 网上程序代写[原]Android开发技巧--Application
1. Application用途 创建Application时机 : Application在启动的时候会调用Application无参的构造方法创建实例; Application构造方法 : App ...
- 高大上的动态CSS
项目里要添加 custom css 功能 (dynamic stylesheet ),总结一下实现方法. 1.在JSP中动态设定文件path 预先生成一些css文件,由用户选择,在jsp被请求时,动态 ...
- Qt之QLocalSocket
简述 QLocalSocket类提供了一个本地socket. 在Windows中,这是一个命名管道:在Unix中,这是一个本地网域socket. 如果发生错误,socketError()会返回错误的类 ...