Linux內核實現了基於虛擬時鐘的完全公平調度算法。
每個調度實體具有與其其快照看起來像
struct sched_entity {
...
u64 exec_start;
u64 sum_exec_runtime;
u64 vruntime;
u64 prev_sum_exec_runtime;
...
}
上述四個屬性用於跟蹤一個進程的運行時以及使用與一些其它方法沿着這些屬性相關聯的sched_entity
結構(update_curr()
其中這些被更新),虛擬時鐘被實現。 將進程分配給CPU時,將exec_start
更新爲當前時間,並將消耗的CPU時間記錄在sum_exec_runtime
中。當從CPU sum_exec_runtime
中取出進程時,值將保存在prev_sum_exec_runtime
中。 sum_exec_runtime
累計計算。 (意味着它單調增長)。
vruntime
存儲過程執行過程中虛擬時鐘流逝的時間量。
如何計算vruntime
?
忽略所有的複雜的計算,它是如何計算的核心概念是: -
vruntime += delta_exec_weighted;
delta_exec_weighted = delta_exec * (NICE_0_LOAD/load.weight);
這裏delta_exec
被處理分配給CPU和從CPU取出之間的時間差而load.weight
是重取決於優先級(Nice Value)的過程。通常情況下,一個進程的好值1的增加意味着它減少了10%的CPU時間,從而減輕了重量。 過程與NICE值0,重量= 1024 過程重新Niced與值1,重量= 1024/1.25 = 820(約)從上方
- 所以
vruntime
增加繪製 點當進程得到CPU
- 和
vruntime
與較低優先級進程相比,對於較高優先級進程緩慢增加。
的運行隊列被保持在紅黑樹和每個運行隊列具有與其相關聯的變量min_vruntime
保持所述最小vruntime
中在運行隊列的所有過程。 (min_vruntime
只能增加,不會隨着進程的安排而減少)。
在紅黑樹的節點,關鍵是process->vruntime - min_vruntime
當調用調度程序,內核基本上拿起其中有最小的鍵(最左邊的節點),併爲其分配CPU的任務。
具有較小鍵的元素將放置在更靠左的位置,因此可以更快地安排。
- 當進程運行時,其
vruntime
會穩步增加,所以它最終會在紅黑樹中向右移動。 因爲vruntime
對於更重要的過程增加得更慢,所以它們也將向右移動得更慢,所以對於不太重要的過程,它們的調度機會更大 - 正如所需。
- 如果一個進程休眠,其
vruntime
將保持不變。因爲在此期間每個隊列min_vruntime
將增加,所以睡眠過程在喚醒後會更靠左,因爲(上面提到的)鍵變小了。
因此沒有餓死,就好像被剝奪CPU的低優先級的進程的機會,都會有其vruntime
最小的,因此重點將是最小的,因此移動到樹的左側迅速,因此調度。