本節說明如何評估一個 scheduling 的效能:
原理是兩個行程相互 pipe,排程器夾在其間來回奔波。
想像兩個行程互相丟球(資源的轉移),一旦排程器跟上球便拋給另一行程,而排程器追著球跑,如此我們就可以測量出排程器的速度(效能)。
Kuanch
這就是為什麼任務的數量遠大於核心數,但我們感到他們同時在執行;當然有平行化的功勞,但並行
核心 (core)
任務 (task)
行程 (process)
線程 (thread)
CPU affinity 在 有被提及,用於限定該程式發起的所有行程(?)僅運作於某一個 CPU core。
其次,與其說它是 scheduling 的效能,不如說是 context switch 的表現,不過這兩者在非專門對排程器演算法和內部實作分析的我們來說,可粗略地視作相等,因為此刻我們關心的是,scheduling 前前後後所處理的各種瑣事
除了 context switching,其他還有什麼花費?我認為大致可以公式化成以下
scheduling = context switching + task arrangement (scheduling) + load balance (rebalance_domains(), affinity) + synchronization (concurrency) + overhead
是所有的資源共享一個任務的 runqueue,排程器排程時經由 locking 來保證互斥,還是針對每個資源,我們都為其設置一個 runqueue,以減少 lock 帶來的損耗?
Run queue 或俗稱 ready queue,存有待執行的行程或線程供排程器決定下一個執行的任務;根據引文谈谈调度 - Linux O(1),這句話的場景是指當多個 core (即資源)嘗試取得任務應該如何取得,如果只有一個 runqueue,每個 core 進入取得任務時區要 lock runqueue,這是 Linux 2.4 scheduler 的策略,僅使用一個 global runqueue;見下一節令人詬病的 Linux 2.4 排程器。
而在 Linux 2.6 使用了 per core runqueue,見下一節 Linux 2.6 排程器
資源如何利用?是 run to completion,還是 time slicing?
run to completion 係指任務將執行直到完成,為 nonpreemptive scheduling;而 time slicing 則是依照設定的時間限制回到待執行狀態,等待下次執行,為 preemptive scheduling,如 Round Robin。
Linux 2.4 排程器的設計導致的以下問題
存取、搜尋、插入、刪除皆能夠滿足 的資料結構並不存在;瓶頸是搜尋,使用 B-tree 也需要 (換句話說,使用 B-tree 進行搜尋是最快的方法之一,複雜度為
融合多種資料結構,因 array 的存取可以達 (indexing),而 linked list, stack, queue 在插入刪除都能夠滿足 ,後來我們知道 Linux 2.6 選擇了 FIFO queue
如何將 array 和 FIFO queue 組合起來呢?使用一個 bitmap 依照 priority 紀錄是否有任務存在,因我們可以透過現代 CPU 指令快速取得目前最高優先權的 FIFO queue;確定 FIFO queue 後也可以在 內取得下一個任務。
但單一處理器在同一時間只能執行一個任務,換言之,不考慮觸發中斷與重新觸發排程機制的情況下,目前任務的時間片段在尚未執行完畢前,其他的任務沒有機會執行,這導致我們無法細緻地排程。
這邊提到一個問題,先前說當任務用盡 timeslice 後將放入 expired queue, runqueue (active priority array) 為空後將和 expired queue 對調,故即便是高優先權的任務被放入 expired queue 後也需要等待目前所有 active task 被執行完畢之後才會被執行。
那如何解決呢?Completely Fair Scheduler (CFS) ,它按照權重分配給低優先權的任務更多 CPU 使用時間,CFS 留待之後討論。