
看看源頭strace
我發現了克隆標誌的使用CLONE_IDLETASK
,其描述為:
#define CLONE_IDLETASK 0x00001000 /* kernel-only flag */
深入研究後我發現,雖然該標誌沒有被涵蓋,但man clone
實際上核心在啟動過程中使用它為機器上的每個 CPU 創建空閒進程(所有這些進程的 PID 都應該為 0)。即一台有 8 個 CPU 的機器將至少有 7 個(見下面的問題)這樣的進程「運行」(注意引號)。
現在,這讓我產生了幾個關於「空閒」進程實際上做了什麼的問題。我的假設是它連續執行 NOP 操作,直到其時間範圍結束並且核心分配一個真實的進程來運行或再次分配空閒進程(如果 CPU 沒有被使用)。然而,這完全是猜測。所以:
在一台擁有 8 個 CPU 的機器上,會建立 7 個這樣的空閒行程嗎? (而一個 CPU 將由核心本身佔用,同時不執行使用者空間工作?)
空閒行程真的只是無限的 NOP 操作流程嗎? (或執行相同操作的循環)。
CPU使用率(例如
uptime
)是否簡單地透過空閒進程在CPU上運行的時間以及在特定時間段內空閒進程不存在的時間來計算?
PS 這個問題很可能很大程度上是由於我不完全理解CPU是如何運作的。即我了解彙編、時間範圍和中斷,但我不知道如何,例如,CPU 可能會根據其正在執行的內容使用更多或更少的能量。如果有人也能啟發我,我將不勝感激。
答案1
空閒任務用於進程統計,同時也是為了減少能耗。在Linux中,為每個處理器建立一個空閒任務,並鎖定到該處理器;只要該 CPU 上沒有其他進程運行,就會調度空閒任務。花在空閒任務上的時間在諸如top
. (正常運轉時間的計算方式不同。)
Unix 似乎總是有某種空閒循環(但不一定是實際的空閒任務,請參閱吉爾斯的回答),甚至在 V1 中它使用了一條WAIT
指令它停止處理器直到發生中斷(它代表“等待中斷”)。其他一些作業系統使用繁忙循環,DOS,作業系統/2,尤其是 Windows 的早期版本。長期以來,CPU 一直使用這種「等待」指令來減少能耗和熱量產生。您可以看到空閒任務的各種實現,例如arch/x86/kernel/process.c
在Linux核心中:基本的只是調用HLT
,它會停止處理器直到發生中斷(並啟用 C1 節能模式),其他實作處理各種錯誤或效率低(例如使用MWAIT
而不是HLT
在某些 CPU 上)。
當進程等待事件(I/O 等)時,所有這些都與進程中的空閒狀態完全分開。
答案2
在進程排程器的教科書設計中,如果排程器沒有任何程序要調度(即,如果所有程序都被阻塞,等待輸入),排程器將等待處理器中斷。中斷可以指示來自周邊設備的輸入(使用者操作、網路封包、從磁碟完成的讀取等),或者可以是觸發進程中的計時器的計時器中斷。
Linux 的調度程式沒有針對無事可做情況的特殊程式碼。相反,它將無事可做的情況編碼為特殊進程,即空閒進程。只有當沒有其他進程可調度時,空閒進程才會被調度(它實際上具有無限低的優先權)。空閒進程實際上是核心的一部分:它是一個核心線程,即執行核心中程式碼的線程,而不是進程中的程式碼。 (更準確地說,每個 CPU 都有一個這樣的執行緒。)當空閒程序運行時,它會執行等待中斷操作。
等待中斷的工作方式取決於處理器的功能。對於最基本的處理器設計,這只是一個繁忙的循環 -
nothing:
goto nothing
處理器永遠運行分支指令,但什麼也做不了。大多數現代作業系統不會這樣做,除非它們運行在沒有更好的處理器上,而大多數處理器都有更好的東西。理想情況下,處理器應該關閉,而不是除了房間供暖之外什麼也不做。因此,核心運行程式碼來指示處理器自行關閉,或至少關閉大部分處理器。必須至少有一小部分保持通電狀態,即中斷控制器。當外設觸發中斷時,中斷控制器將向主(部分)處理器發送喚醒訊號。
實際上,Intel/AMD 和 ARM 等現代 CPU 具有許多複雜的電源管理設定。作業系統可以估計處理器將保持空閒模式的時間,並根據此選擇不同的低功耗模式。這些模式在空閒時的功耗以及進入和退出空閒模式所需的時間之間提供了不同的折衷方案。在某些處理器上,當作業系統發現進程沒有消耗太多 CPU 時間時,它還可以降低處理器的時脈速率。
答案3
不,空閒任務不會浪費 CPU 週期。調度程序根本不選擇空閒進程來執行。空閒進程正在等待某個事件發生,以便它可以繼續。例如,它可以等待read()
系統呼叫中的輸入。
順便說一句,核心不是一個單獨的進程。核心程式碼總是在進程的上下文中執行(當然,除了核心執行緒的特殊情況),因此「一個 CPU 將由核心本身佔用,同時不執行使用者空間工作」的說法是不正確的。