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)          

轉自:阿加

相關文章
相關標籤/搜索