1. 程式人生 > >Linux中的程序排程方法簡介

Linux中的程序排程方法簡介

實時排程演算法介紹

 對於什麼是實時系統,POSIX 1003.b作了這樣的定義:指系統能夠在限定的響應時間內提供所需水平的服務。而一個由Donald Gillies提出的更加為大家接受的定義是:一個實時系統是指計算的正確性不僅取決於程式的邏輯正確性,也取決於結果產生的時間,如果系統的時間約束條件得不到滿足,將會發生系統出錯。實時系統根據其對於實時性要求的不同,可以分為軟實時和硬實時兩種型別。硬實時系統指系統要有確保的最壞情況下的服務時間,即對於事件的響應時間的截止期限是無論如何都必須得到滿足。比如航天中的宇宙飛船的控制等就是現實中這樣的系統。其他的所有有實時特性的系統都可以稱之為軟實時系統。如果明確地來說,軟實時系統就是那些從統計的角度來說,一個任務(在下面的論述中,我們將對任務和程序不作區分)能夠得到有確保的處理時間,到達系統的事件也能夠在截止期限到來之前得到處理,但違反截止期限並不會帶來致命的錯誤,像實時多媒體系統就是一種軟實時系統。一個計算機系統為了提供對於實時性的支援,它的作業系統必須對於CPU和其他資源進行有效的排程和管理。在多工實時系統中,資源的排程和管理更加複雜。本文下面將先從分類的角度對各種實時任務排程演算法進行討論,然後研究普通的 Linux作業系統的程序排程以及各種實時Linux系統為了支援實時特性對普通Linux系統所做的改進。

