代碼邏輯比較簡單:
1、確定就緒隊列的當前執行的調度實體
/* 確定就緒隊列的當前執行進程curr */
struct sched_entity *curr = cfs_rq- >curr;
2、根據獲取的當前執行進程,計算當前和上一次更新負荷權重時兩次的時間的差值
u64 now = rq_clock_task(rq_of(cfs_rq));
u64 delta_exec;
if (unlikely(!curr))
return;
delta_exec = now - curr- >exec_start;
if (unlikely((s64)delta_exec <= 0))
return;
3、重新更新啟動時間exec_start為now,以備下次計算時使用,最后將計算出的時間差加到先前的統計時間上。
/* 重新更新啟動時間exec_start為now */
curr- >exec_start = now;
schedstat_set(curr- >statistics.exec_max,
max(delta_exec, curr- >statistics.exec_max));
/* 將時間差加到先前統計的時間即可 */
curr- >sum_exec_runtime += delta_exec;
schedstat_add(cfs_rq, exec_clock, delta_exec);
這也是通過cat /proc/$pid/sched看到的一些統計信息
4、開始計算虛擬時間
curr- >vruntime += calc_delta_fair(delta_exec, curr);
5、計算虛擬時間函數calc_delta_fair如下,忽略舍入和溢出檢查,calc_delta_fair函數所做的計算如下:
/*
* delta /= w
*/
static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se)
{
if (unlikely(se- >load.weight != NICE_0_LOAD))
delta = __calc_delta(delta, NICE_0_LOAD, &se- >load);
return delta;
}
其中NICE_0_LOAD的值為:1024,當進程的nice=0時,不需要進行加權處理,其虛擬時間就等于其實際運行時間。
# define SCHED_FIXEDPOINT_SHIFT 10
#define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT)
#define NICE_0_LOAD (1L < < NICE_0_LOAD_SHIFT)
?1024也就是Nice值為0對應的權重值,權重值在內核中是預先定義好的,如下所示:
const int sched_prio_to_weight[40] = {
/* -20 */ 88761, 71755, 56483, 46273, 36291,
/* -15 */ 29154, 23254, 18705, 14949, 11916,
/* -10 */ 9548, 7620, 6100, 4904, 3906,
/* -5 */ 3121, 2501, 1991, 1586, 1277,
/* 0 */ 1024, 820, 655, 526, 423,
/* 5 */ 335, 272, 215, 172, 137,
/* 10 */ 110, 87, 70, 56, 45,
/* 15 */ 36, 29, 23, 18, 15,
};
通過公式和內核預先設定的權重表,可以看出來:
Nice值越高(對應的優先級越低),權重越小,虛擬時間累加的越快(虛擬時間過得越快),Nice值越低(對應的優先級越高),權值越高,虛擬時間累加的越慢(虛擬時間過得越慢)。CFS的思想核心也就是這樣,讓每個調度實體的虛擬時間增加速度不同,使用虛擬時間來衡量調度實體在CPU上已經執行的時間。
總結:
不同優先級的進程以各自對應的速度推進虛擬時間,只要保證在一個調度延遲內虛擬時間的推進進展相同,就實現了完成公平,公平指的是相對公平,即按進程的權重給予不同的運行時間,虛擬時間越小,代表著受到了"不公平"對待,因此下一個參與調度的調度實體就是紅黑樹中的最左邊(虛擬時間最小)的節點,如此一來既能公平選擇進程,又能保證高權重進程獲得較多的運行時間。
-
Linux
+關注
關注
87文章
11336瀏覽量
210097 -
代碼
+關注
關注
30文章
4819瀏覽量
68878
發布評論請先 登錄
相關推薦
評論