Mr. Process的一生-Linux內核的社會視角 (1)調度

偶遇奇文!

轉載地址:http://www.manio.org/cn/scheduling-of-linux-view-of-society/

Written by manio (manioster{at)gmail.com)


Linux內核是一個無比複雜的系統,要想看清大致的脈絡也非易事。其實,可以把運行中的Linux想像成一個人類的社會,當中的進程就是社會中的人。人有生老病死,進程有創建、異常、終止。人有各種各樣的財產,進程有對應的地址空間、設備等等。人被各種各樣的東西限制着,被人管着,進程也是。內核無比巨大,從哪着手?我想,從進程的視角來看是個好辦法。並且,在學習Linux內核的同時,類比人類社會來看,會有更深刻的印象,理解得更透徹。

本來也應該從進程的創建開始寫的,但是最近在看調度的相關論文,就又把Linux調度的東西看了一下。所以,就先寫調度相關的東西吧。

首先介紹與進程所在環境對應的人類場景:

這是一個公司,公司裏有很多人(進程),每個人都有其對應的職稱(優先級)。這個公司很奇怪,只有一張辦公桌(CPU),在任意時刻,只能有一個人在工作(TASK_RUNNING正在運行狀態)。其他人呢,要麼在休息室時短暫地休息(對應TASK_RUNNING就緒狀態),要麼就在寢室Sleep(對應TASK_INTERRUPTABLE或TASK_UNINTERRUPTABLE),要麼就是死人了,在停屍間(TASK_ZOMBIE)。是的,這是真的,這個公司就是個血汗工廠,幹活累死了,就直接丟進停屍間,慘絕人寰!

以下是此公司的平面圖:

圖解:“推門”是單向的:比如連接工作室和太平間的是推門,職員只能從工作室走到太平間,不能從太平間走到工作室(這太嚇人了)。“凹槽門”是雙向的:比如連接工作室和休息室的門是凹槽門,職員可以走來走去。

時間片(time slice):這個公司的工資特別高,按工作的小時數計算。工作者得錢,不工作者不得錢。所以,所有的人都特想去辦公桌那裏工作,爭着搶着要去。爲了讓大家都有機會去工作(避免有的人沒錢拿,餓死,i.e. starve to death),所以公司出了條規定,每個人每次工作的時間不能超過公司分給自己的時間片(time slice)。時間片的大小由此人的職稱決定。

職稱(也就是內核中的priority):職稱有兩種,一種是靜態職稱(static priority),一種是動態職稱(dynamic priority)。靜態職稱是先天的,由此人的老爸決定(富二代有先天優勢!)。動態優先級是看在公司裏的工作表現的。職稱是很重要的東西,職稱越高,你到辦公桌上賺錢的機會越大。

默認時間片長點好還是短點好?

自然是不長不短好(世界上的事情都是這樣)。如果太短了,比如說某職員時間片是1分鐘(對應的Linux裏的時間片應該差不多是0.1ms吧,可能還得少點),這個人在辦公桌前屁股沒坐熱就要走了,從起身到回到休息室,再到下一個人起身走到辦公桌前坐下,這也得要一分鐘。如果這樣的話,這公司將有一半的時間花在走路上。這樣搞是不行的,在資本主義社會,大家都要努力搞高生產率。

那是不是時間片長了就好?也不是。比如時間片是一個小時,當兩個客戶(對應Linux中的兩個用戶)同時要和此公司展開業務(對應Linux中的啓動進程),有兩個職員會分別處理這兩個業務。A職員一上去就佔着辦公室一個小時,B職員在這一個小時結束前沒法子處理他的客戶的業務,所以B職員的客戶就得在寒風中等一個小時!資本主義社會裏的公司是不能讓他們的財神爺不高興的。所以,還是不長不短的好。

回到真實的Linux內核中:很多人認爲時間片過長會導致程序的響應(比如字處理程序的I/O響應)變慢,因爲要等時間片用完才能處理。其實不然,字處理程序等交互性強的程序,他們的優先級高,可以搶佔當前正在運行的進程,從而得到執行。在公司裏,就比如B職員的職稱高,他可以把A職員從辦公桌上踢走。事實上,從後面對動態優先級的討論我們可以看到,要是A職員一直霸佔着辦公桌不走,他/她的動態職稱會變低的,結果是,在休息室裏的其他職員的職稱就自然而然地可能比A高了。

職員目錄(Process list):公司有個目錄,在這個目錄中,列出了所有公司的職員。這對應Linux裏的Process List,裏面存有所有進程的信息。

下面以Mr. P的經歷爲例說明

