CFS調度器的思想的新理解

來源:互聯網
上載者:User

本文通過詳細分析老的調度器來說明cfs的優勢。總是新理解新理解的,我怎麼這麼沒完沒了啊,其實每隔一段時間我都會在工作之餘再讀一讀linux核心原始碼的關鍵區段,每次讀都有新的理解,然後就第一時間將心得記錄下來,今天又讀了cfs調度器,越來越發現其美妙了。這次配合了sched-nice-design.txt文檔閱讀,很受啟發,萬惡的發送器終止了,新的時代開始了,O(1)調度器和CFS的作者都是Ingo Molnar,他真的是一個有破有立的傢伙,太猛了!

O(1)調度器是很不錯的,因為它的效率,正如它的名稱一樣,可是我們考慮的周全一點,作業系統對任務的調度不僅僅是用最快的速度選擇最值得啟動並執行進程,而也要兼顧最不值得啟動並執行進程,所謂“效率優先,兼顧公平”。O(1)對於優先順序調度的本意是很有效,因為它可以在最快的時間內選擇出優先順序最高的進程,可是低優先順序的進程可能因此饑餓而得不到執行的機會正如那篇sched-nice-design文檔中講的那樣,O(1)調度器以及以前的更土的調度器的根本麻煩在於時間片的計算,因為那些調度器沒有抽象到真正的的層次,更多的是利用底層的硬體中斷來進行的,這樣的話,根本無法用統一的方式來計算時間片,必須受累於底層的硬體,也就是說沒有一個萬能的時間片計算公式對每一台機器每一個系統都適用,比如一個系統的HZ定義為1000,另一個是100,那麼這兩個系統的調度行為就是不一樣的;第二,老的時間片分時調度中的時間片更多的是一種絕對的參考值,一會會說出原因,現在要說的就是時間片計算公式計算出來的時間片和進程的優先順序不是一個和諧的關係,比如線性關係,比如在nice值為+19到+15這之間,nice值每減少一個點其時間片平均增加delta1,而nice在0到4,時間片平均增加delta2,而這兩者是不同的,這是不應該的,因為比如我想讓時間片大大增加些,我必須知道我當前的nice值。

以上說的是總體上的,下面我來說說我的理解,到O(1)調度器加上更土的調度器,linux的調度器的時間片的計算大致分了三個階段,更土的調度器裡面也即是O(n),計算出來的時間片幾乎分辨不出誰的優先順序更高,優先順序更高的進程的時間片也不會更具有優勢,因為那時的調度器想把時間片限制在50毫秒的左右不超出多少的範圍內,計算規則很簡單:

#elif HZ

#define TICK_SCALE(x) ((x)

#define NICE_TO_TICKS(nice) (TICK_SCALE(20-(nice))+1)

這個簡單的公式很線性,很和諧,但是計算出來的時間片幾乎差不離,高優先順序的進程沒有什麼優勢,後來發展到了O(1)調度器以後,當然進行了改進:

#define BASE_TIMESLICE(p) (MIN_TIMESLICE + /

((MAX_TIMESLICE - MIN_TIMESLICE) * /

(MAX_PRIO-1 - (p)->static_prio) / (MAX_USER_PRIO-1)))

static inline unsigned int task_timeslice(task_t *p)

{

return BASE_TIMESLICE(p);

}

這個公式將最高優先順序的時間片延長了,而把最低優先順序的時間片縮短了,不管怎樣增加了優先順序時間片的動態範圍,這個在效果上的表現就是,優先順序高的進程表現出來的時間片更加長了,為了將優先順序最高的進程的時間片和優先順序最低的進程的時間片有效分離,增加時間片基數是一種方式,比如,最低優先順序的時間片是10,然後每增加1個優先順序則增加時間片n倍,取n為2,那麼從低到高的時間片依次為10,20,40...,或者按照等差數列增加,比如差為10,那麼就是10,20,30,40...但是會遇到一個問題,nice值或者優先順序值的增加會和時間片的增加同步嗎?如果我們強調同步,那麼最高優先順序的進程的時間片就會過於長,要麼就是基數過小,這樣的話就會引起頻繁調度而重新整理cache。後來在2.6.9核心往後的實現裡,又有了新的策略:

