linux CFS程序時間片排程策略

2021-07-25 05:43:07 字數 3492 閱讀 1158

refer to 

linux

支援三種程序排程策略,分別是

sched_fifo 、sched_rr和sched_normal。linux支援兩種型別的程序,實時程序和普通程序。實時程序可以採用sched_fifo 和sched_rr排程策略;普通程序採用sched_normal排程策略。

本文主要討論普通程序的排程演算法,為了描述方便,後面章節中的「程序」指「普通程序」。

從linux2.6.23核心到目前最新的linux3.3.5核心的普通程序(採用排程策略sched_normal)採用了絕對公平排程演算法,cfs(completely fair schedule)。cfs從rsdl/sd中吸取了完全公平的思想,不再跟蹤程序的睡眠時間,也不再區分互動式程序。它將所有的程序都統一對待,這就是公平的含義。cfs 排程中,程序資料結構中的動態優先順序成員prio還繼續有效,只是核心不再動態調整程序的動態優先順序了。

程序的優先順序為100—139,對應的nice值為-20—19。和之前版本的優先順序規定相同。nice 和優先順序對應關係如下

如何實現公平排程的?核心給每個程序維護了乙個虛擬執行時間vruntime,每個程序執行一段時間後,虛擬執行時間會增加,但是執行同樣的實際時間每個程序增加的數值是不同的。比如nice值為0的程序執行了10ms,其虛擬執行時間增加了1vms(vms為1虛擬毫秒,為了描述方便而定義);nice為19的程序執行10ms,其虛擬執行時間增加了1000vms。程序在其生命週期中,其虛擬執行時間一直都是在增加的。核心把虛擬執行時間看做實際執行時間,為了公平起見要選擇執行時間短的程序進行執行。所以核心在排程中總是選擇虛擬執行時間小的程序。對核心來說,這樣就很公平了,o(∩_∩)o

同樣執行10ms,如何確定乙個程序該增加多少vms?增加的虛擬執行時間和程序的優先順序nice數值有關,每個nice數值對應乙個權重數值,見下圖。

每個程序虛擬執行時間增加的時間量和(nice_0_load/nice_n_weight)成正比。其中nice_0_load 為1024,即nice數值為0的權重,nice_n_weight即為nice數值為n的程序的權重,如nice為-20(優先順序最高的普通程序)的權重為88761。從這種演算法也可以看出,優先順序高的程序的虛擬執行時間增加的慢,其實際執行時間累計數值也就長。同樣,這種演算法能保證優先順序低的程序也有執行機會,只是實際執行的時間比較短。

核心要把所有running狀態的程序放到一起,在需要排程時從中取出乙個虛擬執行時間短的程序。因為發生排程的頻率非常高,查詢合適程序的演算法就變的很重要了。在cfs排程中,核心採用了以程序虛擬執行時間為key值的紅黑樹資料結構掛接各個running的程序。有關紅黑樹請參考《linux核心之紅黑樹》。

先要引入乙個重要概念,排程實體

(sched entiy)

:就是排程的物件。每個程序的

task_struct

包含了排程實體成員變數

se。為何要引入排程實體,而不是直接使用程序的

task_struct

?是因為在

cfs中支援

cfs組排程,乙個組中可能包含

1個或多個程序。不能通過組中任何程序的

task_struct來排程組,所以引入了排程實體的概念。為了統一起見,程序組和程序都使用排程實體儲存排程相關的資訊。後面會介紹cfs組排程。

在多核系統中,每個cpu(此處指乙個核心)對應乙個全域性變數per_cpu_runqueues,其資料結構為struct rq,該變數為排程的最頂層的資料結構。在該資料結構中包含了cfs,其資料結構為struct cfs_rq。cfs 就是在該cpu上cfs排程的頂級結構,或者說是cfs排程的入口點。其實rq中還包括了rt成員變數,rt是實時程序排程的頂級結構。

struct cfs_rq

