空閑時CPU做什麼?

原文:manybutfinite.com/post/

翻譯:RobotCode俱樂部

在上一篇文章中,我說過操作系統行為的基本原理是,在任何給定的時間,CPU上只有一個任務是活動的。但如果真的沒什麼可做的,那該怎麼辦?

事實證明,這種情況非常普遍,對於大多數個人電腦來說,這實際上是一種常態:大量的睡眠進程,都在等待某種條件下醒來,而幾乎100%的CPU時間都投入到了虛構的「空閑任務」中。事實上,對於普通用戶來說,如果CPU一直處於繁忙狀態,那麼這通常是一個錯誤配置、bug或惡意軟體。

由於我們不能違背我們的公理---一些任務始終需要在CPU上活動。首先,因為它是好的設計:將特殊情況分散到內核中檢查是否存在活動任務是不明智的。如果沒有例外,設計就會好得多。每當你寫if語句時,Nyan Cat就會哭。其次,我們需要對所有空閑的cpu做些什麼,以免它們變得有活力,創建天網。

因此,為了保持設計的一致性並領先於魔鬼一步,OS開發人員創建了一個空閑任務,該任務在沒有其他工作時被調度運行。在Linux引導過程中,我們已經看到空閑任務是process 0,它是第一次打開計算機時運行的第一個指令的直接後裔。它在rest_init中初始化,其中init_idle_bootup_task初始化空閑調度類。

簡單地說,Linux支持實時進程、常規用戶進程等不同的調度類。當選擇要成為活動任務的進程時,將按優先順序查詢這些類。這樣,核反應堆控制代碼總是在web瀏覽器之前運行。但是,這些類通常返回NULL,這意味著它們沒有合適的進程可以運行——它們都在休眠。但是最後運行的空閑調度類從來不會失敗:它總是返回空閑任務。

這很好,但是讓我們來看看這個空閑任務到底在做什麼。這是cpu_idle_loop,由開源軟體提供:

cpu_idle_loop

while (1) {
while(!need_resched()) {
cpuidle_idle_call();
}

/*
[Note: Switch to a different task. We will return to this loop when the
idle task is again selected to run.]
*/
schedule_preempt_disabled();
}

我省略了許多細節,稍後我們將仔細研究任務切換,但是如果你閱讀代碼,你將了解其要點:只要不需要重新調度,即更改活動任務,就保持空閑。以運行時間來衡量,這個循環及其在其他操作系統中的同類可能是計算歷史上執行次數最多的代碼。對於英特爾處理器,保持空閑通常意味著運行停止指令:

native_halt

static inline void native_halt(void)
{
asm volatile("hlt": : :"memory");
}

hlt停止處理器中的代碼執行,並將其置於停止狀態。奇怪的是,在世界各地,數以百萬計的類似intel的cpu即使在通電的情況下,大部分時間也處於停頓狀態。它的效率也不是很高,在能源方面,這導致晶元製造商為處理器開發更深層的睡眠狀態,以更低的能耗換取更長的喚醒延遲。內核的cpuidle子系統負責利用這些省電模式。

現在,一旦我們告訴CPU停止或休眠,我們需要以某種方式讓它恢復生命。如果你已經閱讀了上一篇文章,你可能會懷疑其中涉及到中斷,事實上確實如此。中斷促使CPU脫離停止狀態並返回到動作狀態。綜上所述,下面是你的系統在你閱讀完整呈現的web頁面時的主要功能:

除了計時器中斷之外,其他中斷也使處理器再次移動。例如,如果單擊web頁面,就會發生這樣的情況:滑鼠發出一個中斷,它的驅動程序處理它,然後突然一個進程可以運行,因為它有新的輸入。此時,need_resched()返回true,空閑任務將被趕出瀏覽器。

但是讓我們在這篇文章中堅持懶惰。這是空閑循環的時間:

在這個例子中,定時器中斷被內核編程為每4毫秒(ms)發生一次。這是滴答周期。這意味著我們每秒有250個節拍,所以節拍速率或節拍頻率是250hz。對於運行在英特爾處理器上的Linux來說,這是一個典型的值,100 Hz是另一個受歡迎的值。這是在構建內核時CONFIG_HZ選項中定義的。

現在,對於空閑的CPU來說,這看起來是一大堆毫無意義的工作,確實如此。如果沒有來自外部世界的新鮮輸入,CPU將繼續處於這種該死的睡眠狀態,每秒被喚醒250次,而你的筆記本電腦電池耗盡。如果它在虛擬機中運行,我們就會消耗主機CPU的能量和寶貴的周期。

這裡的解決方案是一個動態的滴答,這樣當CPU空閑時,定時器中斷禁用或者在需要內核工作的時候要發生滴答中斷(例如,一個過程可能在5秒計時器到期,所以我們不能睡過去)。這也稱為tickless模式。

最後,假設系統中有一個活動進程,例如一個長期運行的cpu密集型任務。這幾乎與空閑系統相同:以上示意圖保持不變,只是用一個進程代替空閑任務,並且這些圖是準確的。在這種情況下,每4毫秒中斷一次任務仍然沒有任何意義:這只是操作系統的抖動讓你的工作稍微慢了一點。Linux還可以在這個單進程場景中以所謂的adaptivate -tick模式停止固定速率滴答。最終,固定速率可能會徹底消失。

內核的空閑行為是操作系統難題的重要組成部分,它與我們將看到的其他情況非常相似,因此這有助於我們構建正在運行的內核的模型。

--未完待續

由於本人水平有限,翻譯必然有很多不妥的地方,歡迎指正。

同時,歡迎關注下方微信公眾號,一起交流學習:)


推薦閱讀:

TAG:Linux內核 | 進程管理 |