1. 程式人生 > >Linux核心之程序排程

Linux核心之程序排程

一些概念

  排程程式負責決定哪個程序投入執行,何時執行及執行多長時間。程序排程程式就是在可執行態程序之間分配有限的處理器時間資源的核心子系統。
多工系統可分為兩類:非搶佔式多工搶佔式多工。Linux提供了搶佔式多工。
I/O消耗型程序就是大部分時間用來提交I/O請求或者是等待I/O請求。
處理器消耗型程序就是把時間大多用在程式碼執行上。
排程策略通常就是在兩個矛盾的目標中間尋求平衡:程序迅速響應(響應時間短)、最大系統利用率(高吞吐量)。
程序優先順序:Linux中用nice值表示,範圍是從-20到+19,預設為0,越大的nice值代表更低的優先順序。
時間片:是程序在被搶佔之前所能持續執行的時間。時間片太短會明顯增加程序切換帶來的處理器耗時;時間片太長會導致系統互動表現欠佳。

Linux排程演算法

Linux排程器是以模組方式排程的,這樣做的目的是允許不同型別的程序可以針對性的選擇排程演算法。
完全公平排程演算法(CFS)是針對普通程序的排程,在Linux中稱為SCHED_NORMAL。演算法定義在檔案kernel/sched_fair.c。
完全公平排程(CFS)不是直接分配時間片到程序,而是將處理器的使用比劃分給程序,同時nice值(優先順序)只是作為程序獲得的處理器執行比的權重(幾何加權)。

Linux排程的實現

CFS排程演算法的實現分四個組成部分:

  • 時間記賬
  • 程序選擇
  • 排程器入口
  • 睡眠和喚醒

時間記賬:

CFS使用排程器實體結構(struct_sched_entity)

來追蹤程序執行的時間記賬,排程器實體結構是作為se成員變數嵌入在程序描述符struct task_struct內。
虛擬實時vruntime變數存放程序的虛擬執行時間,CFS用vruntime來記錄一個程式到底運行了多長時間以及還要執行多長時間。

程序選擇:

CFS排程演算法的核心:選擇最小的vruntime的任務。
CFS使用紅黑樹來組織可執行的程序佇列,並利用其迅速找到最小vruntime的程序。Linux中紅黑樹成為rbtree,是一個自平衡二叉搜尋樹。紅黑樹是以樹節點的形式儲存資料,每個資料對應一個鍵值。
平衡二叉搜尋樹的原則是鍵值小於該節點,則轉向左分支,鍵值大於該節點,則轉向右分支。所以CFS的程序選擇演算法可簡單總結為“執行rbtree樹中最左邊葉子節點所代表的程序”。
CFS將程序加入到rbtree中是發生在程序變為可執行狀態或者是通過fork呼叫第一次建立程序時。新增原則就是鍵值小的走左分支,鍵值大的走又分支。
CFS將程序從rbtree中刪除是發生在程序阻塞或者終止時。

排程器入口

程序排程的主要入口點是函式schedule():選擇哪個程序可以執行,何時將其投入執行。函式會呼叫pick_next_task(),以優先順序為序依次檢查每一個排程類,從最高優先順序的排程類中選擇最高優先順序的程序。

睡眠和喚醒

睡眠:程序把自己標記為休眠狀態,從可執行紅黑樹中移除,放入等待佇列,然後呼叫schedule()選擇和執行一個其他程序
喚醒:喚醒操作通過wake_up()函式進行,喚醒指定的佇列的所有程序。

搶佔和上下文切換

上下文切換就是從一個可執行程序切換到另一個可執行程序,由context_switch()函式負責處理。
使用者搶佔:核心即將返回使用者空間的時候,如果need_resched標誌被設定,會導致schedule()被呼叫。使用者搶佔發生在以下情況,從系統呼叫返回使用者空間時;從中斷處理程式返回使用者空間時。
核心搶佔:Linux支援完整的核心搶佔,只要沒有鎖,核心就可以進行搶佔。
核心搶佔發生在:
- 中斷處理程式正在執行,且返回核心空間之前
- 核心程式碼再一次具有可搶佔性的時候
- 核心中的任務顯式的呼叫schedule
- 如果核心中的任務阻塞

實時排程策略

Linux提供了兩種實時排程策略:SCHED_FIFOSCHED_RR
SCHED_FIFO實現的是一種簡單的、先入先出的排程演算法,不使用時間片。處於可執行狀態的SCHED_FIFO級程序會比任何SCHED_NORMAL級的程序優先得到呼叫。它不基於時間片,可以一直執行下去,只有自己收阻塞或者顯式的釋放處理器,或者更高優先順序的SCHED_FIFO或SCHED_RR程序搶佔。相同優先順序的SCHED_FIFO程序會輪流執行,但同樣是在它們願意讓出處理器才行。
SCHED_RR是帶有時間片的SCHED_FIFO,這是一種實時輪流排程演算法。