Personal History Statement of Mr. Process (Mr. P in short)

出生

這是世界上最怪異的公司,職員都是單性的,都是男的。並且不要交配,自己調用系統調用fork(),就可以生了。生出來的小孩子也都是男的。

在這裏爲了問題的簡化,就只討論與調度的關係比較緊密的內容。

圖:詳細的公司平面圖

如上圖所示,在休息室裏其實還有兩個沙發。一個沙發叫做活動隊列(往後我們叫它活動沙發吧),一個沙發叫做過期隊列(往後我們叫它過期沙發)。坐在活動沙發上的職員都還有時間片沒有用完,坐在過期沙發上的職員的時間片剛剛被用完了(但他們手上都拿着新分配到的時間片,這個是2.5版內核新引入的O(1)調度,後面再講)。

Mr. P的父親在辦公桌旁邊工作的時候,突然fork()了一下,就生出了Mr.P。一出生,Mr. P就擁有和父親一樣的靜態職稱(static priority)。他一出生就坐在了活動沙發上,拿走了父親一半的時間片。比如生MR. P之前,MR. P的父親有10ms的時間片,MR.P出生後,他父親有5ms,Mr. P有5ms。這樣的機制是爲了防止有人以生子來搶奪時間片:試想,有一人,自己有10ms的時間片,他一直生啊生,生了100個孩子,那麼這個程序就有了10+10*100ms的時間片了。然後他的孩子斷續生啊生,那麼有可能系統中絕大部分的時間片都是他家的了,那他的街坊鄰居還要不要活啊,沒時間片等於不能做事,等於沒工資,等於沒食物,等於餓死。

另外,不幸的是,即使是在發達的資本主義社會,孩子也是有可能夭折的(由於各種原因,在第一次到辦公桌上工作之前就死掉了)。在這種情況下,公司會把孩子沒用的時間片還給他父親。多麼人性化的公司…

開始工作

像其他所有孩子一樣,Mr. P一生下來就工作了,他坐在活動沙發上等着做事。他人事部的同事Miss Schedule (以下簡稱Miss S)會在每個tick(內核的時間單位,時間很短)結束時檢查一下以下兩種情況有沒有發生:

  1. 在辦公桌前工作的那個職員是不是已經用完自己的時間片了。
  2. 是不是有更高動態職稱(dynamic priority)的職員在活動沙發上等着。

其中一種情況成立,這個在辦公桌前工作的那個職員就要被趕出來,換在活動沙發上坐着的動態職稱最高的職員進去工作。

假設經過一段時間後,沒有人的動態職稱比Mr. P高了。在一個時間tick結束時,Miss S到休息室檢查大家當前的職稱。他能輕鬆地找到動態職稱最高的職員(sched_find_first),因爲職員們都是按動態職稱來坐的(在活動沙發上),動態職稱相同的職員坐在一起(參考struct prio_array)。Miss S只要按順序找下去,第一個在沙發上找到的職員就是職稱最高的。當Miss S用上面的方法發現Mr. P當前的動態職稱是最高的時,在辦公桌前工作的是職員C,Miss S把C從辦公桌前拉到休息室。如果此時C的時間片已經用完了,他就會被安排坐在過期沙發上(這也就是expired的含義);如果此時C的時間片沒有用完,他就會被安排坐在活動沙發上。C被拉到休息室時,他的工作用具,筆啊紙啊什麼的,都要從辦公桌上拿走(這是關於進程上下文切換的問題)。C走了之後,Mr. P帶着他的東西到辦公桌前坐下,整理好辦工用品(進程上下文切換)。好的,Mr. P可以開始工作了。

評定動態職稱

公司裏的兩類人:

交際花(I/O消耗型進程):這類人常常與外部的客戶打交道,而客戶的反應總是不怎麼快。所以,交際花常常要等客戶做出反應。公司爲了不讓交際花在等客戶反應的時候也佔用着辦公桌,所以,當交際花要等待客戶的響應時,他就會被移到寢室去睡覺(Sleep)。

工作狂(處理器消耗型):這類人就是傳說中的苦幹王,很少和外界打交道,就知道在辦工桌上做事。這種工作狂給公司造成一些困擾,如果他們老佔着辦公桌,交際花就沒法做事了。要知道,一個公司還是需要人去跑跑業務的。

公司有一套機制,這一套機制能很好的區分這兩類人,並且給他們評定職稱。判斷的標準就是他們的平均睡眠時間(average sleep time)。睡眠時間包括在寢室裏的時間(TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE)和在休息室時等待的時間。但平均睡眠時間的計算並不是加和再求平均那麼簡單。在TASK_INT和TASK_UNINT兩種狀態下,平均睡眠時間的增長情況是不一樣的。在運行的時間,平均睡眠時間是在減少的。具體的平均睡眠時間的算法在recalc_task_prio()中。

