转自:http://www.cnblogs.com/openix/p/3254394.html

下文中对于红黑树或链表组织的就绪队列,统称为用队列组织的就绪队列。                                              
    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) | 100 | 150 | 200
---------------------|--------|----------|---------

什么是“公平”???
    操作系统应该在“当前”,将时间公平分配给“当前”系统中的每个进程,“当前”意味着:
        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 | 1 | 2
-----------------|-------------|-----------
runtime(ms) | 0 | 0
-----------------|-------------|-----------
vruntime | 0 | 0
-----------------|-------------|-----------
按vruntime进行排序 | A B
-------------------------------|-----------

b) 调度器选择A,它运行了4ms:

  ----------------|----------|-----------
进程 | A | B
----------------|----------|-----------
weight | 1 | 2
----------------|----------|-----------
runtime(ms) | 4 | 0
----------------|----------|-----------
vruntime | 4 | 0
----------------|----------|-----------
按vruntime进行排序 | B A
---------------------------|-----------

c) B的vruntime最小,选择B运行,运行了4ms:

 -----------------|----------|-----------
进程 | A | B
-----------------|----------|-----------
weight | 1 | 2
-----------------|----------|-----------
runtime(ms) | 4 | 4
-----------------|----------|-----------
vruntime | 4 | 2
-----------------|----------|-----------
按vruntime进行排序 | B A
----------------------------|-----------

d) B的vruntime最小,选择B运行,运行了4ms:

  ----------------|----------|-----------
进程 | A | B
----------------|----------|-----------
weight | 1 | 2
----------------|----------|-----------
runtime(ms) | 4 | 8
----------------|----------|-----------
vruntime | 4 | 4
----------------|----------|-----------
按vruntime进行排序 | A B
---------------------------|-----------

e) vruntime相同,但是A在前,选择A运行,运行了4ms:

---------------|---------|-----------
进程 | A | B
---------------|---------|-----------
weight | 1 | 2
---------------|---------|-----------
runtime(ms) | 8 | 8
---------------|---------|-----------
vruntime | 8 | 4
---------------|---------|-----------
按vruntime进行排序 | B A
-------------------------|-----------

f) B的vruntime最小,选择B运行,运行了4ms:

  ----------------|---------|-----------
进程 | A | B
----------------|---------|----------
weight | 1 | 2
----------------|---------|-----------
runtime(ms) | 8 | 12
----------------|---------|-----------
vruntime | 8 | 6
----------------|---------|-----------
按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 | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
runtime(ms) | 0 | 0 | 0 | 0
--------------------|-----------|----------|----------|----------
vruntime | 0 | 0 | 0 | 0
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | A B C D
--------------------|--------------------------------------------

b) 和前一个模型一样,vruntime的行走速度和权重值成反比,设定权重权为1的A进程的vruntime和实际runtime行走速度相同。A先执行,它执行了2ms,此时:

--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
runtime(ms) | 2 | 0 | 0 | 0
--------------------|-----------|----------|----------|----------
vruntime | 2 | 0 | 0 | 0
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | B C D A
--------------------|--------------------------------------------

c) B的vruntime值最小,选择B运行,假设B运行了3ms:

--------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
runtime(ms) | 2 | 3 | 0 | 0
--------------------|-----------|----------|----------|----------
vruntime | 2 | 1.5 | 0 | 0
--------------------|-----------|----------|----------|----------
按vruntime进行排序 | C D B A
--------------------|--------------------------------------------

d) C的vruntime值最小,选择C运行,假设C运行了3ms:

 --------------------|-----------|----------|----------|----------
进程 | A | B | C | D
--------------------|-----------|----------|----------|----------
weight | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
   runtime(ms) | 2 | 3 | 3 | 0
--------------------|-----------|----------|----------|----------
     vruntime | 2 | 1.5  | 1 | 0
--------------------|-----------|----------|----------|----------
按vruntime进行排序   | D C B A
--------------------|--------------------------------------------

e) D的vruntime值最小,选择D运行,假设D运行了8ms:

 --------------------|-----------|----------|----------|----------
进程 | A | B | C | D
 --------------------|-----------|----------|----------|----------
weight | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
runtime(ms) | 2 | 3 | 3 | 8
--------------------|-----------|----------|----------|----------
vruntime | 2 | 1.5 | 1 | 2
--------------------|-----------|----------|----------|----------
按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 | 1 | 2 | 3 | 4
--------------------|-----------|----------|----------|----------
ideal_runtime(ms) | 2 | 4 | 6 | 8
--------------------|-----------|----------|----------|----------
runtime(ms) | 2 | 3 | 9 | 8
--------------------|-----------|----------|----------|----------
vruntime | 2 | 1.5 | 3 | 2
--------------------|-----------|----------|----------|----------
按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)

