Xen 代碼分析分析(3.一次調度的處理)

一次調度的處理

Xen調度入口函數位於文件”./xen/common/schedule.c”中的static voidschedule(void)。調度的觸發方式會有多種,在Xen中確定已知的有定時觸發、中斷返回觸發、任務阻塞觸發(分析能觸發調度的時機是非常重要的,但由於能力所限,短時間內不能枚舉,此處僅列舉分析過程中確定可以觸發調度的時機。)。所有觸發的調度最終都會傳導到schedule。

在schedule()

1.  switch( *tasklet_work )

tasklet_worktasklet_work=&this_cpu(tasklet_work_to_do)是當前pcpu變量,由DECLARE_PER_CPU定義。是當前pcputasklet work的狀態標誌,可以爲TASKLET_enqueued、TASKLET_scheduled以及TASKLET_enqueued|TASKLET_scheduled,如果僅有TASKLET_scheduled置位,表示不需要處理,否則調度器會執行idle_vcpu,idle_vcpu會執行do_tasklet(),並調整標誌位。do_tasklet()會調用do_tasklet_work(),在do_tasklet_work()中,tasklet的func會被執行;只有在tasklet鏈表中不再有元素時,do_tasklet()會清除TASKLET_enqueued標誌位。在TASKLET_enqueued標誌位被清除時schedule()會清除TASKLET_scheduled。

2.  stop_timer(&sd->s_timer);

sd是當前pcpu的schedule_data,其中包含鎖、struct vcpu *curr當前正在運行的任務vcpu數據結構指針。、void *sched_priv這是調度器的私有數據結構入口。、struct timer s_timer調度定時器,軟中斷將會處理其內function函數。、urgent的vcpu計數。各pcpu的struct timers數據struct timers也是per-cpu變量,依舊是繼承自Linux的各pcpu變量定義,struct timers並未被DECLARE_PER_CPU引用聲明,由宏DEFINE_PER_CPU定義,DEFINE_PER_CPU是對per-cpu變量的真實定義,而DECLARE_PER_CPU是對per-cpu變量的引用聲明。&this_cpu(a)訪問本pcpu的per-cpu變量&per_cpu(a,cpu0)訪問cpu0核的per-cpu變量。中有struct timer,分爲struct timer **heap根據add_to_heap()和remove_from_heap()的分析,struct timer **heap是一個timer堆,大概按照超時順序排列。如果發現所插入timer爲堆內首個timer,則會軟件產生一個TIMER_SOFTIRQ,堆滿才用鏈表。,struct *liststruct timers中的struct timer list是一個timer鏈表,按照超時時間大小排列,在struct timer ** heap空間不夠時,纔會用鏈表。發現所插入timer是鏈表第一個元素時會軟件產生TIMER_SOFTIRQ。,struct timer *runningstruct timers中的struct timer running在timer的function被執行時(見20.中timer_softirq_action()),會從timer堆或timer鏈表中移除,然後實際執行時(execute_timer())被加入到running鏈表。,struct list_head inactivestruct timers中的struct timer inactive是timer被deactivate之後的存放之處。,此處將struct timer->status設置爲TIMER_STATUS_inactive,並加入timer所屬pcpu下struct timers數據的inactive鏈表。timers和timer有着完整的機制描述,可在軟定時器機制struct timers和struct timer查看。

3.  next_slice= sched->do_schedule(sched, now, tasklet_work_scheduled);

調用當前pcpu的調度器計算下一個要投入運行的任務,其中next_slice包含3個元素:structvcpu *task vcpu是Xen調度的基本單位。、s_time_t time指示當前task_slice將會運行多久,主要來自調度器自定數據結構中xx_vcpu->cur_budget。、bool_t migrated指示這個任務是否是從其他pcpu遷移到這裏的。;sched爲調度器結構體,指向當前pcpu調度器指針;do_schedule()爲調度器調度計算函數入口[49];now=NOW()是CPU時間;tasklet_work_scheduled是tasklet需要調度投入執行的標誌(tasklet_work_scheduled置位會使調度器在選擇任務使選中idle_vcpu,idle_vcpu內有tasklet處理函數入口do_tasklet()。)

4.  next =next_slice.task;

next是將會被投入運行的任務。

5.  sd->curr= next;

至此,schedule函數選好了投入運行的任務,記錄到sd的curr可執行狀態RUNSTATErunnable遇到tasklet佔用、高優先級的vcpu等是會被調度出去的。

6.  設置投運任務的運行時間

if (next_slice.time >= 0 ) set_timer(&sd->s_timer, now +next_slice.time);

next_slice.time只有在下一個任務使idle_vcpu的時候纔會小於0;set_timer()將會給當前pcpu的調度定時器續時,時長決定於next_slice.time。

7.  省略

TRACE_3D()、TRACE_4D()會記錄調度的切換,不予分析;當計算完發現即將投入運行的任務還是之前的任務,則會直接投入運行。

8.  vcpu_runstate_change();

修改被調度出局任務的runstate,runstate記錄有vcpu在各狀態停留時間,根據被調度出局的原因:阻塞、離線、可執行[52],是一個struct vcpu_runstate_info數據結構,包含int statestate元素記錄vcpu當前所處狀態:RUNSTATE_running、RUNSTATE_runnable、RUNSTATE_blocked、RUNSTATE_offline、uint64_t state_entry_timevcpu進入當前狀態的時間。、uint64_t time[4]state元素的4個狀態,分別對應數組中的四個元素,記錄有當前vcpu在四個狀態的累計時間。

