Xen 代碼分析分析(4.RT調度)

Xen向GuestOS伸出了魔爪

之所以這麼寫這個標題,是因爲寫到這裏,我發現,這一部分的解析纔剛剛露出冰山一角,這一部分是指Xen作爲Hypervisor對操作GuestOS的支撐部分,我在想是不是要在這個文檔裏寫這個問題;因爲這。。。不屬於調度了吧(還是屬於?)?這已經屬於GuestOS的調度基礎支撐了。

RT調度的do_schedule()

Xen的RT調度入口函數是位於文件”./xen/common/sched_rt.c”中的static struct task_slice rt_schedule(conststruct scheduler *ops, s_time_t now,bool_t tasklet_work_scheduled)。主要處理:任務選擇,預算結算,返回所選擇的任務、將運行時間以及是否遷移自其他pcpu。本章將會分析rt_schedule()函數的實現。

1.  cpumask_clear_cpu(cpu,&prv->tickled);

從tickled中清楚當前pcpu位圖,tickled置位是因爲執行了runq_tickle(),runq_tickle()有點發現優先級排序不對了,會整理,然後就會產生一次軟中斷調度查找到3處使用runq_tickle()的位置,分別是vcpu剛醒、上下文切換時剛保存完當前vcpu現場,調度完

2.  burn_budget(ops,scurr, now);

將當前vcpu的預算結算掉(idle_vcpu除外),對於RT調度,系統定義了私有的數據結構struct rt_vcpu[63],其中的last_start元素snext->last_start = now; 在下一個vcpu投入運行前更新了此元素。記錄上次投入運行的時間,可以計算出當前vcpu已經執行的時長[65],在計算完後也要再次將last_start=now;cur_budget記錄vcpu運行時預算在此處RT調度的預算只可能被減少,另外有一個timer會調用repl_timer_handler()來爲失去預算的vcpu補充預算。詳見章節RT調度的預算補充,當cur_budget<=0,如果flags元素flags同樣是struct rt_vcpu的元素,定義有詳盡的標誌位中存在RTDS_exteratime標誌根據註釋,RTDS_extratime標誌是想讓進程有多x輪的預算,以至於在沒有優先級比他高的vcpu,他就可以一直跑?因爲默認sched_init_vcpu()創建vcpu時都會alloc_vdata(),alloc_vdata()是scheduler的接口,在RT的實現都給加了此標誌。只有在hypercall的do_domctl() XEN_DOMCTL_SCHEDOP_putvcpuinfo操作是沒有XEN_DOMCTL_SCHEDRT_extra標誌時,纔會被清楚此標誌位。,則提升其優先級、補充其預算我很懷疑這種操作的合理性,否則置位flags元素的RTDS_depleted標誌表示vcpu預算耗盡,在之後的處理中將會被加入到預算耗盡的vcpu鏈表,等待補充預算。

3.  tasklet_work_scheduledtasklet需要處理標誌被置位時:snext = rt_vcpu(idle_vcpu[cpu]);

有tasklet需要正式調度過去執行此種情況發生在tasklet_list的任務在tasklet觸發後,發現需要此pcpu執行,即當前pcpu的tasklet_work_to_do被置位了,於是在調度時遇到,則需要執行。,就不會發生runq_pick()算法選擇可投入執行的vcpu操作,即將要投入運行的任務將會是idle_vcpu,只需做一些記錄即可,作爲空閒vcpu會不停地執行tasklet。

4.  snext= runq_pick(ops, cpumask_of(cpu));

遍歷可執行vcpu鏈表,綜合vcpu所處Domain的有效pcpu位圖vcpu所在struct domain中有struct cpupool,cpupool內cpu_valid用位圖表示可用pcpu們。、vcpu的硬親和pcpu位圖vcpu中有cpu_hard_affinity位圖,表示vcpu僅可在哪幾個pcpu上執行。和實際pcpu位圖smp_processor_id()可獲得。,得到下一個運行的vcpu找到的第一個vcpu即爲投入運行的vcpu,於是此鏈表順序很重要,包含調度原則。。需要注意的是這裏的選擇vcpu並不考慮剩餘預算的問題,如果沒有預算,系統將會失敗,也就是說,RunQ中vcpu必有預算。

5.  if (snext == NULL ) snext = rt_vcpu(idle_vcpu[cpu]);

如果沒有合適的vcpu被選到,則執行idle_vcpu。

6.  查看是否需要執行之前的vcpu

