今天我們來學習排程類cfs和rt排程類。
簡述
cfs是絕對公平排程演算法,理想情況下,優先順序相同的兩個task,執行時間應該各佔cpu的50%,同理3個則cpu利用率為1/3。但是cfs中弱化了優先順序的概念而是使用權重weight來決定任務的執行時間。例如:3個任務a,b,c權重分別1,2,3;則總權重,乙個排程週期為6單位時間,理想狀態下,a應占用1單位,b為2,c為3。
cfs中使用虛擬時間vruntime來決定執行的task,nice值-20到20 --> weight -->vruntime; cfs中使用rbtree來管理排程實體se。每次選取vruntime最小的task進行執行。在rbtree中vruntime最小的se在rbtree的最左側。cfs是通過限制當前task的執行時間來實現公平的,task的vruntime單調遞增,它在rbtree中向右移動,讓出cpu使用權給vruntime更小的task。
cfs即普通程序的nice值在-20到19之間。即優先順序在100到139之間.0-99是實時程序,採用rt排程類。
nice值和權重weight之間的轉化,是通過**sched_prio_to_weight轉換的。
kernel/sched/core.c中
const int sched_prio_to_weight[40] = ;
查表法很快得出nice值對應的weight值。nice值為0的weight為1024。同時nice值為0,所對應的vruntime 虛擬時間是和物理時間是同乙個時鐘的,不用通過weight進行加權計算,nice值每上公升一級,則load值下降20%,則總vruntime則下降10%。
vruntime是由該task當前時間和上次更新時間的插值delta 在加上weight權重加權計算而來的。
週期性排程器 scheduler_tick()中會呼叫 具體排程類的task_tick函式。
task_tick_failr()
->entity_tick()
->->update_curr() 更新當前時間的vruntime
kernel/sched/fair.c中
static void update_curr(struct cfs_rq *cfs_rq)
account_cfs_rq_runtime(cfs_rq, delta_exec);
}
curr->vruntime += calc_delta_fair(delta_exec, curr);
/*更新當前task的vruntime,檔期那vruntime+乙個值*/
來看calc_delta_fair()函式
當nice為0時 vruntime 就加上delta值,即為兩次更新物理時間的差值,但當nice值不為0時,則要加權一下。
static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se)
/* * delta_exec * weight / lw.weight
* or
* (delta_exec * (weight * lw->inv_weight)) >> wmult_shift
* * either weight := nice_0_load and lw \e sched_prio_to_wmult, in which case
* we're guaranteed shift stays positive because inv_weight is guaranteed to
* fit 32 bits, and nice_0_load gives another 10 bits; therefore shift >= 22.
* * or, weight =< lw.weight (because lw.weight is the runqueue weight), thus
* weight/lw.weight <= 1, and therefore our shift will also be positive.
*/static u64 __calc_delta(u64 delta_exec, unsigned long weight, struct load_weight *lw)
} /* hint to use a 32x32->64 mul */
fact = (u64)(u32)fact * lw->inv_weight;
while (fact >> 32)
return mul_u64_u32_shr(delta_exec, fact, shift);
}
delta vt = delta vt * nice_0_load/load;
由於除法的演算法效率很低,所以獎除法轉換成乘法和移位操作;轉換成公式:
delat vt = (ldelta vt 1024 * 2^32 /load2^32 ) >> 32;
將2^32/load * 2^32依舊做成查表法 inv_load。
pick_next_fair:
選擇rbtree上vruntime最小的se來進行排程。
vruntime 是在entity_tick中update_curr中更新。
task 至少執行一次的時間間隔。
組排程會有自己的cfs_rq,組內的各se的vruntime如何計算?
排程組對應的se的vruntime是如何計算的?
每個task_group都有乙個shares,share並非我們說的程序優先順序,而是排程權重,這個是cfs排程管理的概念,但在cfs中最終體現到排程優先排序上。shares值預設都是相同的,所有沒有設定權重的值。
entity_tick()
->update_cfs_group()
static void update_cfs_group(struct sched_entity *se)
排程組的shares即為se的load weight。 小張學linux核心 七 裝置樹的使用
在很久之前的版本,uboot還需要傳machine id和引數區位址給核心,但現在只傳遞裝置樹 fdt 的位址給核心了,這些引數全在fdt中做了。uboot將裝置樹bin檔案和kernel載入到記憶體,然後將fdt位址傳給kernel,跳到kernel位址執行。fdt為平坦裝置樹,即數作為乙個乙個節...
小張學linux核心之資料結構 1 hlist
閱讀linux原始碼時,經常會遇到hlist的使用,hlist,看名稱是雜湊鍊錶的意思,那我們學過hash表,是將一串長的資料物件對映到乙個陣列中,已陣列下標來訪問它所對應的資訊。在學習linux字元驅動時,也接觸到雜湊桶的知識。相同主裝置號對應乙個hash表的槽位,子裝置號則是這個槽位所掛的鍊錶上...
Linux系統調優 核心相關引數(五)
修改核心引數有3種辦法 一種臨時修改,兩種永久修改。臨時修改是使用sysctl 選項 引數名 值 命令 永久修改是修改 etc sysctl.conf檔案或修改 proc sys 目錄下的對應檔案 例如,修改net.ipv4.tcp synack retries 0,即echo 0 proc sys...