static unsigned int task_timeslice(task_t *p)

{

if (p->static_prio

return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);

else

return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);

}

新的實現採用了以nice 0為分界點,正值採用緩線性,負值採用陡線性,這可以保證在nice為正值的時候,nice值的減少率和時間片增加率同步,其實就是兩個點的同步,就是+19的nice值和0的nice值,並且為了防止HZ為1000的系統中頻繁調度,採用了約定最小時間片為5ms的方式硬性規定,可是為何選擇+19的nice值考慮呢?因為它是一個極端值,兩點確定一條直線,一個是0,一個是+19,可是為何採用兩類斜率的線段呢?因為如果統一採用緩斜率的線段,那麼會造成和2.4核心以及2.6.9以前一樣的問題,動態範圍小,高優先順序不突出,但是如果統一採用陡斜率,那麼就會造成高優先順序的進程時間片過於長,這會引起系統響應性差,注意這在unix不是問題,可是對於linux就是問題了,因此為了既要實現突出高優先順序進程,又要削弱低優先順序進程又不至於削的更弱而引起頻繁調度而重新整理cache,那麼就很“藝術”的採用了雙斜率線性結構,這裡有一個哲學,就是如果你既要抬高優勢又要削減劣者,那麼你要看看它們是否對稱,如果不是,比如劣者有個顯然的極端,那麼線上性結構中,這個顯然的極端值一定是一個定線段的端點,正如這裡的5ms,另外一個端點就是緩陡分界點,還有一個就是最高的極值,這後面兩個極值就需要經驗值和別的約束條件了,為何使用線性結構呢?不為別的,正是因為它簡單!我一直在想世界不是對稱的,其實我們的世界就不是一個對稱的,比如溫度,我們知道-273°C,而高溫已經到達很高的了,有沒有高溫極限呢?現在還沒有找到,如果說我們人類是和諧,是美的化身,那麼我們為何不生活在(-273+1000000000000000000000)/2°C呢?...要麼我們否認-273是最低的溫度,要麼我們人類就不要再得瑟。閑話少說,又跑偏了...正是由於舊的調度器的時間片的雙斜率導致了nice 0兩邊的不對稱性,導致了你在當前nice為正值和負值兩種情況下進行的nice系統調用的行為不同,一個+1時間片減少的快一個減少的慢。在那篇文檔中,作者特意說了,最重要的就是linux想用統一的方式進行時間片計算去沒有想到不可能,因為時間片的計算和HZ的定義密切相關,這就引入了一個變數,想完全線性實現是不可能的。

不僅如此,就是因為老的調度器(呵呵,現在O(1)都成了老的調度器了)只選擇最高優先順序的進程而不管低優先順序的進程,因此它是“少了一環”的調度,不能稱為是完全的調度,正是它的不完全,才引入了很多複雜的外圍演算法,比如基於平均睡眠時間的互動檢測演算法,比如優先順序的靜態和動態分類演算法,前面的一篇文章說過,O(1)調度器的延時減少了,減少的是尋找最高優先順序進程的時間,別的時間並沒有有效減少也不可能減少,因為一個進程需要佔用確定的時間片,那麼所有的進程完全運行完也將是確定的時間片,而系統的進程數量將使整個調度周期延長,這可能造成更大面積的饑餓現象存在,為了避免這種現象,不管是linux還是windows,都有很多動態演算法,比如饑餓檢測以及優先順序臨時提升等等,這些演算法本身就造成了不多但是有的延時。新的CFS改變了這一切。