if( !is_idle_vcpu(current) &&  

vcpu_runnable(current) &&

scurr->cur_budget > 0&&

( is_idle_vcpu(snext->vcpu) ||compare_vcpu_priority(scurr, snext) > 0 ) )

snext = scurr

如果之前的vcpu,不是idle_vcpu、可執行沒有暫停標誌和暫停計數,並且其所在域也沒有、預算存在並且新選的vcpu是idle_vcpu或比之前vcpu優先級低,則不會切換。

總結成人話就是:如果選完以後發現是空閒vcpu並且原先的vcpu不空閒,那麼繼續執行之前的vcpu;如果選出的vcpu優先級不如之前的高,並且之前的vcpu還有預算,那麼還是執行之前的vcpu。這是RT調度的重要原則之一。

7.  if ( snext != scurr &&

!is_idle_vcpu(current) &&

vcpu_runnable(current) )

__set_bit(__RTDS_delayed_runq_add, &scurr->flags);

如果下一個要投入運行的vcpu不是當前vcpu,並且當前運行的vcpu也不是idle_vcpu,並且當前vcpu還是可執行;置位struct rt_vcpu->flags的__RTDS_delayed_runq_add在rt_context_saved()這個vcpu會被加入到RunQ,rt_context_saved()是在啓動投運vcpu前執行的context_saved()裏調用。

8.  snext->last_start= now;

更新下一個投入執行的vcpu的投入時間

9.  if ( snext->vcpu->processor != cpu ){

snext->vcpu->processor = cpu;

ret.migrated = 1;

}

檢查此vcpu是否遷移自非當前pcpu跨pcpu的任務遷移必然會引起大量cache miss,降低效率,因此原則上跨pcpu的調度應該有一定阻尼,很明顯Xen的RT沒有做。,對於產生遷移的需要更新vcpu->processor;ret是是函數返回值task_slice數據結構,置位其migrated元素,提示遷移發生在schedule()中R next_slice = sched->do_schedule(sched, now,tasklet_work_scheduled); 也有介紹, if ( next_slice.migrated ) sched_move_irqs(next); 同樣根據此處判斷結果。

10. ret.time= snext->cur_budget;

cur_budget存有當前vcpu將會被投入運行的時長,放入在返回值struct task_slice中time元素在schedule()中設置投運任務的運行時間時使用此元素。

11. ret.task= snext->vcpu;

將選定的vcpu設置到返回值中。

RT調度的預算補充

當vcpu的預算消耗完,需要補充預算的vcpu們會被放到ReplQ鏈表,由軟定時器repl_timer[83]觸發的處理函數repl_timer_handler()將會爲之補充預算。下面將分析repl_timer_handler()功能。

1.  遍歷ReplQ鏈表,在遍歷過程中,會不斷給ReplQ中的vcpu元素補充預算、按週期延展deadline、將優先級置0,並加入到臨時鏈表等待進一步處理;預算補充完後,檢測如果vcpu還在RunQ/DeplQ,則會拔、插先從RunQ/DeplQ鏈表取出,再插入,可以重新決定vcpu進RunQ/DeplQ,如果進入RunQ還可以重新排列其位置。回RunQ/DeplQ此處預算剛補充完畢,應該會插回RunQ。。再次遍歷過程中,如果遇到deadline未到的vcpu應截止遍歷,僅處理已補充預算的vcpu。

2.  遍歷上一步補充過預算的vcpu,如果發現vcpu正在運行,但優先級並不比RunQ上的下一個vcpu高因爲Xen的RT調度所有pcpu共用待RunQ鏈表,經過重新充能先後時可能出現低優先級被先執行的情況的。,這是不合理的,觸發runq_tickle()runq_tickle()會檢查指定scheduler的新加vcpu是否有機會調度,如果有,則觸發調度軟中斷。;如果vcpu不在執行,判斷其RTDS_depleted標誌位(判斷完清除之)並確認其在RunQ/DeplQ,同樣觸發runq_tickle()。

RT調度的喚醒

vcpu任務的喚醒由rt_vcpu_wake()執行,對於以下vcpu狀態:

1.  vcpu正在指定的pcpu執行,更改per-cpu狀態vcpu_wake_running,喚醒結束。

2.  vcpu處於RunQ/DeplQ,更改per-cpu狀態vcpu_wake_onrunq,喚醒結束。

喚醒vcpu可直接執行完畢。

