linux搶佔式排程

碼農sjkj發表於2019-05-19
為什麼會發生排程?
 
因為cpu是有限的,而作業系統上的程式很多,所以作業系統需要平衡各個程式的執行時間
比如說有的程式執行時間已經很長了,已經佔用了cpu很長時間了,這個時候作業系統要公平
就會換下一個需要執行的程式。
 
舉個例子
 
公司只有一個飲水機用來接水,有很多人排隊,某個人接完了一杯水,又接下一杯水,一連線了好多杯水,這個時候公司的人事就要過來把這個人趕走
換下一個人接水,然而這個時候老闆過來接水了,這個時候下一個人就是老闆來接水,而不是後面排隊的人,因為什麼呢?因為他是老闆,就這麼強悍
 
這裡面的飲水機就是cpu
人事就是作業系統
等接水的一個個員工就是程式
 
老闆就對應作業系統裡的實時程式
普通員工就對應作業系統的普通程式
 
在作業系統裡面實時程式的優先順序比普通程式的優先順序要高,
所以作業系統在選擇下個程式的時候會優先選擇實時程式佇列裡面的程式
除非實時程式裡面的程式沒有了,這個時候才輪到普通程式
 
 
作業系統就像人事一樣,需要公平的排程和分配資源,當然公司裡面有很多老闆啊,總經理啊,領導啊
這些人擁有特權,所有分配資源的時候要優先考慮這些老闆領導們,這也很正常,誰讓人家是老闆呢
 
 
 
下面來說說搶佔式排程
 
什麼情況下會發生搶佔式排程呢?
最常見的現象是你這個程式執行時間太長了,是時候切換到另一個程式了
 
然而作業系統怎麼去統計執行時間呢?
 
計算機有個時鐘的概念,每過一段時間,計算機會通知作業系統,告訴作業系統,又過去了一段時間,你去看看,當前執行的程式執行時間是不是過長了,這個時候作業系統就會去搞這個程式了。
 
在作業系統中對於每個程式有一個理想執行時間的變數,然後對應還有一個虛擬執行時間和實際執行時間和權重(優先順序)。
 
這三者有什麼關係呢?
 
虛擬執行時間 vruntime += 實際執行時間 delta_exec * NICE_0_LOAD/ 權重(優先順序)
 
通過這個公式可以看出來,給高優先順序的程式的虛擬執行時間算少了,給低優先順序的程式的虛擬執行時間算多了,但是當作業系統選擇下一個程式的時候還是選擇虛擬執行時間最少的程式,所以說優先順序在這裡面就體現出來了。
 
當某個程式在執行的時候,這個程式的虛擬執行時間會增加,當程式不執行的時候,虛擬時間不增加
其實這裡又會涉及到排程器的概念。
 
這裡我們就只說針對普通程式的絕對公平排程策略
 
這種策略在選取下個程式的時候,是怎麼選取的呢?
他是選取當前所有普通程式中執行時間最少的程式,這個應該很好理解吧,因為你在cpu上佔用的時間最少,所以為了公平,就要選取你這個程式在cpu上執行。
 
在作業系統中維護了一個紅黑樹,紅黑樹就是一顆平衡二叉樹,也就是說紅黑樹上面掛了好多程式,最左邊的程式就是執行時間最少的程式,所有作業系統在,選取下一個程式就會選取這個紅黑樹上最左側的程式。
 
static void
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
unsigned long ideal_runtime, delta_exec;
struct sched_entity *se;
s64 delta;
 
 
ideal_runtime = sched_slice(cfs_rq, curr);
delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
if (delta_exec > ideal_runtime) {
resched_curr(rq_of(cfs_rq));
return;
}
......
se = __pick_first_entity(cfs_rq);
delta = curr->vruntime - se->vruntime;
if (delta < 0)
return;
if (delta > ideal_runtime)
resched_curr(rq_of(cfs_rq));
}
 
上面程式碼是Linux原始碼
 
在作業系統中還有個時間的概念,就是在一個排程週期中,這個程式應該執行的實際時間(ideal_runtime)
sum_exec_runtime指程式總共執行的實際時間, prev_sum_exec_runtime指上次該程式被排程時已經佔用的實際時間。
 
每次在排程一個新的程式時都會把它的se->prev_sum_exec_runtime=se->sum_exec_runtime,所以sum_exec_runtime-prev_sum_exec_runtime
就是這次排程佔用實際時間。如果這個時間大於ideal_runtime,則應該被搶佔了。
 
除了這個條件外,還會通過_pick_first_entity取出紅黑樹中最小的程式。如果當前程式的vruntime(虛擬執行時間)大於紅黑樹中最小的程式的vruntime,且差值大於ideal_time,也應該
被搶佔了
 
當發現這個程式應該被搶佔了,不能直接把他踢下去,而是在這個程式上打一個標籤TIF_NEED_RESCHED,標示這個程式可以被搶佔了
 
還有一個可能發生搶佔的場景,就是當一個休眠的程式被喚醒的時候
這個時候如果這個被喚醒的程式比當前執行的程式的優先順序高,則也應該被搶佔了,也是在當前執行的程式上打一個標籤TIF_NEED_RESCHED
 
搶佔的時機
 
1.使用者態的搶佔時機
當該程式進行系統呼叫從核心態返回到使用者態的時候,判斷如果該程式有TIF_NEED_RESCHED標籤,則進行搶佔。
 
2.核心態的搶佔時機
對核心態的執行中,被搶佔的時機一般發生在preempt_enable()中。
preempt_disable()關閉搶佔
在核心態的執行中,有的操作是不能被中斷的,所有在進行這些操作之前,總是先呼叫preempt_disable()關閉搶佔,當再次開啟的時候,也就是呼叫preempt_enable()的時候
就是一次核心態程式碼被搶佔的機會。
 
在核心態也會遇到中斷的情況,當中斷返回的時候,返回的仍然是核心態度。這個時候也是一個執行搶佔的時機。
 
大家可以看看這張圖理解

相關文章