1. 程式人生 > >linux排程器_第三代cfs(3)_分解程式碼vruntime的詳解

linux排程器_第三代cfs(3)_分解程式碼vruntime的詳解

前面講了排隊的關鍵值,是靠這兩個引數確定的se->vruntime - cfs_rq->min_vruntime,後一個引數是為了建立一個標準,像一本線二本線那樣的概念,所以今天我們來重點討論第一個引數的情況。

vruntime的詳解:

看到虛擬執行時間,肯定會想到有一個真實的執行時間,事實確實是有的。真實的執行的時間做一些計算,就變成虛擬執行時間了。想想看是不是那些優先順序高的程序,同樣的實際執行時間,虛擬時間要漲的慢一些,那樣它就會更靠近紅黑樹左邊的位置,那麼就有更大的機會來運行了呢?

事實上核心就是這麼來計算的。見如下程式碼:

我試了把一堆程式碼貼出來,但是真不是那麼容易讓人接受,一大堆程式碼太容易讓人望而生畏了,我選擇其中重點了來說吧,哎,其實《深入linux核心架構》這本書裡也是這麼做的,只放些重點的程式碼進去,我覺得那本書寫的很好,我寫這些有可能會是多餘,但是對於新手來說,也許更能讓人容易理解一些吧。我註釋的程式碼,放在最後有興趣的可以研究下。

精簡版程式碼:

delta_exec = (now - curr->exec_start);//這個是實際執行時間,就是現在的時間減去執行開始的時間,看來變數名字真的很重要,下次我們自己取變數名字也儘可能讓別人一看就知道意思呢,delta 這個應該念代爾塔,是微積分還是什麼數學裡面的概念吧,很小的一個時間段,now就代表現在的時間,curr是current的縮寫,就是當前的意思。exec是execute的縮寫,執行的意思,start就是開始的意思。有現在時間減去這個程序開始執行的時間,是不是就是這個程序執行的時間了呢。當然這時是物理時間。

現在要來統計這個程序執行的物理時間跟虛擬執行時間了,這是一個求和的過程,剛才delta也可以看出是一個很短的微積分概念。

curr->sum_exec_runtime += delta_exec; //這個是計算一個執行了多少實際的時間,runtime前面並沒有加v(virtual)。把每次執行的實際時間加起來就是當前程序的實際執行時間的總和了。然而排隊時候選哪個程序執行時,這個然並卵。然而並沒有什麼卵用。

關鍵的要來了,上程式碼:

delta_exec_weighted = delta_exec;
if (unlikely(curr->load.weight != NICE_0_LOAD)) {
delta_exec_weighted = calc_delta_fair(delta_exec_weighted,
&curr->load);
}
curr->vruntime += delta_exec_weighted;

基本這幾行,就表示計算虛擬執行時間的核心了。一行一行來分解吧。

delta_exec_weighted = delta_exec;//weighted是重量的意思,在這裡理解為權值。下面分割線裡對權值多扯幾句,跳過不影響下文,只需記得優先順序越高,權值越大。

---------------------------------------------------我是分割線(權值)------------------------------------------------

這部分不插太多程式碼,就是原來有140個優先順序,100-139個給一般程序使用,然而歷史原因搞了個nice值-20到19之間來表示值越大優先順序越低。為了拉開差距,二代只有140個優先順序,並不能很好的拉開差距,所以這裡用權值把粒度拉的很開。對應關係如下:

/*
* Nice levels are multiplicative, with a gentle 10% change for every
* nice level changed. I.e. when a CPU-bound task goes from nice 0 to
* nice 1, it will get ~10% less CPU time than another CPU-bound task
* that remained on nice 0.
*
* The "10% effect" is relative and cumulative: from _any_ nice level,
* if you go up 1 level, it's -10% CPU usage, if you go down 1 level
* it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
* If a task goes up by ~10% and another task goes down by ~10% then
* the relative distance between them is ~25%.)
*/
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,
};

以前我英文很差,後來為了學好它,我儘可能的多裝b,所以到後來,看到英文就想賣弄下,望體諒。

//此段大意,CPU的nice值下降一級,那麼將多獲得10%的CPU時間,而這個10%中有一個相對(relative)的概念
//來舉個例子吧,只有AB兩個程序在執行,nice值原本都是0,知權值load都為1024,
//則A程序1024/(1024+1024)=50%的CPU,想象下若要拉開10%的差距,此消彼長,則A=55%,B=45%;
//若此時A的nice值不變,即權值不變,B的nice值上升一級,權值該便多少呢?這就是我們這個權值表的由來了?
//1024/(1024+B的權值) ≈ 55%;計算出來的1024/0.55 - 1024 = 837左右,可見於820相差並不大。
//而核心直接用1/(1+1.25)≈ 0.4444; 取1.25這個基數,這個約等於放大就是我們上面的情況了。
//應該是從0這個nice值對應1024分別向兩邊擴充套件的

---------------------------------------------------我是分割線(權值)------------------------------------------------

if (unlikely(curr->load.weight != NICE_0_LOAD)) //如果權值不等於某個”基準“權值,

{

delta_exec_weighted = calc_delta_fair(delta_exec_weighted,
&curr->load);
//那麼重新計算。

}

也就是說,若是等於某個基準值,就按前面的實際時間計算,負責就重新計算。

怎麼重新計算呢?這個有點繞圈,公式是這樣的delta_exec_weighted = delta_exec * NICE_0_LOAD/curr->load.weight;

NICE_0_LOAD/curr->load.weightNICE_0_LOAD是一個標準值,若程序重要性比它大,那麼curr->load.weight大於NICE_0_LOAD,所以相除小於1,那麼乘以執行時間,相當於實際執行時間縮短了,反之,若程序重要性比它小,那麼商大於1,相當於執行時間拉長了,而短的時間會排在前面。

最後求和,curr->vruntime += delta_exec_weighted;得出虛擬執行時間。

整個過程基本就是這樣的了。若需要更深入的研究可以去看《深入理解linux核心架構這本書》,然後再結合核心原始碼來理解。