linux即時任務調度演算法分析

來源:互聯網
上載者:User

原文地址:http://blog.csdn.net/imtgj/article/details/7107489?reload

鑒於最近有關cpu佔有率的一些問題涉及到linux核心的調度演算法,有必要進行瞭解。因此,寫了這篇文章。linux常見的任務有兩種,即時任務與非即時任務。即時任務的調度演算法是大家都非常熟悉的優先順序搶佔或優先順序搶佔加時間片兩種,其主要思想是效率優先。非即時任務的調度演算法是CFS(完全公平演算法),從名字就可以知道,其思想是公平優先,兼顧效率。由於我們使用上,即時任務比較多,本篇就先介紹即時任務的調度機制。


一、UP(Uniprocess)下的優先順序調度
熟悉vxworks的同學都非常清楚,vxworks使用的就是優先順序搶佔,從0-255,優先順序高的搶佔優先順序低的。如果再加上時間片調度,則當任務運行完它的時間片後,會重新進行調度,這時候,如果有相同優先的任務,就可以得到運行。這點要注意,即使當前進程的時間片用完了,優先順序比它低的任務還是不能得到CPU的,重新調度還是會調度到之前啟動並執行任務的。所謂時間片,就是相同優先順序的任務輪流佔有CPU,不同優先順序只有搶佔。如果沒有啟用時間片調度,相同優先順序的任務只有等待前面的任務運行完後才能得到CPU。
簡單說:座位只有一個,誰坐?比拳頭,大的先上,拳頭一樣大的,輪流上,小的靠邊站。
非常好理解,實際上UP方式下linux的調度機制與vxworks並沒有多大差異。差別的是內部代碼實現及調度點。
在vxworks 5.5.1下,只維護了一個就緒隊列,按優先順序排序,優先順序高的排在前面,優先順序一樣的,按先後順序排列。每次調度時就從隊列頭取下一個任務運行。
而linux則按優先順序維護了多個就緒隊列,每個優先順序都有一個就緒隊列,任務入隊列時會置隊列位元影像表相應的bit位,表示該優先順序有任務已經就緒,等待調度。調度時掃描隊列位元影像表,從高優先順序隊列中取下一個任務運行。
另外一個差異就是vxworks作為一個即時作業系統,只有任務一就緒就會檢查是否需要調度,而linux則需要等待調度點的到來才真正檢查是否需要調度。
UP下的調度非常好理解,那麼SMP下又如何呢?


二、SMP下的優先順序調度
有錢了,買了好多凳子,甚至還是二人沙發,四人沙發,如何讓合適的人,坐到合適的凳子上,反而變成了一件不容易的事情。
UP下大家的目標都很簡單,就是搶同一個CPU,而SMP下,則是從多個CPU中搶一個CPU。一個常見的誤區是:一說到SMP,就會想到負載平衡。實際上,即時任務的調度是不會考慮負載平衡的,其調度演算法是搶佔式的,既然是搶,當然是搶到一個算一個。即時任務的負載平衡應該是由設計者考慮的:核與任務的關係,如何更好的讓即時任務都得到調度。
既然是從多個CPU中搶一個,那麼搶那一個呢?當然是靠近你邊上的座位(當前CPU),如果能搶到的話,否則就挑最弱小的下手。所以,系統維護了一個當前所有CPU的優先順序,實際就是每個CPU上當前運行任務的優先順序全域表,每個cpu上進行任務調度時,都會更新此表。那麼當一個任務就緒準備搶佔運行時,就會從這裡面挑優先順序最低的下手。
看起來是如此的簡單,但實際上,這隻是個大原則,由於SMP下涉及到任務綁定,任務遷移,CPU狀態(active變成inactive)、相關隊列的操作,還是有很多細節需要考慮的。
1、CPU的優先順序狀態表
這個全域狀態表的結構與就緒隊列類似,每個優先順序列表包含了該優先順序的CPU位元影像,一個優先順序列表的位元影像(該優先順序是否有CPU的指示),一個CPU優先順序數組。尋找時通過位元影像操作以加快速度。


下面分3種情境來分析下SMP下如何調度即時任務的。