當一個職員常常睡覺,公司就知道這人是交際花了,因爲他常常因爲等客戶的響應而睡覺。當一個職員很少睡覺,公司就知道這人是個工作狂了,因爲他很少因爲等客戶的響應而睡覺。

現在我們回來討論Mr. P,假設Mr. P在工作的時候要等待一個客戶給數據給他(比如說鍵盤數據),他就把自己的加入一個等待隊列裏,將自己設爲TASK_INT,這樣他就進入了寢室裏。Mr. P在那裏苦苦地等待他要的數據到來。終於,客戶敲下了鍵盤,給出了數據。然後鍵盤事件的管理者調用wake_up()函數,將Mr. P喚醒。如果Mr. P的動態職稱高於當前正在工作的職員的動態職稱,那麼Mr. P就會搶掉這個職員的辦公桌。如果不高於的話,Mr. P就只是先到休息室裏坐着。我們假設Mr. P的動態職稱很高,所以,現在Mr. P又搶到了辦公桌。

O(1)調度

又過了一段時間,Mr. P的時間片用完了,該離開了。這時他該被Miss S帶到過期沙發上了,在從辦公桌走到過期沙發的路上,Miss S會幫他重新算時間片(依照動態職稱來決定時間片的長短)。事實上,每個職員被帶到過期沙發上坐着的時候,Miss S都會幫他算好時間片。這樣,過期沙發上的所有職員手中都拿着時間片。這樣做的好處是,當活動沙發空了的時間,只要把活動沙發和過期沙發上貼着的“活動沙發”和“過期沙發”的標籤互換一下,原來的過期沙發就變成了活動沙發,原來的活動沙發就變成了過期沙發。這樣,Miss S就又可以從活動沙發上叫人去工作了。而這個“互換標籤”的動作的時間複雜度是O(1)。這就是2.5版內核所引入的O(1)調度。

試想一下沒有這個O(1)調試之前是什麼情況:每次所有進程的時間片都用完時,要重新計算所有TASK_RUNNING狀態的進程的時間片。當一個系統中只有幾個進程的情況還好,但是對於有成千上萬個進程的大型系統,這是相關耗時的。

對交際花的優惠政策

在一個公司來說,交際花是非常重要的,他們的表現直接關係到客戶的滿意度和公司的形象。所以,Linux公司有一些專門針對交際花的優惠政策。

假設Mr. P就是一個十足的交際花:上班打扮得花枝招展(雖然是個男的),見人說人話見鬼說鬼話,關鍵是,他有一些客戶特別愛和他把交道。當Mr. P用完一個時間片的時候,照常理,他是應該被Miss S帶到過期沙發上去等待下一次工作的。但這樣的等待有可能太久了-要等到所有活動沙發上的職員都用完時間片。所以,Miss S爲了客戶的滿意度(如果等太久,客戶是不滿意的),就在重新計算Mr. P的時間片之後,讓他留在了活動沙發上。這樣,Mr. P就能更快地處理客戶的IO事件。

這看起來是對交際花的特權,其實這是爲了公司的長遠利益着想。如果客戶的需求得不到及時的滿足,客戶不滿意,就不會有人用這公司的產品了,即使工作狂們的工作做得很好。

公司裏的超級特權階級-小霸王(real-time process)

交際花是有一些特權,但權利再大也大不過小霸王。公司有時會有一些時間很緊的項目要做,這些項目有deadline。爲了能完成這些重要的項目,公司裏發展了一種特權階級,就是小霸王。他們的職稱高於其他所有普通員工,除非他們完成了自己的工作,否則其他職工不能去工作。

這些小霸王的工作方式有兩種:

FIFO(First In First Out):當一個小霸王完成自己工作的時間,其他小霸王才能去工作。但是當有職稱更高的小霸王到來時,職稱更高的小霸王能搶佔當前的小霸王的辦公桌。

RR(Route Robin):相同優先級的小霸王轉着用辦公桌,每人用一段時間。

總結:

在這篇文章裏,以Mr. P的工作經歷來說明了Linux調度的一些比較重要的機制。介紹了IO消耗型進程和處理器消耗型的進程,O(1)調度等等。這些是比較大的方面,當大的方面理解了之後,那些世界頂尖高手寫的源碼也就更容易看懂一些了。

發佈了37 篇原創文章 · 獲贊 23 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章