CFS理论模型

参考资料:《调度器笔记》Kevin.Liulinux

                 《Linux kernel development》服务器

                 《深刻Linux内核架构》架构

                   version: 2.6.32.9ide

 

    下文中对于红黑树或链表组织的就绪队列,统称为用队列组织的就绪队列。                                              
    linux中用struct rq将处于ready状态的进程组织在一块儿。
    struct rq结构体包含cfs和rt成员,分别表示两个就绪队列:cfs就绪队列用于组织就绪的普通进程(这个队列上的进程用彻底公平调度器进行调度);rt就绪队列用于组织就绪的实时进程(该队列上的进程用实时调度器调度)。
    在多核cpu系统中,每一个cpu对应一个struct rq结构体实例。

    核心调度器分为:
    一、周期性调度器  schedule_tick();
         周期性调度器不负责进程的切换,只是定时更新调度相关的统计信息,以备主调度器使用。
    二、主调度器      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公平模型。post

 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
idea

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

 

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

  ----------------|----------|-----------
      进程         |   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:code

  ----------------|----------|-----------
      进程         |   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分别为:一、二、三、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)          

转自:阿加

相关文章
相关标签/搜索