1、任務被喚醒
當一個任務就緒時(比如睡眠時間到了,或者等待的訊號量已經空閑了等情況),任務會被喚醒,這時候需要挑選一個合適的CPU。
什麼是合適的CPU,其判斷標準如下:
1)、當前任務為非即時任務,則不費心找了,搶佔當前CPU正合適。
2)、被喚醒任務優先順序大於當前任務,且當前任務允許在多個CPU允許,則不費心找了,搶佔當前CPU正合適。
3)、被喚醒任務優先順序大於當前任務,但當前任務只綁定了當前CPU,則需要進一步尋找一個合適的CPU.
4)、被喚醒任務允許在多個CPU上運行,且其優先順序比當前任務低,則需要進一步尋找一個合適的CPU.


後面兩種情況需要尋找CPU的優先順序狀態表,找出與任務相匹配的優先順序最低的CPU列表(如任務綁定了某些CPU,雖然目前還是優先順序更低的CPU,還是不能選),然後再從列表中選擇一個,其標準是:如被喚醒任務上一次啟動並執行CPU在列表中,則選它;如果當前Cpu在列表中,則選它;否則根據調度域,選擇一個。調度域簡單說,就是根據遠近親疏關係,對CPU進行分組,後面講負載平衡的時候再詳細瞭解。
總的來說,第一,二種情況是儘可能快的響應(即時任務嘛),挑當前CPU下手,可以認為是fastpath;實在沒辦法了,尋找優先順序最低的CPU集合,並考慮cache和記憶體的利用率,從中挑選一個,可以認為是slowpath。
選擇好目的CPU之後,則入該CPU的就緒隊列,等待調度運行,同時把任務掛入待push隊列(任務不是只綁定到目的CPU情況下)。


檢查是否可以搶佔當前任務,如果可以,置調度標誌。特別情況,如果當前運行任務與被喚醒任務優先順序相同,則需要判斷運行任務是否可以在其他CPU上運行(比如被喚醒任務綁定了當前CPU,而運行任務沒有綁定當前CPU,則可以讓當前任務在其他CPU上運行,這樣,皆大歡喜),可以的話把喚醒任務入隊列頭,置調度標誌。


如果沒有辦法搶佔,這時候會嘗試把該任務推到其他的CPU上運行,此為所謂的"PUSH"機制。這時候挑選CPU與任務被喚醒時的處理是類似的,挑優先順序最低的CPU列表,並考慮調度域,cache利用率等因素選擇合適的CPU.
相應地,“PULL"機制,就是準備調度時,或者當前任務狀態發生變化(優先順序調整變低了,從即時任務變成非即時任務等),從其他CPU的可PUSH隊列上拉任務過來運行。


到這裡,任務已經放入合適的就緒隊列,等待調度運行。

2、當前運行任務放棄CPU
當任務消亡、自願(如sleep)或者被迫(如擷取不到訊號量)放棄CPU時,會觸發調度,這時候需要挑選一個合適的任務來運行。
如果當前任務為即時任務,且就緒隊列中沒有比當前任務優先順序高的任務,則系統可能還存在比當前任務優先順序低的即時任務,這時候會觸發PULL操作。這個操作主要解決如下情境:假設系統有兩個CPU,4個任務,優先順序分別為T1>T2>T3>T4,T1為CPU1的當前任務,T3在CPU1的就緒隊列中,T2為CPU2的當前任務,T4在CPU2的就緒隊列中。如果T2很快執行完畢,觸發調度,則不能選T4,必須從CPU1中把T3給拉過來(如果T3是可push的,即T3沒有綁定到CPU1去)。從這裡也可以看出,PUSH和PULL機制實際就是為瞭解決任務第一次入隊有可能並不是最佳的情況。如果系統只有一個就緒隊列,那麼每次都從隊列頭取任務,肯定就不會錯了,雖然簡單,但卻造成了各個CPU都需要競爭同一個隊列,各CPU的調度必須串列處理,效能上是不可接受的。因此,修改為各個CPU都有自己的就緒隊列,但又可能導致了排錯隊,就引入了PUSH和PULL處理。

然後根據優先順序位元影像的指示,從最高優先順序隊列中取出下一個待啟動並執行任務。


