每日閱讀1之內核設計與實現(第三版)4.5——linux調度實現之時間記賬

前面討論CFS調度算法的動機和內在邏輯,下面開始探索CFS是如何實現的。

相關代碼位於kernel/sched_fair.c文件中。

主要包含四個組成部分:

(1)時間記賬

(2)進程選擇

(3)調度器入口

(4)睡眠與喚醒

今天,主要關注時間記賬這個部分。。。

所有的調度器都必須對進程的運行時間進行記賬,大多數unix系統採用爲進程分配一個時間片,每當系統時鐘節拍發生時,時間片減少一個節拍週期,當剩餘時間片減少到0時,該進程被其它可運行進程搶佔。

在現在的CFS調度中,沒有了時間片的概念,但是仍然需要進行時間記賬,以確保每個進程只在分配給它的處理器時間內運行,CFS使用調度器實體結構struct sched_entity(定義位於linux/sched.h中)來跟蹤進程運行記賬。。

struct sched_entity {
struct load_weight load; /* for load-balancing */
struct rb_node run_node;
struct list_head group_node;
unsigned int on_rq;


u64 exec_start;
u64 sum_exec_runtime; //虛擬運行時間,以ns爲單位,和定時器節拍不在相關
u64 vruntime;
u64 prev_sum_exec_runtime;


u64 last_wakeup;
u64 avg_overlap;


u64 nr_migrations;


u64 start_runtime;
u64 avg_wakeup;


u64 avg_running;

。。。。。。。。。。

}

調度器實體結構,實際上是一個成員變量se,嵌入在進程結構體中。

kernel/sched_fair.c中的update_curr()函數實現vruntime記賬功能。

static void update_curr(struct cfs_rq *cfs_rq)
{
struct sched_entity *curr = cfs_rq->curr;
u64 now = rq_of(cfs_rq)->clock_task;
unsigned long delta_exec;


if (unlikely(!curr))
return;


/*
* Get the amount of time the current task was running
* since the last time we changed load (this cannot
* overflow on 32 bits):
*/
delta_exec = (unsigned long)(now - curr->exec_start); //該函數計算當前進程的執行時間,並放在delta_exec變量中,而後將該運行時間傳遞到__update
if (!delta_exec)
return;


__update_curr(cfs_rq, curr, delta_exec);
curr->exec_start = now;


if (entity_is_task(curr)) {
struct task_struct *curtask = task_of(curr);


trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime);
cpuacct_charge(curtask, delta_exec);
account_group_exec_runtime(curtask, delta_exec);
}

好,一個好的開始,明天接着分析。。。

/*
 * Update the current task's runtime statistics. Skip current tasks that
 * are not in our scheduling class.
 */
static inline void
__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
     unsigned long delta_exec)
{
unsigned long delta_exec_weighted;


schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max));


curr->sum_exec_runtime += delta_exec;
schedstat_add(cfs_rq, exec_clock, delta_exec);
delta_exec_weighted = calc_delta_fair(delta_exec, curr);


curr->vruntime += delta_exec_weighted; //__update_curr進行加權計算(根據可運行進程總數),最終值加入到當前進程的vruntime中去
update_min_vruntime(cfs_rq);
}

update_curr()是由系統定時器週期性調用(中斷上下文?),無論進程處於運行態或阻塞態,根據這種方式vruntime可以準確的測定給定進程的運行時間。。

這句話看不懂,這裏的系統定時器的工作層次在哪裏?

下一節去研究一下,系統定時器。。

欲知後事如何,see U next paper!






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章