cfs很有創意,它囊括了關於調度的一切,包括優先順序,包括尋找最值得啟動並執行進程等等一切,在cfs中,以前O(1)的創意如今簡單的成了一棵紅/黑樹狀結構,紅/黑樹狀結構本身就有優先順序的性質,因為它是一棵排序樹,而且插入和刪除的效率很高,由於從運行隊列刪除進程很多都是發生了該進程運行時期,出隊運行更是增加了效率,到此為此O(1)的所有工作,一棵紅/黑樹狀結構就全部搞定了,就是簡單的找出最高“優先順序”的進程,在cfs中,沒有了時間片,優先順序對應成了weight,叫做權值,系統的已耗用時間完全在所有進程之間按照權值公平分配,公平性體現在每個進程都有一個虛擬時鐘,各個虛擬時鐘相互追趕,調度器總是選擇虛擬時鐘最慢的進程運行,前面文章說過,權值小的進程虛擬時鐘走的快,比如它在1個tick就走了1個字,而權值大的進程虛擬時鐘走的慢,比如10個tick走了一個字,cfs的創舉是,它可保證一個虛擬時鐘的速度比是1:10的進程對,那麼它的權值比是10:1,怎麼保證呢?在linux的cfs調度器中,有一個靜態數組,叫做prio_to_weight,它有40個元素,其中對應0到39這40個優先順序,每增加一個優先順序值,那麼它的權值減少十分之一,注意,如果開始一個進程的權值是10,優先順序是10,那麼它的優先順序變成9以後其權值會是9嗎?不!因為整個系統的已耗用時間不變,你減少了1/10的時間,那麼其它的所有進程將會增加這些時間,因為一個進程減少1/10,別的進程增加1/10,那麼這個進程將減少25%的時間,這就是這個數組的妙處,每一個元素都是後一個元素乘以1.25%。這樣的話,整個系統的權值將是一個按比例縮減的,相應的,其虛擬時鐘的速度將按照這個比例增加,虛擬時鐘向前推進你完全可以理解成以前的時間片,只不過這個時間片不再是固定的了,而是動態,比如一個進程運行了10個tick其虛擬時鐘走了一個字,這時系統中又來了一個進程,那麼這個進程就不再運行10個tick了,可能會變成9個,如果這個系統就剩下它一個進程了,那麼它將一直運行,不再進行無用的--p->task_timeslice的操作。記住,一切都是按照比例進行的,這個比例就是那個數組的縮減比例。

我們看看cfs怎麼解決之前調度器遇到的那些問題,第一,不再需要雙斜率的線段,因為可以保證高權值的進程的“時間片”就是低權值的N倍,這是這個數組決定的,調度器會計算這個進程的權值佔用系統當前所有進程的權值和的幾分之幾,然後就分配整個調度周期幾分之幾的“時間片”,這個機制之所以可以如此完美又有效進行就是因為每個進程虛擬時鐘的向前推進方式--互相追趕,調度器選擇最慢的運行(推進的速度不同)。cfs中的所謂動態已耗用時間可以保證cpu永遠不會浪費去做沒有意義的事情,如果系統只剩下一個進程,那麼調度器會把整個cpu全部給了這個進程,本質上,正如作者的話:"CFS百分之八十的工作可以用一句話概括:CFS在真實的硬體上類比了完全理想的多任務處理器"。在“完全理想的多任務處理器“下,每個進程都能同時獲得CPU的執行時間。當系統中有兩個進程時,CPU的計算時間被分成兩份,每個進程獲得50%。然而在實際的硬體上,當一個進程佔用CPU時,其它進程就必須等待。這就產生了不公平。cfs的調度器只知道把cpu分給當前的進程們,這種分配是按照進程的權值平均分配的,虛擬時鐘只是實現這種公平的手段而已。cfs中的nice調用可以“放心”的進行,因為nice影響的進程啟動並執行“時間片”只和相對值有關和絕對值無關。cfs中將優先順序巧妙的轉換成了權值這個概念,而權值又是那麼巧妙的組織,好,非常好!

cfs如此統一的解決了那麼多問題,統一就是美,簡單就是美!cfs是一個完全的調度方案,而不僅僅是挑選第一個值得啟動並執行進程的方案,這個意義上O(1)僅僅是一個挑選第一個進程的方案罷了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.