最後分析了將Linux作業系統應用於實時領域中時所出現的一些問題,並總結了各種實時Linux是如何解決這些問題的。

  1. 實時CPU排程演算法分類 各種實時作業系統的實時排程演算法可以分為如下三種類別[Wang99][Gopalan01]:基於優先順序的排程演算法(Priority-drivenscheduling-PD)、基於CPU使用比例的共享式的排程演算法(Share-driven scheduling-SD)、以及基於時間的程序排程演算法(Time-driven scheduling-TD),下面對這三種排程演算法逐一進行介紹。 

   1.1. 基於優先順序的排程演算法 基於優先順序的排程演算法給每個程序分配一個優先順序,在每次程序排程時,排程器總是排程那個具有最高優先順序的任務來執行。根據不同的優先順序分配方法,基於優先順序的排程演算法可以分為如下兩種型別[Krishna01][Wang99]: 靜態優先順序排程演算法: 這種排程演算法給那些系統中得到執行的所有程序都靜態地分配一個優先順序。靜態優先順序的分配可以根據應用的屬性來進行,比如任務的週期,使用者優先順序,或者其它的預先確定的策略。RM(Rate-Monotonic)排程演算法是一種典型的靜態優先順序排程演算法,它根據任務的執行週期的長短來決定排程優先順序,那些具有小的執行週期的任務具有較高的優先順序。動態優先順序排程演算法: 這種排程演算法根據任務的資源需求來動態地分配任務的優先順序,其目的就是在資源分配和排程時有更大的靈活性。非實時系統中就有很多這種排程演算法,比如短作業優先的排程演算法。在實時排程演算法中, EDF演算法是使用最多的一種動態優先順序排程演算法,該演算法給就緒佇列中的各個任務根據它們的截止期限(Deadline)來分配優先順序,具有最近的截止期限的任務具有最高的優先順序。

    1.2. 基於比例共享排程演算法 雖然基於優先順序的排程演算法簡單而有效,但這種排程演算法提供的是一種硬實時的排程,在很多情況下並不適合使用這種排程演算法:比如象實時多媒體會議系統這樣的軟實時應用。對於這種軟實時應用,使用一種比例共享式的資源排程演算法(SD演算法)更為適合。 比例共享排程演算法指基於CPU使用比例的共享式的排程演算法,其基本思想就是按照一定的權重(比例)對一組需要排程的任務進行排程,讓它們的執行時間與它們的權重完全成正比。我們可以通過兩種方法來實現比例共享排程演算法[Nieh01]:第一種方法是調節各個就緒程序出現在排程佇列隊首的頻率,並排程隊首的程序執行;第二種做法就是逐次排程就緒佇列中的各個程序投入執行,但根據分配的權重調節分配個每個程序的執行時間片。比例共享排程演算法可以分為以下幾個類別:輪轉法、公平共享、公平佇列、彩票排程法(Lottery)等。比例共享排程演算法的一個問題就是它沒有定義任何優先順序的概念;所有的任務都根據它們申請的比例共享CPU資源,當系統處於過載狀態時,所有的任務的執行都會按比例地變慢。所以為了保證系統中實時程序能夠獲得一定的CPU處理時間,一般採用一種動態調節程序權重的方法。

   1.3. 基於時間的程序排程演算法 對於那些具有穩定、已知輸入的簡單系統,可以使用時間驅動(Time-driven:TD)的排程演算法,它能夠為資料處理提供很好的預測性。這種排程演算法本質上是一種設計時就確定下來的離線的靜態排程方法。在系統的設計階段,在明確系統中所有的處理情況下,對於各個任務的開始、切換、以及結束時間等就事先做出明確的安排和設計。這種排程演算法適合於那些很小的嵌入式系統、自控系統、感測器等應用環境。這種排程演算法的優點是任務的執行有很好的可預測性,但最大的缺點是缺乏靈活性,並且會出現有任務需要被執行而CPU卻保持空閒的情況。

   2. 通用Linux系統中的CPU排程通用Linux系統支援實時和非實時兩種程序,實時程序相對於普通程序具有絕對的優先順序。對應地,實時程序採用SCHED_FIFO或者SCHED_RR排程策略,普通的程序採用SCHED_OTHER排程策略。 在排程演算法的實現上,Linux中的每個任務有四個與排程相關的引數,它們是rt_priority、policy、priority(nice)、counter。排程程式根據這四個引數進行程序排程。在SCHED_OTHER 排程策略中,排程器總是選擇那個priority+counter值最大的程序來排程執行。從邏輯上分析,SCHED_OTHER排程策略存在著排程週期(epoch),在每一個排程週期中,一個程序的priority和counter值的大小影響了當前時刻應該排程哪一個程序來執行,其中 priority是一個固定不變的值,在程序建立時就已經確定,它代表了該程序的優先順序,也代表這該程序在每一個排程週期中能夠得到的時間片的多少; counter是一個動態變化的值,它反映了一個程序在當前的排程週期中還剩下的時間片。在每一個排程週期的開始,priority的值被賦給 counter,然後每次該程序被排程執行時,counter值都減少。當counter值為零時,該程序用完自己在本排程週期中的時間片,不再參與本排程週期的程序排程。當所有程序的時間片都用完時,一個排程週期結束,然後周而復始。另外可以看出Linux系統中的排程週期不是靜態的,它是一個動態變化的量,比如處於可執行狀態的程序的多少和它們priority值都可以影響一個epoch的長短。值得注意的一點是,在2.4以上的核心中, priority被nice所取代,但二者作用類似。 可見SCHED_OTHER排程策略本質上是一種比例共享的排程策略,它的這種設計方法能夠保證程序排程時的公平性--一個低優先順序的程序在每一個epoch中也會得到自己應得的那些CPU執行時間,另外它也提供了不同程序的優先順序區分,具有高priority值的程序能夠獲得更多的執行時間。 對於實時程序來說,它們使用的是基於實時優先順序rt_priority的優先順序排程策略,但根據不同的排程策略,同一實時優先順序的程序之間的排程方法有所不同: SCHED_FIFO:不同的程序根據靜態優先順序進行排隊,然後在同一優先順序的佇列中,誰先準備好執行就先排程誰,並且正在執行的程序不會被終止直到以下情況發生:1.被有更高優先順序的程序所強佔CPU;2.自己因為資源請求而阻塞;3.自己主動放棄CPU(呼叫sched_yield); SCHED_RR:這種排程策略跟上面的SCHED_FIFO一模一樣,除了它給每個程序分配一個時間片,時間片到了正在執行的程序就放棄執行;時間片的長度可以通過sched_rr_get_interval呼叫得到; 由於Linux系統本身是一個面向桌面的系統,所以將它應用於實時應用中時存在如下的一些問題: Linux系統中的排程單位為10ms,所以它不能夠提供精確的定時;當一個程序呼叫系統呼叫進入核心態執行時,它是不可被搶佔的; Linux核心實現中使用了大量的封中斷操作會造成中斷的丟失;由於使用虛擬記憶體技術,當發生頁出錯時,需要從硬碟中讀取交換資料,但硬碟讀寫由於儲存位置的隨機性會導致隨機的讀寫時間,這在某些情況下會影響一些實時任務的截止期限;雖然Linux程序排程也支援實時優先順序,但缺乏有效的實時任務的排程機制和排程演算法;它的網路子系統的協議處理和其它裝置的中斷處理都沒有與它對應的程序的排程關聯起來,並且它們自身也沒有明確的排程機制;

     3. 各種實時Linux系統 

     3.1. RT-Linux和RTAI RT -Linux是新墨西哥科技大學(New Mexico Institute of Technology)的研究成果[RTLinuxWeb][Barabanov97]。它的基本思想是,為了在Linux系統中提供對於硬實時的支援,它實現了一個微核心的小的實時作業系統(我們也稱之為RT-Linux的實時子系統),而將普通Linux系統作為一個該作業系統中的一個低優先順序的任務來執行。另外普通Linux系統中的任務可以通過FIFO和實時任務進行通訊。RT-Linux的框架如圖 1所示:圖 1 RT-Linux結構RT -Linux的關鍵技術是通過軟體來模擬硬體的中斷控制器。當Linux系統要封鎖CPU的中斷時時,RT-Linux中的實時子系統會擷取到這個請求,把它記錄下來,而實際上並不真正封鎖硬體中斷,這樣就避免了由於封中斷所造成的系統在一段時間沒有響應的情況,從而提高了實時性。當有硬體中斷到來時, RT-Linux擷取該中斷,並判斷是否有實時子系統中的中斷例程來處理還是傳遞給普通的Linux核心進行處理。另外,普通Linux系統中的最小定時精度由系統中的實時時鐘的頻率決定,一般Linux系統將該時鐘設定為每秒來100個時鐘中斷,所以Linux系統中一般的定時精度為 10ms,即時鐘週期是10ms,而RT-Linux通過將系統的實時時鐘設定為單次觸發狀態,可以提供十幾個微秒級的排程粒度。 RT-Linux實時子系統中的任務排程可以採用RM、EDF等優先順序驅動的演算法,也可以採用其他排程演算法。RT -Linux對於那些在重負荷下工作的專有系統來說,確實是一個不錯的選擇,但他僅僅提供了對於CPU資源的排程;並且實時系統和普通Linux系統關係不是十分密切,這樣的話,開發人員不能充分利用Linux系統中已經實現的功能,如協議棧等。所以RT-Linux適合與工業控制等實時任務功能簡單,並且有硬實時要求的環境中,但如果要應用與多媒體處理中還需要做大量的工作。義大利的RTAI( Real-Time Application Interface )源於RT-Linux,它在設計思想上和RT-Linux完全相同。它當初設計目的是為了解決RT-Linux難於在不同Linux版本之間難於移植的問題,為此,RTAI在 Linux 上定義了一個實時硬體抽象層,實時任務通過這個抽象層提供的介面和Linux系統進行互動,這樣在給Linux核心中增加實時支援時可以儘可能少地修改 Linux的核心原始碼。

      3.2. Kurt-LinuxKurt -Linux由Kansas大學開發,它可以提供微秒級的實時精度[KurtWeb] [Srinivasan]。不同於RT-Linux單獨實現一個實時核心的做法,Kurt -Linux是在通用Linux系統的基礎上實現的,它也是第一個可以使用普通Linux系統呼叫的基於Linux的實時系統。 Kurt-Linux將系統分為三種狀態:正常態、實時態和混合態,在正常態時它採用普通的Linux的排程策略,在實時態只執行實時任務,在混合態實時和非實時任務都可以執行;實時態可以用於對於實時性要求比較嚴格的情況。為了提高Linux系統的實時特性,必須提高系統所支援的時鐘精度。但如果僅僅簡單地提高時鐘頻率,會引起排程負載的增加,從而嚴重降低系統的效能。為了解決這個矛盾, Kurt-Linux採用UTIME所使用的提高Linux系統中的時鐘精度的方法[UTIMEWeb]:它將時鐘晶片設定為單次觸發狀態(One shot mode),即每次給時鐘晶片設定一個超時時間,然後到該超時事件發生時在時鐘中斷處理程式中再次根據需要給時鐘晶片設定一個超時時間。它的基本思想是一個精確的定時意味著我們需要時鐘中斷在我們需要的一個比較精確的時間發生,但並非一定需要系統時鐘頻率達到此精度。它利用CPU的時鐘計數器TSC (Time StampCounter)來提供精度可達CPU主頻的時間精度。對於實時任務的排程,Kurt-Linux採用基於時間(TD)的靜態的實時CPU排程演算法。實時任務在設計階段就需要明確地說明它們實時事件要發生的時間。這種排程演算法對於那些迴圈執行的任務能夠取得較好的排程效果。 Kurt -Linux相對於RT-Linux的一個優點就是可以使用Linux系統自身的系統呼叫,它本來被設計用於提供對硬實時的支援,但由於它在實現上只是簡單的將Linux排程器用一個簡單的時間驅動的排程器所取代,所以它的實時程序的排程很容易受到其它非實時任務的影響,從而在有的情況下會發生實時任務的截止期限不能滿足的情況,所以也被稱作嚴格實時系統(Firm Real-time)。目前基於Kurt-Linux的應用有:ARTS(ATM Reference TrafficSystem)、多媒體播放軟體等。另外Kurt-Linux所採用的這種方法需要頻繁地對時鐘晶片進行程式設計設定。

     3.3. RED-Linux RED -Linux是加州大學Irvine分校開發的實時Linux系統[REDWeb][ Wang99],它將對實時排程的支援和Linux很好地實現在同一個作業系統核心中。它同時支援三種類型的排程演算法,即:Time-Driven、Priority-Dirven、Share-Driven。為了提高系統的排程粒度,RED-Linux從RT-Linux那兒借鑑了軟體模擬中斷管理器的機制,並且提高了時鐘中斷頻率。當有硬體中斷到來時,RED-Linux的中斷模擬程式僅僅是簡單地將到來的中斷放到一個佇列中進行排隊,並不執行真正的中斷處理程式。另外為了解決Linux程序在核心態不能被搶佔的問題, RED-Linux在Linux核心的很多函式中插入了搶佔點原語,使得程序在核心態時,也可以在一定程度上被搶佔。通過這種方法提高了核心的實時特性。 RED-Linux的設計目標就是提供一個可以支援各種排程演算法的通用的排程框架,該系統給每個任務增加了如下幾項屬性,並將它們作為程序排程的依據: Priority:作業的優先順序;Start-Time:作業的開始時間; Finish-Time:作業的結束時間; Budget:作業在執行期間所要使用的資源的多少; 通過調整這些屬性的取值及排程程式按照什麼樣的優先順序來使用這些屬性值,幾乎可以實現所有的排程演算法。這樣的話,可以將三種不同的排程演算法無縫、統一地結合到了一起。