其中成員變數tasks_timeline指向了紅黑樹的根,所有的程序都掛到這棵紅黑樹上(有些是間接掛接的)。如下圖中的單個程序,程序資料結構task_struct中包含了成員變數se,即排程實體。排程實體se中包含了run_node節點,se通過該節點掛接到紅黑樹上。在選擇需要排程的程序時,核心將搜尋這個紅黑樹,找到虛擬執行時間小的程序,並把該程序從樹上摘下。同時會把切換出(因執行時間長而被剝奪執行的程序插入紅黑樹)。由於紅黑樹的特性,其插入、摘除和超找的效率都很高,從而保證了cfs排程的效率。

因下圖不清楚,直接把原始的word文件傳上了:

cfs組排程

為何要引入cfs組排程呢?假設使用者a和b共用一台機器。我們可能希望a和b能公平的分享cpu資源,但是如果使用者a使用建立了8個程序、而使用者b只建立1個程序,根據cfs排程是基於程序的(假設使用者程序的優先順序相同),a使用者占用的cpu的時間將是b使用者的8倍。

如何保證a、b使用者公平分享cpu呢?組排程就能做到這一點。把屬於使用者a和b的程序各分為一組,排程程式將先從兩個組中選擇乙個組,再從選中的組中選擇乙個程序來執行。如果兩個組被選中的機率相當,那麼使用者a和b將各占有約50%的cpu。

相關資料結構

在linux核心中,使用task_group結構來管理組排程的組。所有存在的task_group組成乙個樹型結構。

乙個task_group可以包含具有任意排程類別的程序(具體來說是實時程序和普通程序兩種類別),task_group包含實時程序對應的排程實體和排程佇列,以及普通程序對應的排程實體和排程佇列。見下面的結構定義

struct task_group

下面只描述cfs組排程。在多核處理器平台上,核心在建立組的時候,核心會在每個cpu上給該組建立乙個排程實體和乙個排程佇列,見上面圖中紅色方框外的部分。組在各個cpu上的排程實體se是單獨被排程的。紅色方框內是指在乙個cpu上的排程資料結構。如果組在該cpu上有可以執行的程序,則組在該cpu上的排程實體se就會掛到該cpu上cfs_rq的紅黑樹上。組在該cpu上可以執行的程序則掛到了組排程實體se中my_q指向的紅黑樹上,參見上圖中右下角單個程序。

cfs組的優先順序。組在建立時其優先順序是固定的,其nice值為0。組在某cpu上所能獲得的執行時間和乙個單獨的nice為0的程序獲得的執行時間相同。組的se在獲得了一定執行時間後,按照cfs演算法相同的方法把實際執行時間分配給其my_q上的所有程序。從而實現了a使用者和b使用者占用相同的cpu時間的目的。

疑問:有關程序權重表使用的疑問,在計算程序虛擬執行時間時,總是需要進行一次乘法和一次除法運算。大家都知道乘法和除法運算是比較消耗cpu週期的,為何不直接修改一下權重表prio_to_weight中的數值,使得其中的每一項數值都等於目前的數值除以15後取整(當然是人工計算出結果後替換到表中),使得優先順序最小的程序的權重為1。在計算虛擬執行時間時可以直接乘以權重值,這樣就可以減少一次除法了。這樣是否更好?

另外,從**中看到,nice為0的程序在計算虛擬執行時間時是直接增加了真實的時間差,而沒有進行乘和除的過程,如下圖,是否是因為設計初衷認為大多數的普通程序的nice值都是0的緣故?

程序排程 時間片輪轉

include include include typedef struct table node node creat void p2 next null return head 輸出函式 void print node head 對程序表按優先數從大到小排序 node insert node h...

Linux CFS排程演算法的理解

在加權的情況下,任務按照加權比例同時進行 例如a程序權重2,b程序權重1,a程序完成50 b程序應該完成25 加權後的實際分配的時間 排程的總時間 該程序權重 總權重 那麼我們就可以得到公式 程序實際分配時間 應該分配時間 排程的總時間 程序權重 總權重 程序應該分配時間 程序實際分配時間 應該分配...

時間片輪轉排程演算法

include define max 10 struct task struct tasks max int counter 實際程序個數 int time counter 0 int poutput 排程結果輸出 int time int charge 判斷是否所有的程序都被執行過 int tim...