linux內核調度算法(1)--快速找到最高優先級進程

爲何要了解內核的調度策略呢?呵呵,由於它值得咱們學習,不算是廢話吧。內核調度程序很先進很強大,管理你的LINUX上跑的大量的亂七八糟的進程,同時還保持着對用戶操做的高靈敏響應,若是可能,爲何不把這種思想放到本身的應用程序裏呢?或者,有沒有可能更好的實現本身的應用,使得操做系統可以以本身的意志來分配資源給本身的進程?算法



帶着這兩個問題來看看KERNEL。首先回顧上咱們開發應用程序,基本上就兩種類型,一、IO消耗型:好比hadoop上的trunk服務,很明顯它的消耗主要在IO上,包括網絡IO磁盤IO等等。二、CPU消耗型,好比mapreduce或者其餘的須要對大量數據進行計算處理的組件,就象對高清視頻壓縮成適合手機觀看分辨率的進程,他們的消耗主要在CPU上。當兩類進程都在一臺SERVER上運行時,操做系統會如何調度它們呢?如今的服務器都是SMP多核的,那麼一個進程在多CPU時會來回切換嗎?若是我有一個程序,既有IO消耗又有CPU消耗,怎麼讓多核更好的調度個人程序呢?


又多了幾個問題。來看看內核調度程序吧,咱們先從它的優先隊列談起吧。調度程序代碼就在內核源碼的kernel/sched.c的schedule函數中。
首先看下面的優先級隊列,每個runqueue都有。runqueue是什麼?下面會詳細說下,如今你們能夠理解爲,內核爲每一顆CPU分配了一個runqueue,用於維護這顆CPU能夠運行的進程。runqueue裏,有幾個成員是prio_array類型,這個東東就是優先隊列,先看看它的定義:服務器

 



看看BITMAP_SIZE是怎麼算出來的:#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
那麼,LINUX默認配置(若是你用默認選項編譯內核的話)MAX_PRIO是140,就是說一共內核對進程一共定義了140種優先級。等待某個CPU來處理的進程中,可能包含許多種優先級的進程,但,LINUX是個搶佔式調度算法的操做系統,就是說,須要調度時必定是找到最高優先級的進程執行。上面的BITMAP_SIZE值根據MAX_PRIO算出來爲5,那麼bitmap實際是32*5=160位,這樣就包含了MAX_PRIO的140位。優先級隊列是怎麼使用的?看2649行代碼:idx=sched_find_first_bit(array->bitmap);這個方法就用來快速的找到優先級最高的隊列。看看它的實現能夠方便咱們理解這個優先級位的設計:網絡

 


那麼__ffs是幹什麼的?函數

 


sched_find_first_bit返回值就是最高優先級所在隊列的序號,與queue是對應使用的哈,queue=array->queue + idx;這樣就取到了要處理的進程隊列。這個設計在查找優先級時是很是快的,很是值得咱們學習。


好,優先級隊列搞明白了,如今來看看runqueue,每一個runqueue包含三個優先級隊列。oop

 


LINUX是一個時間多路複用的系統,就是說,經過把CPU執行時間分紅許多片,再分配給進程們使用,形成即便單CPU系統,也貌似容許多個任務在同時執行。那麼,時間片大小假設爲100ms,太短過長,過長了有些不靈敏,太短了,連切換進程時可能都要消耗幾毫秒的時間。分給100個進程執行,在全部進程都用完本身的時間片後,須要從新給全部的進程從新分配時間片,怎麼分配呢?for循環遍歷全部的run狀態進程,重設時間片?這個性能沒法容忍!太慢了,跟當前系統進程數相關。那麼2.6內核怎麼作的呢?它用了上面提到的兩個優先級隊列active和expired,顧名思義,active是還有時間片的進程隊列,而expired是時間片耗盡必須從新分配時間片的進程隊列。


這麼設計的好處就是不用再循環一遍全部進程重設時間片了,看看調度函數是怎麼玩的:性能

 



當全部運行進程的時間片都用完時,就把active和expired隊列互換指針,沒有遍歷哦,而時間片耗盡的進程在出acitve隊列入expired隊列時,已經單獨的從新分配好新時間片了。


再看一下schedule(void)調度函數,當某個進程休眠或者被搶佔時,系統就開始調試schedule(void)決定接下來運行哪一個進程。上面說過的東東都在這個函數裏有體現哈。學習

 


固然,在咱們程序中,也能夠經過執行如下系統調用來改變本身進程的優先級。nice系統調用能夠改變某個進程的基本優先級,setpriority能夠改變一組進程的優先級。操作系統

相關文章
相關標籤/搜索