上次主要講了
cfs排程的基本原理,並且沒有分析有喚醒和程序遷移時候的排程流程,所以本文主要 從核心中幾個重要的排程點來詳細的分析一下排程的基本流程,主要以流程圖的形式給出。
核心中主要有以下幾個重要的切入點
:(1)tick
相關,即時鐘中斷
這就是上篇文章中講的每次中斷中,更 新
vruntime
的整個過程,可以理解為是在中斷的上半部分做的,很顯然我們會想到前一篇文章中 講到的檢查
tif_need_sched
位並顯示呼叫
schedule()
的地方就是中斷的下半部分了,為了更好的理解我把中斷的整個處理流程也做了個流程圖
(以時鐘中斷為例):
) 與中斷相關的部分,我會在以後的文章裡詳細介紹,在這裡就不具體接講解了。
現在來總結一下這個切入點的整個過程:
當來乙個時鐘中斷的時候,概括來說核心做了兩個操作
(參見上圖中):
(1)do_timer():
它主要來更新系統的時間
(2)update_progress_times():
一方面去執行我們上面談到的
scheduler_tick()
,另一方面他又去觸發乙個軟中斷
執行完上面幾個步驟後,時鐘中斷就要返回了,因為其他的任務留給軟中斷做了。具體怎麼做我會在中斷一部分在分析。我們來看看中斷返回時的一段 **:
call do_irq
jmp ret_from_intr #
執行完do_irq
後跳到ret_from_intr
ret_from_intr:
..............
cmpl $user_rpl, %eax
#判斷返回使用者態還是核心態
jb resume_kernel # not returning to v8086 or userspace
entry(resume_userspace)
..............
jne work_pending
jmp restore_all
entry(resume_kernel)
..........
need_resched:
movl ti_flags(%ebp), %ecx # need_resched set ?
testb $_tif_need_resched, %cl #檢查
tif_need_sched
有沒有被置位
jz restore_all
testl $x86_eflags_if,pt_eflags(%esp) # interrupts off (exception path) ?
jz restore_all
call preempt_schedule_irq
#在這裡顯示呼叫 了
schedule()
jmp need_resched
到這裡我們已經跟蹤了在時鐘中斷裡面的乙個完整的排程過程。
(2)當前程序主動放棄
cpu
既然是主動放棄,直接主動呼叫
schedule()
就行了,核心裡面的很多地方都是這麼做的,只要搜一下
schedule
的呼叫點就會看到。下面是從
schedule()
開始的乙個呼叫
流程圖:
總結一下執行的流程:
(1)清除tif_need_sched
(2)判斷一下當前程序應該被繼續設定為
task_running
狀態,如果不是的話就把它從執行佇列中刪除
(3)看一下當前執行佇列是否還有可執行進 程,沒有的話,呼叫
idle_balance(cpu, rq)
平衡負載
(4)把當前程序放回執行佇列,並設定當前 程序的指標為空。
(5)選擇下乙個程序作為當前程序
(6)判斷如果當前程序不等於選擇的程序的 話,就進行程序切換,執行swtich_to,這部分將在下次講解。
先說這麼多,因為有很多細節我也不怎麼理解,下面提出幾個問題,希望能和大家一塊討論:
(1)schedule()函式中的這段**及其展開
if (prev->state && !(preempt_count() & preempt_active)){
/*prev->state >0 即當前程序處在stopped狀態下,而且可搶占的情況下*/
if (unlikely(signal_pending_state(prev->state, prev)))
prev->state = task_running;/**/
else
deactivate_task(rq, prev, 1) ;/*從紅黑樹中刪除prev*/
switch_count = &prev->nvcsw;
這部分的意思是如果當前程序還需要呆在執行佇列中就設定其prev->state = task_running,否則把它從
紅黑樹中刪除。
問題一:繼續留在執行佇列的那個判斷條件具體是什麼意思?
if (unlikely(signal_pending_state(prev->state, prev)))
猜測應該 是,task_interruptible這種狀態時,可隨時接受訊號來繼續執行。
問題二: 如果不留在執行佇列就要從紅黑樹種刪除,跟蹤刪除函式最後到了dequeue_entity()的這段**
/*清除夥伴*/
clear_buddies(cfs_rq, se);
/*大部分情況下二者是相等的,不執行,
因為當前程序一直就不在執行佇列中
問題的關鍵是什麼情況下執行呢?*/
if (se != cfs_rq->curr)
__dequeue_entity(cfs_rq, se);
這個判斷條件是什麼意思?se不就是當前程序嗎?什麼情況下這個判斷條件才能成立,最好能有個具體的例子。
我是這麼想的,大部分情況下se = cfs_rq->curr,那麼出隊操作就不執行,因為當前程序是不在執行佇列中的,這一點可以從新選擇乙個程序來執行的時候要先把它出列得到印 證,具體可見pick_next_task().
Linux程序排程之CFS
在linux2.6核心中,開發人員引入了一種新的排程策略,旨在解決2.5及之前的排程器在處理使用者互動式程式時延遲大的不足。這種排程器就是completely fair scheduler 簡稱cfs 排程器的任務就是從當前系統中的就緒任務中選擇合適的任務執行。排程器需要確定在什麼時候排程什麼任務,...
linux排程器(四) 主排程器與CFS
當核心從系統呼叫返回,或者從中斷處理程式返回,核心都會檢查當前程序是否設定了tif need resched標誌 或者程序主動放棄cpu時 sched yield,sleep或者收到sigstop,sigttop訊號 都會進入主排程器。同樣的我們先看一下主排程的框架部分,該部分就是sched.c s...
linux核心分析之排程演算法 CFS排程分析
前面對linux排程演算法的框架進行了介紹,在這裡對cfs 完全公平排程 演算法進行分析。cfs允許每個程序執行一段時間 迴圈輪轉 選擇執行最少的程序作為下乙個執行程序,而不再採用分配給每個程序時間片的做法了,cfs在所有可執行程序總數基礎上計算出乙個程序應該執行多久,而不是依靠nice值來計算時間...