1. 程式人生 > >作業系統CPU上下文切換

作業系統CPU上下文切換

程序切換

進行程序切換就是從正在執行的程序中收回處理器,然後再使待執行程序來佔用處理器。 這裡所說的從某個程序收回處理器,實質上就是把程序存放在處理器 的暫存器中的中間資料找個地方存起來,從而把處理器的暫存器騰出來讓其他程序使用。那麼被中止執行程序的中間資料存在何處好呢?當然這個地方應該是程序的 私有堆疊。   

讓程序來佔用處理器,實質上是把某個程序存放在私有堆疊中暫存器的資料(前一次本程序被中止時的中間資料)再恢復到處理器的暫存器中去,並把待執行程序的斷點送入處理器的程式指標PC,於是待執行程序就開始被處理器運行了,也就是這個程序已經佔有處理器的使用權了。   

這就像多個同學要分時使用同一張課桌一樣,說是要收回正在使用課桌同學的課桌使用權,實質上就是讓他把屬於他的東西拿走;而賦予某個同學課桌使用權,只不過就是讓他把他的東西放到課桌上罷了。   

在切換時,一個程序儲存在處理器各暫存器中的中間資料叫做程序的上下文,所以程序的切換實質上就是被中止執行程序與待執行程序上下文的切換。在程序未佔用處理器時,程序 的上下文是儲存在程序的私有堆疊中的。  

從上面的敘述可知,排程器程序切換的程式碼應有如下功能:   

●儲存處理器PC暫存器的值到被中止程序的私有堆疊;  

●儲存處理器PSW暫存器的值到被中止程序的私有堆疊;  

●儲存處理器SP暫存器的值到被中止程序的程序控制塊; 

●儲存處理器其他暫存器的值到被中止程序的私有堆疊; 

●自待執行程序的程序控制塊取SP值並存入處理器的暫存器SP;  

●自待執行程序的私有堆疊恢復處理器各暫存器的值;   

●自待執行程序的私有堆疊中彈出PSW值並送入處理器的PSW;

●自待執行程序的私有堆疊中彈出PC值並送入處理器的PC。 

  顯然,程序的切換可以用中斷技術來實現,即當排程器獲得了待執行程序的控制塊之後,應立即用軟 中斷指令來中止當前程序的執行,並儲存當前程序的PC值和PSW值。其後,使 用壓棧指令把處理器其他暫存器的值壓入程序私有堆疊。接下來,就從待執行程序的程序控 制塊中取出私有堆疊指標的值並存入處理器的暫存器SP,至此SP就指向了待執行程序的私 有堆疊,於是下面就自待執行程序的私有堆疊中彈出上下文進人處理器。最後,利用中斷返回指令來實現自待執行程序的私有堆疊中彈出PSW值和自待執行程序的 私有堆疊中彈出PC值的功能。   

這是一個完整的軟中斷處理過程,只不過在保護現場和恢復現場工作中,保護的是被中止 執行程序的現場,恢復的是待執行程序的現場,這一切都依賴於堆疊指標的切換。

程序排程

1:程序型別:

在Linux排程演算法中,將程序分為兩種型別。即:I/O消耗型和CPU消耗型。例如文字處理程式與正在執行的Make的程式。文字處理程式大部份時間都 在等待I/O裝置的輸入,而make程式大部份時間都在CPU的處理上。因此為了提高響應速度,I/O消耗程式應該有較高的優先順序,才能提高它的互動性。 相反的,Make程式相比之下就不那麼重要了。只要它能處理完就行了。因此,基於這樣的原理,linux有一套互動程式的判斷機制。

在task_struct結構中新增了一個成員:sleep_avg.此值初始值為100。程序在CPU上執行時,此值減少。當程序在等待時,此值增加。最後,在排程的時候。根據sleep_avg的值重新計算優先順序。

2:程序優先順序

正如我們在上面所說的:互動性強的需要高優先順序,互動性弱的需要低優先順序。在linux系統中,有兩種優先順序:普通優先順序和實時優先順序。

3:執行時間片

程序的時間片是指程序在搶佔前可以持續執行的時間。在linux中,時間片長短可根據優先順序來排程。程序不一定要一次執行完所有的時間片,可以在運時的中途被切換出去。

4:程序搶佔

當一個程序被設為TASK_RUNING狀態時。它會判斷它的優先順序是否高於正在執行的程序。如果是,則設定排程標誌位,呼叫schedule()執行程序的排程。當一個程序的時間片為0時,也會執行程序搶佔。

關於CPU,有3個重要的概念:上下文切換(context switchs),執行佇列(Run queue)和使用率(utilization)。

上下文切換:
   目前流行的CPU在同一時間內只能執行一個執行緒,超執行緒的處理器可以在同一時間執行多個執行緒(包括多核CPU),Linux核心會把多核的處理器當作多個單獨的CPU來識別。
   一個標準的Linux核心可以支援執行50~50000個程序執行,對於普通的CPU,核心會排程和執行這些程序。每個程序都會分到CPU的時間片來運 行,當一個程序用完時間片或者被更高優先順序的程序搶佔後,它會備份到CPU的執行佇列中,同時其他程序在CPU上執行。這個程序切換的過程被稱作上下文切 換。過多的上下文切換會造成系統很大的開銷。

執行佇列  每個CPU都會維持一個執行佇列,理想情況下,排程器會不斷讓佇列中的程序執行。程序不是處在sleep狀態就是run able狀態。如果CPU過載,就會出現排程器跟不上系統的要求,導致可執行的程序會填滿佇列。佇列愈大,程式執行時間就愈長。


關於時間片和動態優先順序
   時間片對於CPU來說是很關鍵的引數,如果時間片太長,就會使系統的互動效能變差,使用者感覺不到並行。如果太短,又會造成系統頻繁的上下文切換,使效能 下降。對於IO Bound的系統來講並不需要太長的時間片,因為系統主要是IO操作;而對於CPU Bound的系統來說需要長的時間片以保持cache的有效性。
  每一個程序啟動的時候系統都會給出一個預設的優先順序,但在執行過程中,系統會根據程序的執行狀況不斷調整優先順序,核心會升高或降低程序的優先順序(每次增加或降低5),判斷標準是根據程序處於sleep狀態的時間。
  
   IO Bound程序大部分時間在sleep狀態,所以核心會調高它的優先順序,CPU Bound程序會被核心懲罰降低優先順序。因此,如果一個系統上即執行IO Bound程序,又執行CPU Bound程序,會發現,IO Bound程序的效能不會下降,而CPU Bound程序效能會不斷下降。

經驗總結:
1. 對於每一個CPU來說執行佇列不要超過2,例如,如果是雙核CPU就不要超過4;
2. 如果CPU在滿負荷執行,應該符合下列分佈,
a) User Time:65%~70%
b) System Time:30%~35%
c) Idle:0%~5%
3. 對於上下文切換要結合CPU使用率來看,如果CPU使用滿足上述分佈,大量的上下文切換也是可以接受的。