鑑於最近有關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上已經是最高優先順序了,它也就不會被遷移,也就我們看到的最後現象。
linux實時任務排程演算法分析
鑑於最近有關cpu占有率的一些問題涉及到linux核心的排程演算法,有必要進行了解。因此,寫了這篇文章。linux常見的任務有兩種,實時任務與非實時任務。實時任務的排程演算法是大家都非常熟悉的優先順序搶占或優先順序搶占加時間片兩種,其主要思想是效率優先。非實時任務的排程演算法是cfs 完全公平演算法...
Linux定時任務排程
linux定時任務 為當前使用者建立cron服務 1.鍵入 crontab e 編輯crontab服務檔案 例如 檔案內容如下 2 bin sh home admin jiaoben buy deletefile.sh 儲存檔案並並退出 2 bin sh home admin jiaoben buy...
Linux 定時任務排程
任務排程 系統在某個特定時間執行的特定命令和程式 分類 系統工作 有些重要的工作必須周而復始的執行 病毒掃瞄 使用者工作 個別使用者希望可以執行某些程式 定期對mysql資料庫備份 crond任務排程 crontab 選項 任務排程 選項 e 編輯crontab定時任務 l 查詢crontab任務 ...