在cfs調度中有這麼幾個常用的參數:
-
sysctl_sched_latency:表示一段時間內,sched_entity肯定會被調度到一次,也就是一個sched_entity調度的最大的延時,2.6.35.13內核中默認是6ms。
-
sysctl_sched_min_granularity:表示調度的最小粒度,如果調度的時間間隔小於這個時間段,內核是不會挑選其他sched_entity進行調度,這個2.6.35.13內核中默認是2ms。
-
nr_latency:表示在上面的那段最大調度延遲中,最多處理的sched_entity。
上面的這些參數,書上都是這麼說的,說下個人的理解。
-
對於sysctl_sched_latency參數是調度的最大延遲,在cfs中,調度根據sched_entity的vruntime來選擇對應的調度單位,對於不同的sched_entity的load並不相同,cfs_rq中記錄了running的sched_entity的總load,可以根據sched_entity的load占總cfs_rqload的比重來分配調度時間,內核中就是通過統計sched_entity的運行時間來確定是否運行的時間夠了,如果夠了,那麼要重新選擇vruntime最小的單位進行調度,這樣才能保證在sysctl_sched_latency讓所有的running的sched_entity運行一次。
-
sysctl_sched_min_granularity變量比較好理解,sched_tick中,應該判斷當前運行的sched_entity的運行時間是否超過了sysctl_sched_min_granularity,如果未超過,就表示當前sched_entity還需要繼續運行,如果超過了,可能會考慮讓wakeup的sched_entity搶占調度。
-
nr_latency是延遲時間段能最大處理任務的數量,在這段時間點有可能切換進程,這幾個時間點就是當一個sched_entity運行時間超過了sysctl_sched_min_granularity,那麼就可以考慮切換進程了,這樣如果每次都切換進程,那麼延遲時間段內最大處理任務的數量就是nr_latency
nr_latency=sysctl_sched_latency/sysctl_sched_min_granularity
sched_entity的理論運行時間是按照cfs_rq中的總的load和當前sched_entity的load來平分sysctl_sched_latency的。
static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
u64 slice = __sched_period(cfs_rq->nr_running + !se->on_rq);//獲得總的運行時間段,這個時間有可能比sysctl_sched_latency要大
for_each_sched_entity(se) {
struct load_weight *load;
struct load_weight lw;
cfs_rq = cfs_rq_of(se);
load = &cfs_rq->load;//獲得cfs_rq總的load
if (unlikely(!se->on_rq)) { //如果se不再rq中,說明rq中的load不包括se的load,這個時候需要把se的load加到rq上
lw = cfs_rq->load;
update_load_add(&lw, se->load.weight);
load = &lw;
}
//根據slice是一輪調度總的時間,load是rq總的load,se->load.weight是se的load,這樣就可以算出load占總load的百分比,然後體現在平分slice上
slice = calc_delta_mine(slice, se->load.weight, load);
}
return slice;
}
__sched_period函數是計算調度一輪所有的sched_entity所需要的時間
static u64 __sched_period(unsigned long nr_running)
{
u64 period = sysctl_sched_latency;
unsigned long nr_latency = sched_nr_latency;
if (unlikely(nr_running > nr_latency)) {
period = sysctl_sched_min_granularity;
period *= nr_running;
}
return period;
}
如果當前可以運行的sched_entity的個數超過了 nr_latency,那麼認為 在sysctl_sched_latency的一段時間內調度所有的sched_entity時間不夠,這時候需要按照nr_running的個樹,擴大 sysctl_sched_latency。時鐘周期中斷函數會調用scheduler_tick,最終調用了cfs中的check_preempt_tick,檢測當前調度的sched_entity是否需要被搶占,需要調度其他的sched_entity。
static void
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
unsigned long ideal_runtime, delta_exec;
ideal_runtime = sched_slice(cfs_rq, curr);
//獲得當前進程的理想運行時間,按照sched_entity的load和rq的總load平分 sysctl_sched_latency所得的時間
delta_exec = curr->sum_exec_runtime – curr->prev_sum_exec_runtime;
//sum_exec_runtime是sched_entity自fork出來的運行時間,prev表示截止到上次切換進程的運行時間,所以這兩個時間之差就是切換到當前進程後,該進程所運行的時間
if (delta_exec > ideal_runtime) {
//可以知道如果當前進程運行時間超過了理論運行時間,那麼就應該讓其它的進程運行了。
resched_task(rq_of(cfs_rq)->curr);
/*
* The current task ran long enough, ensure it doesn't get
* re-elected due to buddy favours.
*/
clear_buddies(cfs_rq, curr);
//如果curr被放在了cfs_rq的next或者last位,就應該清除這個引用。
return;
}
/*
* Ensure that a task that missed wakeup preemption by a
* narrow margin doesn't have to wait for a full slice.
* This also mitigates buddy induced latencies under load.
*/
if (!sched_feat(WAKEUP_PREEMPT))
return;
if (delta_exec < sysctl_sched_min_granularity)
//如果進程運行的時間小於最小的進程切換的時間,那麼是不需要切換進程的,切換的越頻繁,成本開銷也就越大
return;
if (cfs_rq->nr_running > 1) {
//給剛wakeup的進程一個機會,避免使他等太久的時間未得到調度(由於當前進程的理想運行時間過長),其實在wakeup一個進程 的時候已經有機會讓wakeup的進程先調度,可能由於vruntime和curr的vruntime相距不大,沒有得到運行的機會,這裡再給新wakeup的進程一次被調度的機會。
struct sched_entity *se = __pick_next_entity(cfs_rq);
s64 delta = curr->vruntime - se->vruntime;
if (delta > ideal_runtime)
resched_task(rq_of(cfs_rq)->curr);
}
}
在切換sched_entity的時候會記錄當前sched_entity的 prev_sum_exec_runtime,表示當前的 prev_sum_exec_runtime=sum_exec_runtime,至於最後pick出next sched_entity後為什麼要判斷和當前vruntime之差大於理想運行時間,才能重新調度新的進程,猜測一下,對於一個剛剛wakeup的進程,sleep了足夠長的時間了,一個sysctl_sched_latency就可以讓curr進程的vruntime增加ideal_runtime(nice=0,優先級低的增加的會更快,優先級高的增加的會相對慢一些,需要多個sysctl_sched_latency的時間),那麼可以認為curr的vruntime和wakeup的vruntime差距超過了ideal_runtime,curr相對於sleep進程已經執行了足夠長的時間了,這時候即使curr在這一輪調度沒有達到ideal_runtime的時間,那麼也該需要新喚醒的進程輪到調度了,所以這個時候需要resched