Linux 2.6 完全公平调度算法CFS(Completely Fair Scheduler)分析
轉(zhuǎn)會http://www.ibm.com/developerworks/cn/linux/l-completely-fair-scheduler/index.html?
ca=drs-cn-0125
Linux 調(diào)度器簡史
早期的 Linux 調(diào)度器使用了最低的設(shè)計,它顯然不關(guān)注具有非常多處理器的大型架構(gòu),更不用說是超線程了。1.2 Linux 調(diào)度器使用了環(huán)形隊列用于可執(zhí)行的任務(wù)管理。使用循環(huán)調(diào)度策略。 此調(diào)度器加入和刪除進(jìn)程效率非常高(具有保護(hù)結(jié)構(gòu)的鎖)。簡而言之,該調(diào)度器并不復(fù)雜可是簡單快捷。
Linux 版本號 2.2 引入了調(diào)度類的概念,同意針對實(shí)時任務(wù)、非搶占式任務(wù)、非實(shí)時任務(wù)的調(diào)度策略。 2.2 調(diào)度器還包含對稱多處理 (SMP) 支持。
2.4 內(nèi)核包括了相對簡單的調(diào)度器,按 O(N) 的時間間隔運(yùn)行(在調(diào)度事件期間它會迭代每一個任務(wù))。
2.4 調(diào)度器將時間切割成 epoch。每一個 epoch 中,每一個任務(wù)同意運(yùn)行到其時間切片用完。
假設(shè)某個任務(wù)沒有使用其全部的時間切片。那么 剩余時間切片的一半將被加入到新時間切片使其在下個 epoch 中能夠運(yùn)行更長時間。
調(diào)度器僅僅是迭代任務(wù)。應(yīng)用 goodness 函數(shù)(指標(biāo))決定以下運(yùn)行哪個任務(wù)。
雖然這樣的方法比較簡單,可是卻比較低效、缺乏可擴(kuò)展性并且不適合用在實(shí)時系統(tǒng)中。它還缺少利用新硬件架構(gòu)(比方多核處理器)的能力。
早期的 2.6 調(diào)度器,叫做 O(1) 調(diào)度器,它旨在解決 2.4 調(diào)度器存在的問題 — 該調(diào)度器不須要迭代整個任務(wù)列表來確定要調(diào)度的下一個任務(wù)(因此得名 O(1),這意味著它效率更高,擴(kuò)展性更好)。O(1) 調(diào)度器跟蹤執(zhí)行隊列中可執(zhí)行的任務(wù)(實(shí)際上,每一個優(yōu)先級水平有兩個執(zhí)行隊列 — 一個用于活動任務(wù)。一個用于過期任務(wù))。 這意味著要確定接下來執(zhí)行的任務(wù),調(diào)度器僅僅需按優(yōu)先級將下一個任務(wù)從特定活動的執(zhí)行隊列中取出就可以)。 O(1) 調(diào)度器擴(kuò)展性更好并且包括交互性,提供了大量啟發(fā)用于確定任務(wù)是受 I/O 限制還是受處理器限制。 可是 O(1) 調(diào)度器在內(nèi)核中非常笨拙。須要大量代碼計算啟發(fā)。難以管理而且對于純粹主義者而言未能體現(xiàn)算法的本質(zhì)。
為了解決 O(1) 調(diào)度器面臨的問題以及應(yīng)對其它外部壓力, 須要改變某些東西。這樣的改變來自 Con Kolivas 的內(nèi)核補(bǔ)丁。當(dāng)中包括他的 Rotating Staircase Deadline Scheduler (RSDL), 這包括了他在 staircase 調(diào)度器方面的早期工作。這些工作的成果就是一個設(shè)計簡單的調(diào)度器,包括了公平性和界限內(nèi)延遲。
Kolivas 的調(diào)度器吸引了非常多人(而且非常多人呼吁將其包括在眼下的 2.6.21 主流內(nèi)核中),非常顯然調(diào)度器的變革即將發(fā)生。 Ingo Molnar,O(1) 調(diào)度器的創(chuàng)造者,然后環(huán)繞 Kolivas 的一些思想開發(fā)了基于 CFS 的調(diào)度器。我們來剖析一下 CFS。從較高的層次上看看它是怎樣執(zhí)行的。
------------------------------------------------------------------------------------------------------------------------------
CFS 概述
CFS 背后的主要想法是維護(hù)為任務(wù)提供處理器時間方面的平衡(公平性)。這意味著應(yīng)給進(jìn)程分配相當(dāng)數(shù)量的處理器。
分給某個任務(wù)的時間失去平衡時(意味著一個或多個任務(wù)相對于其它任務(wù)而言未被給予相當(dāng)數(shù)量的時間)。應(yīng)給失去平衡的任務(wù)分配時間,讓其運(yùn)行。
要實(shí)現(xiàn)平衡,CFS 在叫做虛擬執(zhí)行時?的地方維持提供給某個任務(wù)的時間量。任務(wù)的虛擬執(zhí)行時越小。 意味著任務(wù)被同意訪問server的時間越短 — 其對處理器的需求越高。
CFS 還包括睡眠公平概念以便確保那些眼下沒有執(zhí)行的 任務(wù)(比如。等待 I/O)在其終于須要時獲得相當(dāng)份額的處理器。
可是與之前的 Linux 調(diào)度器不同,它沒有將任務(wù)維護(hù)在執(zhí)行隊列中,CFS 維護(hù)了一個以時間為順序的紅黑樹(參見圖 1)。
?紅黑樹?是一個樹,具有非常多有趣、實(shí)用的屬性。首先,它是自平衡的,這意味著樹上沒有路徑比不論什么其它路徑長兩倍以上。
第二,樹上的執(zhí)行按 O(log?n) 時間發(fā)生(當(dāng)中?n?是樹中節(jié)點(diǎn)的數(shù)量)。這意味著您能夠高速高效地插入或刪除任務(wù)。
圖 1. 紅黑樹演示樣例
任務(wù)存儲在以時間為順序的紅黑樹中(由?sched_entity?對象表示),對處理器需求最多的任務(wù) (最低虛擬執(zhí)行時)存儲在樹的左側(cè),處理器需求最少的任務(wù)(最高虛擬執(zhí)行時)存儲在樹的右側(cè)。 為了公平。調(diào)度器然后選取紅黑樹最左端的節(jié)點(diǎn)調(diào)度為下一個以便保持公平性。
任務(wù)通過將其執(zhí)行時間加入到虛擬執(zhí)行時, 說明其占用 CPU 的時間,然后假設(shè)可執(zhí)行。再插回到樹中。這樣,樹左側(cè)的任務(wù)就被給予時間執(zhí)行了,樹的內(nèi)容從右側(cè)遷移到左側(cè)以保持公平。
因此,每一個可執(zhí)行的任務(wù)都會追趕其它任務(wù)以維持整個可執(zhí)行任務(wù)集合的執(zhí)行平衡。
------------------------------------------------------------------------------------------------------------------------------
CFS 內(nèi)部原理
Linux 內(nèi)的全部任務(wù)都由稱為?task_struct?的任務(wù)結(jié)構(gòu)表示。該結(jié)構(gòu)(以及其它相關(guān)內(nèi)容)完整地描寫敘述了任務(wù)并包含了任務(wù)的當(dāng)前狀態(tài)、其堆棧、進(jìn)程標(biāo)識、優(yōu)先級(靜態(tài)和動態(tài))等等。
您能夠在 ./linux/include/linux/sched.h 中找到這些內(nèi)容以及相關(guān)結(jié)構(gòu)。 可是由于不是全部任務(wù)都是可執(zhí)行的。您在?task_struct?中不會發(fā)現(xiàn)不論什么與 CFS 相關(guān)的字段。 相反,會創(chuàng)建一個名為?sched_entity?的新結(jié)構(gòu)來跟蹤調(diào)度信息(參見圖 2)。
圖 2. 任務(wù)和紅黑樹的結(jié)構(gòu)層次
各種結(jié)構(gòu)的關(guān)系如?圖 2?所看到的。
樹的根通過?rb_root?元素通過?cfs_rq?結(jié)構(gòu)(在 ./kernel/sched.c 中)引用。紅黑樹的葉子不包括信息。可是內(nèi)部節(jié)點(diǎn)代表一個或多個可執(zhí)行的任務(wù)。
紅黑樹的每一個節(jié)點(diǎn)都由?rb_node?表示,它僅僅包括子引用和父對象的顏色。
?rb_node?包括在sched_entity?結(jié)構(gòu)中,該結(jié)構(gòu)包括?rb_node?引用、負(fù)載權(quán)重以及各種統(tǒng)計數(shù)據(jù)。最重要的是,?sched_entity?包括?vruntime(64 位字段),它表示任務(wù)執(zhí)行的時間量,并作為紅黑樹的索引。 最后,task_struct?位于頂端,它完整地描寫敘述任務(wù)并包括?sched_entity?結(jié)構(gòu)。
就 CFS 部分而言,調(diào)度函數(shù)很easy。 在 ./kernel/sched.c 中。您會看到通用?schedule()?函數(shù),它會先搶占當(dāng)前執(zhí)行任務(wù)(除非它通過yield()?代碼先搶占自己)。注意 CFS 沒有真正的時間切片概念用于搶占,由于搶占時間是可變的。
當(dāng)前執(zhí)行任務(wù)(如今被搶占的任務(wù))通過對?put_prev_task?調(diào)用(通過調(diào)度類)返回到紅黑樹。 當(dāng)?schedule?函數(shù)開始確定下一個要調(diào)度的任務(wù)時,它會調(diào)用?pick_next_task函數(shù)。此函數(shù)也是通用的(在 ./kernel/sched.c 中)。但它會通過調(diào)度器類調(diào)用 CFS 調(diào)度器。 CFS 中的?pick_next_task?函數(shù)能夠在 ./kernel/sched_fair.c(稱為?pick_next_task_fair())中找到。 此函數(shù)僅僅是從紅黑樹中獲取最左端的任務(wù)并返回相關(guān)?sched_entity。通過此引用,一個簡單的?task_of()?調(diào)用確定返回的?task_struct?引用。通用調(diào)度器最后為此任務(wù)提供處理器。
------------------------------------------------------------------------------------------------------------------------------
優(yōu)先級和 CFS
CFS 不直接使用優(yōu)先級而是將其用作同意任務(wù)運(yùn)行的時間的衰減系數(shù)。
低優(yōu)先級任務(wù)具有更高的衰減系數(shù)。而高優(yōu)先級任務(wù)具有較低的衰減系數(shù)。
這意味著與高優(yōu)先級任務(wù)相比,低優(yōu)先級任務(wù)同意任務(wù)運(yùn)行的時間消耗得更快。 這是一個絕妙的解決方式,能夠避免維護(hù)按優(yōu)先級調(diào)度的運(yùn)行隊列。
CFS 組調(diào)度
CFS 還有一個有趣的地方是組調(diào)度?概念(在 2.6.24 內(nèi)核中引入)。組調(diào)度是還有一種為調(diào)度帶來公平性的方式,尤其是在處理產(chǎn)生非常多其它任務(wù)的任務(wù)時。 如果一個產(chǎn)生了非常多任務(wù)的server要并行化進(jìn)入的連接(HTTP server的典型架構(gòu))。不是全部任務(wù)都會被統(tǒng)一公平對待, CFS 引入了組來處理這樣的行為。產(chǎn)生任務(wù)的server進(jìn)程在整個組中(在一個層次結(jié)構(gòu)中)共享它們的虛擬執(zhí)行時,而單個任務(wù)維持其自己獨(dú)立的虛擬執(zhí)行時。這樣單個任務(wù)會收到與組大致同樣的調(diào)度時間。
您會發(fā)現(xiàn) /proc 接口用于管理進(jìn)程層次結(jié)構(gòu),讓您對組的形成方式有全然的控制。使用此配置。您能夠跨用戶、跨進(jìn)程或其變體分配公平性。
調(diào)度類和域
與 CFS 一起引入的是調(diào)度類概念(能夠回想?圖 2)。每一個任務(wù)都屬于一個調(diào)度類,這決定了任務(wù)將怎樣調(diào)度。 調(diào)度類定義一個通用函數(shù)集(通過?sched_class),函數(shù)集定義調(diào)度器的行為。
比如,每一個調(diào)度器提供一種方式, 增加要調(diào)度的任務(wù)、調(diào)出要執(zhí)行的下一個任務(wù)、提供給調(diào)度器等等。
每一個調(diào)度器類都在一對一連接的列表中彼此相連,使類能夠迭代(比如。 要啟用給定處理器的禁用)。一般結(jié)構(gòu)如圖 3 所看到的。注意,將任務(wù)函數(shù)增加隊列或脫離隊列僅僅需從特定調(diào)度結(jié)構(gòu)中增加或移除任務(wù)。 函數(shù)?pick_next_task?選擇要執(zhí)行的下一個任務(wù)(取決于調(diào)度類的詳細(xì)策略)。
圖 3. 調(diào)度類圖形視圖
可是不要忘了調(diào)度類是任務(wù)結(jié)構(gòu)本身的一部分(參見?圖 2)。這一點(diǎn)簡化了任務(wù)的操作,不管其調(diào)度類怎樣。比如, 下面函數(shù)用 ./kernel/sched.c 中的新任務(wù)搶占當(dāng)前執(zhí)行任務(wù)(當(dāng)中?curr?定義了當(dāng)前執(zhí)行任務(wù)。?rq?代表 CFS 紅黑樹而?p?是下一個要調(diào)度的任務(wù)):
static inline void check_preempt( struct rq *rq, struct task_struct *p ) {rq->curr->sched_class->check_preempt_curr( rq, p ); }假設(shè)此任務(wù)正使用公平調(diào)度類,則?check_preempt_curr()?將解析為?check_preempt_wakeup()。
您能夠在 ./kernel/sched_rt.c, ./kernel/sched_fair.c 和 ./kernel/sched_idle.c 中查看這些關(guān)系。
調(diào)度類是調(diào)度發(fā)生變化的還有一個有趣的地方,可是隨著調(diào)度域的添加。功能也在添加。 這些域同意您出于負(fù)載平衡和隔離的目的將一個或多個處理器按層次關(guān)系分組。 一個或多個處理器可以共享調(diào)度策略(并在其之間保持負(fù)載平衡)或?qū)崿F(xiàn)獨(dú)立的調(diào)度策略從而有益隔離任務(wù)。
其它調(diào)度器
繼續(xù)研究調(diào)度,您將發(fā)現(xiàn)正在開發(fā)中的調(diào)度器將會突破性能和擴(kuò)展性的界限。Con Kolivas 沒有被他的 Linux 經(jīng)驗羈絆。他開發(fā)出了還有一個 Linux 調(diào)度器。其縮寫為:BFS。
該調(diào)度器據(jù)說在 NUMA 系統(tǒng)以及移動設(shè)備上具有更好的性能。 而且被引入了 Android 操作系統(tǒng)的一款衍生產(chǎn)品中。
版權(quán)聲明:本文博客原創(chuàng)文章。博客,未經(jīng)同意,不得轉(zhuǎn)載。
轉(zhuǎn)載于:https://www.cnblogs.com/mfrbuaa/p/4641240.html
總結(jié)
以上是生活随笔為你收集整理的Linux 2.6 完全公平调度算法CFS(Completely Fair Scheduler)分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 生成排列、组合以及选择
- 下一篇: java Split 用法