9.  prev->last_run_time= now;

記錄被調度出局的vcpu的出局時間。

10. vcpu_runstate_change(next,RUNSTATE_running, now);

記錄即將投運任務的runstate。

11. next->is_running= 1;

標誌着vcpu正在運行中。

12. stop_timer(&prev->periodic_timer);

關閉調度出局的vcpu的periodic_timer,其處理函數爲vcpu_periodic_timer_fn() init_timer(&v->periodic_timer,vcpu_periodic_timer_fn, v, v->processor);,periodic_timer的作用是向vcpu定時發出虛擬中斷信號通過evtchn_port_set_pending()向vcpu發送了一箇中斷信號,;此處將之關閉即不再發出此虛擬中斷。

13. if (next_slice.migrated ) sched_move_irqs(next);

對於即將投入運行的vcpu,如果是從別的cpu遷移過來的,則需要調整他的IRQ到當前的cpu上這又是一個大活兒啊,另外還涉及到Xen對中斷機制的操作,

14. vcpu_periodic_timer_work(next);

即將投入運行的vcpu的periodc_timer的啓動:首先檢測當前是否到vcpu的週期,決定是否發出virq;然後檢查並遷移periodic_timer到在當前pcpu名下migrate_timer()完成;最後設置vcpu下一個virq發生點。

15. context_switch(prev,next);

進行了任務切換 context_switch()需要做很多很多事,不過功能卻只有一個,任務切換,於是先不分析細節。

描述Xen的調度單位vcpu

structvcpu 分析

vcpu是Xen的基本調度單位,其數據結構structvcpu複雜還好我已經搞明白了不少。,下面將分析其關鍵元素。

int

vcpu_id;

vcpu識別號

int            

processor;

vcpu運行的pcpu號

vcpu_info_t    

*vcpu_info;

NC

struct domain  

*domain;

指向vcpu所在的域

(即描述虛擬機的主數據結構)

s_time_t      

periodic_period;

時間計數,週期時長

s_time_t       

periodic_last_event;

時間計數,上次週期開始時間

struct timer    

periodic_timer;

週期定時器,給vcpu提供虛擬中斷的

struct timer    

poll_timer;   

/* timeout for SCHEDOP_poll */

void           

*sched_priv;   

指向vcpu所處調度器的私有數據結構,與調度算法密切相關,由算法實現者定義,對於RT調度,此指針指向struc rt_vcpu

struct vcpu_runstate_info

runstate;

記錄vcpu運行狀態、進入此運行狀態的時間,在各個運行狀態累積時間。

uint64_t

last_run_time;

記錄調度出去的時間

bool          

is_initialised;

/* Initialization completed for this VCPU?

bool           

is_running;

正在pcpu上運行的標誌

unsigned long   

pause_flags;

vcpu被暫停標誌

atomic_t        

pause_count;

被暫停計數

cpumask_var_t   

cpu_hard_affinity;

允許vcpu執行的pcpu位圖

cpumask_var_t   

cpu_hard_affinity_tmp;

/* Used to change affinity temporarily. */

    cpumask_var_t   

cpu_hard_affinity_saved;

    /* Used to restore affinity across S3. */

    cpumask_var_t   

cpu_soft_affinity;

    /* Bitmask of CPUs on which this VCPU prefers to run. */

struct arch_vcpu

arch;

 

記錄有ARM的各個寄存器值(含pc、sp)以及其他不認識的,在任務切換時大顯身手

    cpumask_var_t   

vcpu_dirty_cpumask;

/* Bitmask of CPUs which are holding onto this VCPU's state. */

struct vcpu還有很多很多元素,以上元素佔比<50%,其他元素與調度關係不大,省略。

structrt_vcpu分析

struct rt_vcpu是RT調度專有數據結構,如下爲全部元素:

struct list_head

q_elem

作爲一個鏈表元素,可能被放在RunQ鏈表、DeplQ鏈表或爲空。

struct list_head

replq_elem

作爲鏈表元素可能被放在ReplQ或爲空

s_time_t

period

設定參數,vcpu的虛擬中斷觸發週期;

默認週期RTDS_DEFAULT_PERIOD爲10毫秒

s_time_t

budget

設定參數,vcpu作爲Xen中的任務,被調度時要設定的預算值,即允許持續執行的時間;

默認預算RTDS_DEFAULT_BUDGET爲4毫秒

s_time_t

cur_budget

運行時參數,vcpu剩餘預算值

s_time_t

last_start

運行時參數,vcpu開始執行時間

s_time_t

cur_deadline

運行時參數,vcpu的deadline

struct rt_dom

*rt_dom

NC

struct vcpu

*vcpu

指向所描述vcpu主體

unsigned

priority_level

vcpu的調度優先級

unsigned

flag

標誌位

RTDS_scheduled表示此vcpu是否正在pcpu上執行;

RTDS_delayed_runq_add表示此vcpu被調度暫停執行時,將會被加入Runq還是DeplQ;

RTDS_depleted表示此vcpu是否還有預算;

RTDS_extratime置位時,預算耗盡將會自動補充

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