cfs的更多相关文章

  1. O(1)调度器的时间计算公式与CFS调度器

    http://blog.csdn.net/dog250/article/details/48750809 O(1): 优先级计算: 进程优先级公式:prio=MAX_RT_PRIO+nice+20其中 ...

  2. linux 提高进程优先级nice+ 进程调度CFS

    http://www.cnblogs.com/wang_yb/archive/2012/09/04/2670564.htmlhttp://liwei.life/2016/04/07/linux%E7% ...

  3. CFS: 虚拟运行时间

    http://edsionte.com/techblog/archives/4331 nice和prio的关系如下: #define NICE_TO_PRIO(nice) (MAX_RT_PRIO+n ...

  4. 进程的优先级 与 CFS 进程调度

    在Linux下改变进程的优先级 作者:曾老师,华清远见嵌入式学院讲师. 作为多任务的操作系统,Linux内核为每个创建的进程分配时间片并根据其优先级进行调度.当进程被创建时,其对应的task_stru ...

  5. 朴素UNIX它-Linux CFS注视

    该系列产品,被称为纯UNIX,但它也包含各种类别UNIX该系统的细节,自从完成我多年的学习笔记本系列文章,分析了各种UNIX,类UNIX思想和情感的实现. 这篇文章是比较短.只是分析Linux CFS ...

  6. Linux 2.6 完全公平调度算法CFS(Completely Fair Scheduler) 分析

    转会http://www.ibm.com/developerworks/cn/linux/l-completely-fair-scheduler/index.html? ca=drs-cn-0125 ...

  7. linux内核cfs浅析

    linux调度器的一般原理请参阅<linux进程调度浅析>.之前的调度器cfs之前的linux调度器一般使用用户设定的静态优先级,加上对于进程交互性的判断来生成动态优先级,再根据动态优先级 ...

  8. CFS调度器(1)-基本原理

    首先需要思考的问题是:什么是调度器(scheduler)?调度器的作用是什么?调度器是一个操作系统的核心部分.可以比作是CPU时间的管理员.调度器主要负责选择某些就绪的进程来执行.不同的调度器根据不同 ...

  9. Linux CFS调度器之唤醒抢占--Linux进程的管理与调度(三十)

    我们也讲解了CFS的很多进程操作 table th:nth-of-type(1){ width: 20%; } table th:nth-of-type(2){ width: 20% ; } 信息 函 ...

随机推荐

  1. 由Lucnene 对于预治疗的文字,全角半角转换器(可执行)

    这是我第二次读这本书,在自己的学习之间XML,javascript,的深入研究<JAVA 核心技术>. 在当中深入的学习了java的非常多机制. 回头再来看搜索引擎这本书的时候.就认为比第 ...

  2. spring常规任务(轻便易)

    spring提供了定时任务功能.我们不需要第三者jar包支持.spring够了. 代码: package com.inth.product.web.task; import java.util.Dat ...

  3. 开销是有益的:AppCan 至HTML5移动创新和创业精神和健康

      2014年移动创业更趋向理性,消费级App市场接近饱和,BAT等巨头的竞争更加激烈,市场版图及格局基本定型.而企业级移动应用却迎来爆发增长,替代进入红海的消费级App市场,企业级定制APP开发成为 ...

  4. js中的json对象

    1.JSON(JavaScript Object  Notation)一种简单的数据格式,比xml更轻巧.JSON是JavaScript原生格式,这意味着在JavaScript中处理JSON数据不须要 ...

  5. SharePoint使用BCS开发你第一个应用程序(三)

    SharePoint使用BCS开发你第一个应用程序(三) 创建外部内容类型.         创建外部内容类型有三种不同方式: 1. 在记事本上手写XML代码(不推荐). 2. 使用SharePoin ...

  6. Android开发学习总结(五)——Android应用目录结构分析(转)

    一.手动创建android项目 手动创建一个Android项目,命名为HelloWorld,命令如下: android create project -n HelloWorld -t 1 -p E:/ ...

  7. 【甘道夫】HBase连接池 -- HTablePool是Deprecated之后

    说明: 近期两天在调研HBase的连接池,有了一些收获,特此记录下来. 本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然后查 ...

  8. 我的第一次windows规划

    #include <windows.h>   LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; //WinMain功能被分配一 ...

  9. 严格模式 (JavaScript)

    严格模式是一种将更好的错误检查引入代码中的方法. 在使用严格模式时,您无法使用隐式声明的变量.将值赋给只读属性或将属性添加到不可扩展的对象. 〉声明严格模式 可以通过在文件.程序或函数的开头添加 &q ...

  10. C#+Mapxtreme 实现一些GIS系统基本的功能

    此程序包括了mapxtreme地图相关基本功能的演示其中包括 鹰眼地图,图层控制,发达,缩小,平移地图,地图模糊查询,中点工具,距离测量工具,面积测量工具,图元信息查看工具.适合于企业级开发,可以为您 ...