程序排程依據
排程程式執行時,要在所有可執行狀態的程序中選擇最值得執行的程序投入執行。選擇程序的依據是什麼呢?在每個程序的task_struct結構中有以下四項:policy、priority、counter、rt_priority。這四項是選擇程序的依據。其中,policy是程序的排程策略,用來區分實時程序和普通程序,實時程序優先於普通程序執行;priority是程序(包括實時和普通)的靜態優先順序;counter是程序剩餘的時間片,它的起始值就是priority的值;由於counter在後面計算乙個處於可執行狀態的程序值得執行的程度goodness時起重要作用,因此,counter也可以看作是程序的動態優先順序。rt_priority是實時程序特有的,用於實時程序間的選擇。
linux用函式goodness()來衡量乙個處於可執行狀態的程序值得執行的程度。該函式綜合了以上提到的四項,還結合了一些其他的因素,給每個處於可執行狀態的程序賦予乙個權值(weight),排程程式以這個權值作為選擇程序的唯一依據。關於goodness()的情況在後面將會詳細分析。
程序排程策略
排程程式執行時,要在所有處於可執行狀態的程序之中選擇最值得執行的程序投入執行。選擇程序的依據是什麼呢?
在每個程序的task_struct 結構中有這麼四項:
policy, priority , counter, rt_priority
這四項就是排程程式選擇程序的依據.其中,policy是程序的排程策略,用來區分兩種程序—實時和普通;priority是程序(實時和普通)的優先順序;counter 是程序剩餘的時間片,它的大小完全由priority決定;rt_priority是實時優先順序,這是實時程序所特有的,用於實時程序間的選擇。
首先,linux 根據policy從整體上區分實時程序和普通程序,因為實時程序和普通進程度排程是不同的,它們兩者之間,實時程序應該先於普通程序而執行,然後,對於同一型別的不同程序,採用不同的標準來選擇程序:
對於普通程序,linux採用動態優先排程,選擇程序的依據就是程序counter的大小。程序建立時,優先順序priority被賦乙個初值,一般為0~70之間的數字,這個數字同時也是計數器counter的初值,就是說程序建立時兩者是相等的。字面上看,priority是「優先順序」、counter是「計數器」的意思,然而實際上,它們表達的是同乙個意思—程序的「時間片」。priority代表分配給該程序的時間片,counter表示該程序剩餘的時間片。在程序執行過程中,counter不斷減少,而priority保持不變,以便在counter變為0的時候(該程序用完了所分配的時間片)對counter重新賦值。當乙個普通程序的時間片用完以後,並不馬上用priority對counter進行賦值,只有所有處於可執行狀態的普通程序的時間片(p->counter==0)都用完了以後,才用priority對counter重新賦值,這個普通程序才有了再次被排程的機會。這說明,普通程序執行過程中,counter的減小給了其它程序得以執行的機會,直至counter減為0時才完全放棄對cpu的使用,這就相對於優先順序在動態變化,所以稱之為動態優先排程。至於時間片這個概念,和其他不同作業系統一樣的,linux的時間單位也是「時鐘滴答」,只是不同作業系統對乙個時鐘滴答的定義不同而已(linux為10ms)。程序的時間片就是指多少個時鐘滴答,比如,若priority為20,則分配給該程序的時間片就為20個時鐘滴答,也就是20*10ms=200ms。linux中某個程序的排程策略(policy)、優先順序(priority)等可以作為引數由使用者自己決定,具有相當的靈活性。核心建立新程序時分配給程序的時間片預設為200ms(更準確的,應為210ms),使用者可以通過系統呼叫改變它。
對於實時程序,linux採用了兩種排程策略,即fifo(先來先服務排程)和rr(時間片輪轉排程)。因為實時程序具有一定程度的緊迫性,所以衡量乙個實時程序是否應該執行,linux採用了乙個比較固定的標準。實時程序的counter只是用來表示該程序的剩餘時間片,並不作為衡量它是否值得執行的標準。實時程序的counter只是用來表示該程序的剩餘時間片,並不作為衡量它是否值得執行的標準,這和普通程序是有區別的。上面已經看到,每個程序有兩個優先順序,實時優先順序就是用來衡量實時程序是否值得執行的。
這一切看來比較麻煩,但實際上linux中的實現相當簡單。linux用函式goodness()來衡量乙個處於可執行狀態的程序值得執行的程度。該函式綜合了上面提到的各個方面,給每個處於可執行狀態的程序賦予乙個權值(weight),排程程式以這個權值作為選擇程序的唯一依據。
linux根據policy的值將程序總體上分為實時程序和普通程序,提供了三種排程演算法:一種傳統的unix排程程式和兩個由posix.1b(原名為posix.4)作業系統標準所規定的「實時」排程程式。但這種實時只是軟實時,不滿足諸如中斷等待時間等硬實時要求,只是保證了當實時程序需要時一定只把cpu分配給實時程序。
非實時程序有兩種優先順序,一種是靜態優先順序,另一種是動態優先順序。實時程序又增加了第三種優先順序,實時優先順序。優先順序是一些簡單的整數,為了決定應該允許哪乙個程序使用cpu的資源,用優先順序代表相對權值—優先順序越高,它得到cpu時間的機會也就越大。
? 靜態優先順序(priority)—不隨時間而改變,只能由使用者進行修改。它指明了在被迫和其他程序競爭cpu之前,該程序所應該被允許的時間片的最大值(但很可能的,在該時間片耗盡之前,程序就被迫交出了cpu)。
? 動態優先順序(counter)—只要程序擁有cpu,它就隨著時間不斷減小;當它小於0時,標記程序重新排程。它指明了在這個時間片中所剩餘的時間量。
? 實時優先順序(rt_priority)—指明這個程序自動把cpu交給哪乙個其他程序;較高權值的程序總是優先於較低權值的程序。如果乙個程序不是實時程序,其優先順序就是0,所以實時程序總是優先於非實時程序的(但實際上,實時程序也會主動放棄cpu)。
當policy分別為以下值時:
1) sched_other:這是普通的使用者程序,程序的預設型別,採用動態優先排程策略,選擇程序的依據主要是根據程序goodness值的大小。這種程序在執行時,可以被高goodness值的程序搶先。
2) sched_fifo:這是一種實時程序,遵守posix1.b標準的fifo(先入先出)排程規則。它會一直執行,直到有乙個程序因i/o阻塞,或者主動釋放cpu,或者是cpu被另乙個具有更高rt_priority的實時程序搶先。在linux實現中,sched_fifo程序仍然擁有時間片—只有當時間片用完時它們才被迫釋放cpu。因此,如同posix1.b一樣,這樣的程序就象沒有時間片(不是採用分時)一樣執行。linux中程序仍然保持對其時間片的記錄(不修改counter)主要是為了實現的方便,同時避免在排程**的關鍵路徑上出現條件判斷語句 if (!(current->policy&sched_fifo))—要知道,其他大量非fifo程序都需要記錄時間片,這種多餘的檢測只會浪費cpu資源。(一種優化措施,不該將執行時間佔10%的**的執行時間減少到50%;而是將執行時間佔90%的**的執行時間減少到95%。0.9+0.1*0.5=0.95>0.1+0.9*0.9=0.91)
3) sched_rr:這也是一種實時程序,遵守posix1.b標準的rr(迴圈round-robin)排程規則。除了時間片有些不同外,這種策略與sched_fifo類似。當sched_rr程序的時間片用完後,就被放到sched_fifo和sched_rr佇列的末尾。
只要系統中有乙個實時程序在執行,則任何sched_other程序都不能在任何cpu執行。每個實時程序有乙個rt_priority,因此,可以按照rt_priority在所有sched_rr程序之間分配cpu。其作用與sched_other程序的priority作用一樣。只有root使用者能夠用系統呼叫sched_setscheduler,來改變當前程序的型別(sys_nice,sys_setpriority)。
此外,核心還定義了sched_yield,這並不是一種排程策略,而是擷取排程策略的乙個附加位。如同前面說明的一樣,如果有其他程序需要cpu,它就提示排程程式釋放cpu。特別要注意的就是這甚至會引起實時程序把cpu釋放給非實時程序。
主要的程序排程的函式分析
真正執行排程的函式是schedule(void),它選擇乙個最合適的程序執行,並且真正進行上下文切換,使得選中的程序得以執行。而reschedule_idle(struct task_struct *p)的作用是為程序選擇乙個合適的cpu來執行,如果它選中了某個cpu,則將該cpu上當前執行程序的need_resched標誌置為1,然後向它發出乙個重新排程的處理機間中斷,使得選中的cpu能夠在中斷處理返回時執行schedule函式,真正排程程序p在cpu上執行。在schedule()和reschedule_idle()中呼叫了goodness()函式。goodness()函式用來衡量乙個處於可執行狀態的程序值得執行的程度。此外,在schedule()函式中還呼叫了schedule_tail()函式;在reschedule_idle()函式中還呼叫了reschedule_idle_slow()。這些函式的實現對理解**p的排程非常重要,下面一一分析這些函式。先給出每個函式的主要流程圖,然後給出源**,並加注釋。
goodness()函式分析
goodness()函式計算乙個處於可執行狀態的程序值得執行的程度。乙個任務的goodness是以下因素的函式:正在執行的任務、想要執行的任務、當前的cpu。goodness返回下面兩類值中的乙個:1000以下或者1000以上。1000或者1000以上的值只能賦給「實時」程序,從0到999的值只能賦給普通程序。實際上,在單處理器情況下,普通程序的goodness值只使用這個範圍底部的一部分,從0到41。在**p情況下,**p模式會優先照顧等待同乙個處理器的程序。不過,不管是up還是**p,實時程序的goodness值的範圍是從1001到1099。
goodness()函式其實是不會返回-1000的,也不會返回其他負值。由於idle程序的counter值為負,所以如果使用idle程序作為引數呼叫goodness,就會返回負值,但這是不會發生的。
goodness()是個簡單的函式,但是它是linux排程程式不可缺少的部分。執行佇列中的每個程序每次執行schedule時都要排程它,因此它的執行速度必須很快。
Linux程序優先順序和調整優先順序
linux 是乙個多使用者 多工的作業系統,系統中通常執行著非常多的程序。但是 cpu 在乙個時鐘週期內只能運算一條指令 現在的 cpu 採用了多執行緒 多核心技術,所以在乙個時鐘週期內可以運算多條指令。但是同時運算的指令數也遠遠小於系統中的程序總數 那問題來了 誰應該先運算,誰應該後運算呢?這就需...
程序優先順序
程序的優先順序可以通過setpriority nice修改優先順序。程序分為普通程序和實時程序。實時程序的優先順序比普通程序的優先順序高。nice的值 20 19值越小優先順序越高。預設為0 不同程序的執行緒優先順序?執行緒會繼承程序的優先順序,核心的排程是執行緒。所以先看程序是普通程序還是實時程序...
程序優先順序
用top或者ps命令會輸出pri pr ni ni nice這三種指標值,這些到底是什麼東西?先給出大概的解釋如下 pri 程序優先權,代表這個程序可被執行的優先順序,其值越小,優先順序就越高,越早被執行 ni 程序nice值,代表這個程序的優先值 nice 改變過優先順序的程序的占用cpu的百分比...