對於普通情況,檢測vcpu處於可執行狀態/不可執行狀態,相應的更改per-cpu狀態標誌。如果vcpu的deadline已超時,更新其deadline、預算、last_start=now、優先級置0rt_update_deadline()操作。;否則無需操作。如果vcpu RTDS_scheduled標誌vcpu在pcpu上執行。置位,則置位RTDS_delayed_runq_add,以便於在此vcpu經過rt_context_saved()時會將之加入RunQ/DeplQ;如果之前判斷deadline超時,則此處需要將其在ReplQ上插拔一次,以防止其在ReplQ鏈表不存在或順序問題,完成後喚醒即結束。對於vcpu RTDS_scheduled未置位,即vcpu未在pcpu上執行,則需要將其插入ReplQ、RunQ/DeplQ、然後用runq_tickle()檢查一下是否該觸發軟中斷如果被喚醒vcpu優先級高的話。,喚醒結束。

RT調度的優先級

RT調度的優先級首先由struct rt_vcpu->priority_level決定,priority_level越小的vcpu優先級越高;在同優先級的情況下,會比較structrt_vcpu->cur_deadline,deadline越近的vcpu優先級越高。具體可查看函數compare_vcpu_priority()。

RT調度的數據結構

RT調度有3個鏈表每個RT調度的scheduler實體有3個鏈表,多個scheduler(RT/Credit)共存是可能的。,由所有的pcpu源文件中存在註釋表述的是CPU pool,用pcpu是爲了不用解釋CPU pool。共享一個是有序排列順序是優先級高在前,同優先級的deadline緊急的靠前。的RunQ鏈表,鏈接有預算且可執行的vcpu;一個是無序DeplQ鏈表,鏈接沒有預算等待補充預算之後就能跑的vcpu;最後是一個有序排列順序同樣是優先級高在前,同優先級的deadline緊急的靠前與RunQ用同樣的插入函數和優先級比較方式。的ReplQ鏈表,鏈接等待補充預算的vcpu。

RunQ和DeplQ是互斥的兩個鏈表,即一個vcpu不能同時在RunQ和DeplQ上;但一個vcpu應該同時在RunQ和ReplQ上,或同時在DeplQ和ReplQ上。

ReplQ只能在vcpu喚醒、初創的時候,插入RunQ/DeplQ(或is_running態)纔會被插入ReplQ;當vcpu不再被調度時,需要離開ReplQ(也會離開RunQ/DeplQ)。

如果vcpu是由於進入睡眠rt_vcpu_sleep()是調度器接口sleep的RT實現、被銷燬rt_vcpu_remove()是調度器接口remove_vcpu的RT實現,在銷燬vcpu(sched_destroy_vcpu())、遷移domain(sched_move_domain())被使用。、遷移離開調度rt_context_saved()是調度器context_saved的RT實現,,則離開3大鏈表。

RT調度的deadline

RT調度的deadline位於rt_vcpu->cur_deadline,唯一可以補充cur_deadline的位置是rt_update_deadline(),而在普通運行階段vcpu初始化、vcpu喚醒也會執行rt_update_deadline()操作。,唯有軟定時器repl_tmer的處理函數repl_timer_handler()會調用rt_update_deadline()爲vcpu更新deadline,軟定時器repl_timer的觸發時間總是按照RunQ即將投入運行的任務的cur_deadline設定。

進一步

經過上述分析可以全面的瞭解Xen調度的前因後果,RT調度的實現考量,之後還需要進一步分析以及目前Xen的調度在ARM平臺存在的一些問題如下。

1.  總結分析可能觸發調度的點。

2.  Xen對vcpu的切換過程,如寄存器保存、新寄存器值設入。

3.  Xen在已啓動的pcpu中如何啓動其他pcpu。

在vcpu_initialise()時,會有

   vcpu->arch.saved_context.sp = (register_t)v->arch.cpu_info;

   vcpu->arch.saved_context.pc = (register_t)continue_new_vcpu;

    是如何工作的。

4.  目前的RT調度,各CPU均採用同一任務鏈表,調度需要獲取鎖,是存在存在競爭、浪費的。

5.  Xen跨CPU調度僅根據一些固定設置,不是阻尼的方式防止,這很明顯會引起不必要的cachemiss降低效率。

6.  Xen不能感知GuestOS的空閒、於是當vcpu執行idle線程時,Xen也不會有動作,是否可以修改GuestOS的idle線程。

7.  Xen對大小核並未考慮。

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