天天看點

Linux kernel是如何執行組排程的

Linux系統主排程函數,當執行到該函數時,從目前cpu的rq隊列中選擇一個task投入運作:

static void __sched__schedule(void) {
	struct task_struct *prev, *next;
	...
	rq = cpu_rq(cpu);
	...
	put_prev_task(rq, prev);
	...
	next = pick_next_task(rq);
	...
	context_switch(rq, prev, next);
}
           
Linux kernel是如何執行組排程的

1, CFS組排程 fair_sched_class.pick_next_task = pick_next_task_fair

Linux kernel是如何執行組排程的
Linux kernel是如何執行組排程的

pick_next_entity從系統cfs隊列(csf_rq)中選擇一個排程實體se(紅黑樹最左邊的節點); set_next_entity設定cfs_rq->curr = se 等; group_cfs_rq會判斷選擇到的se是對應一個task還是一個task_group,如果是task可直接切換到該task運作,如果是task_group還需要繼續往下執行。可根據se->my_q判斷se對應什麼,如果se->my_q為空表示se是一個task,如果不為空se表示是一個task_group(排程組): static inline struct cfs_rq * group_cfs_rq(struct sched_entity *grp) { return grp->my_q; } struct sched_entity中my_q字段的意義, 如果排程實體代表task_group,則它的my_q字段指向這個排程組對應的運作隊列;否則my_q字段為NULL,排程實體代表task。

Linux kernel是如何執行組排程的

是以如果group_cfs_rq判斷se是排程組,那麼該排程組自己的cfs隊列就是cfs_rq = group_cfs_rq(se)。下次循環就從排程組自己的cfs隊列中選擇一個排程實體se(紅黑樹最左邊的節點),如果se還是對應排程組,就繼續遞歸下去,直到在某個子(後代)排程組的cfs隊列中找到對應一個task的se,然後将其投入運作。

一個組排程對應核心要為其建立一個task_group。例如,在系統CPU子系統/sys/fs/cgroup/cpu/下面建立一個目錄my_test,即/sys/fs/cgroup/cpu/my_test,然後将系統中的某些程序轉移到my_test中去,echo PIDxxx > /sys/fs/cgroup/cpu/my_test/tasks。 核心将為你的my_test cpu子系統建立一個task_group用于my_test的組排程, 并為該task_group初始化它自己的se與cfs,rt隊列(為task_group結構體的變量),如下代碼所示:

Linux kernel是如何執行組排程的

為my_test建立struct task_group:

Linux kernel是如何執行組排程的

初始化struct task_group的cfs_rq隊列與cfs_se(用于組中NORMAL程序的排程):

Linux kernel是如何執行組排程的

初始化struct task_group的rt_rq隊列與rt_se(用于組中實時程序的排程):

Linux kernel是如何執行組排程的

初始化結果(假設系統有兩個CPU):

Linux kernel是如何執行組排程的

例如,在my_test下又建立了my_test_child, /sys/fs/cgroup/cpu/my_test =>對應一個task_group /sys/fs/cgroup/cpu/my_test/my_test_child =>對應一個task_group echo PIDxxx > /sys/fs/cgroup/cpu/my_test/my_test_child/tasks 其在CPU0上的排程過程如下: 從cpu_rq(0)->cfs_rq中得到紅黑樹最左側節點se ---> 如果該se是my_test對應task_group->se[0], 那麼se[0]->my_q != null,說明是個組排程實體, 從該組排程實體相應隊列se[0]->my_q中擷取紅黑樹最左側節點se ---> 如果該se是my_test_child對應task_group->se[0],如果se[0]->my_q != null,說明仍然是個組排程實體, 繼續從該組排程實體相應隊列se[0]->my_q中擷取紅黑樹最左側節點se ---> se[0]->my_q == null, 說明se是個task,其PID正是PIDxxx ,然會傳回給__schedule函數投入排程。

2, rt組排程 rt_sched_class.pick_next_task = pick_next_task_rt

Linux kernel是如何執行組排程的
Linux kernel是如何執行組排程的
LXC