Linux CFS中的程式排程

許佳佳233發表於2017-10-17

使用優先順序對映時間片的劣勢

在Linux中用nice值代表優先順序,它的範圍是-20~19。nice值越低,優先順序越高。

在Linux之前,Unix中就是使用nice值對映時間片的方式來進行排程。比如,nice值為0對應100ms的時間片,nice值為20對應5ms的時間片,nice值為19對應10ms的時間片。

在一般情況下,如果是nice值為0和nice值為20的兩個程式同時執行,那麼他們對應的時間片分別為100ms和5ms。這種情況中,nice值為0的程式擁有20/21的處理器時間,讓優先順序更高的擁有更多的處理器的處理時間是非常合理的。

但是在另一些情況下可能表現就並非這麼理想了。
如果是兩個同等的低優先順序的程式,比如他們都是nice值為20的程式,那麼他們的時間片都為5ms,於是他們每執行5ms就會進行一次程式切換。如此就放大的程式切換所帶來的消耗,但是我們最初希望的是兩個程式都佔有CPU 50%的時間。在這樣的情況下,顯然無法實現。

CFS理想狀態

CFS全稱完全公平排程演算法。
在理想情況下,每個程式將能獲得1/n的處理器時間——n是指可執行程式的數量。

但是有很多因素使理想狀態無法實現:
1、一個處理器無法同時執行多個程式,程式切換本身有消耗,還會影響到快取的效率。
2、當時間片小到一定的程度,程式搶佔的代價會被放大。

CFS實現

在CFS中不再是nice值與時間片的絕對對映,而是讓nice值對應不同的權重,然後根據權重和實際執行時間來分配時間片。
比如有A、B兩個程式,他們對應的weight分別為1和3,週期時間為20ms,那麼A需要執行的時間就是1/4*20=5ms,B需要執行的時間就是3/4*20=15ms。

nice與weight的對應對如下:

static const int prio_to_weight[40] = {
 /* -20 */     88761,     71755,     56483,     46273,     36291,
 /* -15 */     29154,     23254,     18705,     14949,     11916,
 /* -10 */      9548,      7620,      6100,      4904,      3906,
 /*  -5 */      3121,      2501,      1991,      1586,      1277,
 /*   0 */      1024,       820,       655,       526,       423,
 /*   5 */       335,       272,       215,       172,       137,
 /*  10 */       110,        87,        70,        56,        45,
 /*  15 */        36,        29,        23,        18,        15,
};

在這種情況下,執行的時間都是按照權值來計算,而不是之前的絕對時間,這樣就不會出現“時間片過小,放大程式切換所帶來的消耗”的問題了。

CFS下的程式選擇

主要思想:
CFS根據vruntime的值,將所有的程式存入紅黑樹,每次在紅黑樹中選擇vruntime最小的程式執行。同時CFS為了實現公平,必須懲罰正在執行的程式,以使那些正在等待的程式下次會被排程。(否則就會一直呼叫vruntime最小的程式到執行結束為止)

vruntime是虛擬執行時間,計算公式如下:(1024代表nice=0時的權重,上面表中有)
vruntime = 實際執行時間 * 1024 / 程式權重 (公式1)

由公式所得,如果一個程式執行的事件越長,那麼它的vruntime的值也會越大,被呼叫的概率也會越小。
因此,優先順序越高,已經執行時間越短的程式最會被呼叫。

另外這個公式還有一個演化:
vruntime = (排程週期 * 程式權重 / 所有程式總權重) * 1024 / 程式權重 = 排程週期 * 1024 / 所有程式總權重 (公式2)

從這個公式我們可以看到,雖然程式的權重不同,但是它們的 vruntime增長速度應該是一樣的 ,與權重無關。因此,通過vruntime 來選擇執行的程式,既能公平選擇程式,又能保證高優先順序程式獲得較多的執行時間。這就是CFS的主要思想了。

相關文章