3、任務被建立
對即時任務,會把當前的CPU作為任務初始啟動並執行CPU;
任務狀態置為就緒態,併入當前CPU的就緒隊列;
檢查是否可搶佔當前任務,若是的話置調度位。


所謂調度,就是對資源的管理與分配。不同的是UP只需要關心管理工作資源,而SMP下還需要管理CPU資源,並且在這兩者獲得最佳配合,其複雜程度也就成倍的擴大。


到這裡,即時任務的調度過程已經分析了清楚了。
下面我們來看看最近發生的有關調度的問題:


三、一個調度的問題
測試通過tesgine向8個收包任務發同樣流量的報文,發現各任務的佔用的CPU並不相近,相差接近20%,而且CPU佔有率高的任務反而丟包;另外,發現有兩個核的CPU佔有率一直相對其他的核高,一個各核的CPU佔有率不相近。我們的系統為6核12個VCPU。

通過上面的分析,應該可以很容易的解釋這個現象:
一個房間裡有6張二人沙發,每張沙發前有一個茶几,茶几上放著糖果。先來了6個人,則每個人剛好坐一張沙發,後來的兩個人,只能和其他人擠一擠,這樣就有兩張沙發坐滿了人,另外4張沙發只坐一個人(核間不均衡)。一個人獨坐一張沙發的人就比較爽了,想吃茶几上的那個糖果,就能拿那個;而合坐同一張沙發的人,出手時還要看看不要碰到旁邊的人,假如大家都對果凍感興趣,還必須等另外一個人拿完你才能拿。所以,消耗同樣的糖果下,合坐的人肯定要比獨坐一張沙發的人時間長了(CPU佔有率高)。勤快的菲傭不停的給每個人上糖果,合坐沙發的人由於吃的慢,慢慢的糖果就堆滿了茶几,最後再也放不下了(丟包)。
合坐沙發的人為什麼不移動到其他沙發去呢?移動到其他沙發又有啥好處呢,在這張沙發屁股剛剛坐熱(cache hot), 到另外一張沙發還是要跟別人合坐,沒啥好處。
另外一個小問題:核心是以座位為管理對象,而不是沙發為對象進行分配的,為什麼先來的6個人,每個人坐一張沙發,而不是先安排2個人同坐一張沙發?實際上,核心在對座位進行編號時,使了個小花招,6張2人沙發其編號如下:沙發1有兩個座位,座位號為0,6,沙發2的座位號為1,7,...所以,只需要按座位號對號入座就可以了。
任務一開始啟動就是這樣子嗎?實際也不是的,這是穩定點下的現象(在我們這個系統中,達到這個狀態非常快)。前面說了,任務建立時賦予了初始的運行CPU就是當時建立代碼所啟動並執行CPU。收包任務的優先順序為30,當時測試環境有比收包任務高的只有定時器任務(20)。假當時建立啟動並執行CPU為0,收包任務分別為R1-R8,定時器任務為T1-T8,定時器任務肯定會搶佔收包任務,但定時器任務已耗用時間很快,大部分都在睡眠,收包任務處理非常繁忙,當時的觀察是70-90%的CPU佔有率。假設R1先運行,緊接著其他收包任務也就緒,由於R1正在運行,其他收包任務只能遷移到其他CPU上運行,於是R2到了VCPU6(調度域的原因),R3->VCPU1,R4->VCPU2,R5->CPU3,R6->VCPU4,R7->VCPU5,R8->VCPU7.(上面假設收包任務按順序R1->R8就緒調度運行,
每個收包任務就緒時編號在它前面的收包任務在運行,系統沒有其他任務),實際運行情況稍微複雜,但不會影響最終的結果,通這時候定時器任務被喚醒搶佔R1,於是R1被遷移到VCPU8。由於定時器任務大部分都在睡眠,因此,T1-T8任務很大機率都在VCPU0上運行,即使定時器任務運行時,另外一個定時器任務也就緒了,它只會被遷移到優先順序最低的VCPU上(VCPU9,VCPU10,VCPU11),而不會搶佔收包任務的VCPU。這樣過幾次的調度後很快就達到了穩定點,由於收包任務在它啟動並執行CPU上已經是最高優先順序了,它也就不會被遷移,也就我們看到的最後現象。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.