NO_HZ:減少排程時鐘節拍

本文件介紹了 Kconfig 選項和啟動引數,這些選項和引數可以減少排程時鐘中斷的數量,從而提高能源效率並減少作業系統抖動。減少作業系統抖動對於某些型別的計算密集型高效能計算 (HPC) 應用程式和即時應用程式非常重要。

有三種主要方法來管理排程時鐘中斷(也稱為“排程時鐘節拍”或簡稱為“節拍”)

  1. 永不省略排程時鐘節拍(對於舊核心,CONFIG_HZ_PERIODIC=y 或 CONFIG_NO_HZ=n)。通常您-不-會希望選擇此選項。

  2. 在空閒 CPU 上省略排程時鐘節拍(對於舊核心,CONFIG_NO_HZ_IDLE=y 或 CONFIG_NO_HZ=y)。這是最常見的方法,應該是預設設定。

  3. 在空閒或只有一個可執行任務的 CPU 上省略排程時鐘節拍 (CONFIG_NO_HZ_FULL=y)。除非您正在執行即時應用程式或某些型別的 HPC 工作負載,否則通常您-不-會希望使用此選項。

以下三個部分描述了這三種情況,然後是關於 RCU 特定考慮事項的第三部分,討論測試的第四部分以及列出已知問題的第五個也是最後一個部分。

永不省略排程時鐘節拍

來自 1990 年代和 2000 年代初期的非常舊版本的 Linux 無法省略排程時鐘節拍。事實證明,在某些情況下,這種老式方法仍然是正確的方法,例如,在使用短 CPU 突發的許多工的繁重工作負載中,存在非常頻繁的空閒期,但這些空閒期也很短(數十或數百微秒)。對於這些型別的工作負載,通常會傳遞排程時鐘中斷,因為每個 CPU 通常會有多個可執行任務。在這些情況下,嘗試關閉排程時鐘中斷除了增加在空閒狀態之間切換以及在使用者和核心執行之間轉換的開銷之外,不會產生任何影響。

可以使用 CONFIG_HZ_PERIODIC=y(或者對於舊核心,CONFIG_NO_HZ=n)選擇此操作模式。

但是,如果您正在執行具有較長空閒期的輕型工作負載,則無法省略排程時鐘中斷將導致過多的功耗。這在電池供電裝置上尤其糟糕,因為它會導致電池壽命極短。如果您正在執行輕型工作負載,那麼您應該閱讀以下部分。

此外,如果您正在執行即時工作負載或具有短迭代的 HPC 工作負載,則排程時鐘中斷可能會降低您的應用程式效能。如果這描述了您的工作負載,您應該閱讀以下兩個部分。

對於空閒 CPU,省略排程時鐘節拍

如果 CPU 空閒,則向其傳送排程時鐘中斷沒有多大意義。畢竟,排程時鐘中斷的主要目的是迫使繁忙的 CPU 在多個任務之間轉移注意力,而空閒的 CPU 沒有任務可以轉移注意力。

未接收排程時鐘中斷的空閒 CPU 被稱為“dyntick-idle”、“處於 dyntick-idle 模式”、“處於 nohz 模式”或“執行無節拍”。本文件的其餘部分將使用“dyntick-idle 模式”。

CONFIG_NO_HZ_IDLE=y Kconfig 選項使核心避免向空閒 CPU 傳送排程時鐘中斷,這對於電池供電裝置和高度虛擬化的大型機都至關重要。執行 CONFIG_HZ_PERIODIC=y 核心的電池供電裝置會非常快地耗盡其電池,其速度很容易是執行 CONFIG_NO_HZ_IDLE=y 核心的同一裝置的 2-3 倍。執行 1,500 個作業系統例項的大型機可能會發現一半的 CPU 時間被不必要的排程時鐘中斷消耗掉。在這些情況下,有強烈的動機避免向空閒 CPU 傳送排程時鐘中斷。也就是說,dyntick-idle 模式不是免費的

  1. 它增加了在進入和退出空閒迴圈的路徑上執行的指令數量。

  2. 在許多架構上,dyntick-idle 模式還會增加昂貴的時鐘重新程式設計操作的數量。

因此,具有嚴格即時響應約束的系統通常執行 CONFIG_HZ_PERIODIC=y 核心(對於舊核心,CONFIG_NO_HZ=n),以避免降低從空閒狀態轉換的延遲。

還有一個啟動引數“nohz=”,可用於透過指定“nohz=off”來停用 CONFIG_NO_HZ_IDLE=y 核心中的 dyntick-idle 模式。預設情況下,CONFIG_NO_HZ_IDLE=y 核心以“nohz=on”啟動,從而啟用 dyntick-idle 模式。

對於只有一個可執行任務的 CPU,省略排程時鐘節拍

如果 CPU 只有一個可執行任務,則向其傳送排程時鐘中斷沒有多大意義,因為沒有其他任務可以切換到。請注意,對於只有一個可執行任務的 CPU 省略排程時鐘節拍意味著也對空閒 CPU 省略它們。

CONFIG_NO_HZ_FULL=y Kconfig 選項使核心避免向具有單個可執行任務的 CPU 傳送排程時鐘中斷,並且此類 CPU 被稱為“自適應節拍 CPU”。這對於具有嚴格即時響應約束的應用程式非常重要,因為它允許它們將最壞情況下的響應時間提高排程時鐘中斷的最大持續時間。對於計算密集型的短迭代工作負載也很重要:如果在給定的迭代期間延遲了任何 CPU,則所有其他 CPU 將被迫等待空閒狀態,而延遲的 CPU 完成。因此,延遲乘以小於 CPU 數量的 1。在這些情況下,再次有強烈的動機避免傳送排程時鐘中斷。

預設情況下,沒有 CPU 將是自適應節拍 CPU。“nohz_full=”啟動引數指定自適應節拍 CPU。例如,“nohz_full=1,6-8”表示 CPU 1、6、7 和 8 是自適應節拍 CPU。請注意,您被禁止將所有 CPU 標記為自適應節拍 CPU:必須至少有一個非自適應節拍 CPU 保持線上以處理計時任務,以確保諸如 gettimeofday() 之類的系統呼叫在自適應節拍 CPU 上返回準確的值。(對於 CONFIG_NO_HZ_IDLE=y,這不是問題,因為沒有執行的使用者程序可以觀察到時鐘速率的輕微漂移。)請注意,這意味著您的系統必須至少有兩個 CPU,CONFIG_NO_HZ_FULL=y 才能為您做任何事情。

最後,自適應節拍 CPU 必須解除安裝其 RCU 回撥。這將在下面的“RCU 含義”部分中介紹。

通常,CPU 會盡可能長時間地保持在自適應節拍模式下。特別是,轉換為核心模式不會自動更改模式。相反,CPU 僅在需要時才退出自適應節拍模式,例如,如果該 CPU 將 RCU 回撥排隊。

就像 dyntick-idle 模式一樣,自適應節拍模式的好處不是免費的

  1. CONFIG_NO_HZ_FULL 選擇 CONFIG_NO_HZ_COMMON,因此您不能在不執行 dyntick 空閒狀態的情況下執行自適應節拍。此依賴關係延伸到實現中,因此 CONFIG_NO_HZ_IDLE 的所有成本也由 CONFIG_NO_HZ_FULL 承擔。

  2. 由於需要通知核心子系統(如 RCU)有關模式更改,因此使用者/核心轉換稍微貴一些。

  3. POSIX CPU 定時器阻止 CPU 進入自適應節拍模式。需要根據 CPU 時間消耗採取措施的即時應用程式需要使用其他方法來執行此操作。

  4. 如果有比硬體可以容納的更多 perf 事件掛起,它們通常會進行迴圈,以便隨著時間的推移收集所有事件。自適應節拍模式可能會阻止此迴圈的發生。這可能會透過阻止具有大量掛起 perf 事件的 CPU 進入自適應節拍模式來解決。

  5. 自適應節拍 CPU 的排程器統計資訊可能與非自適應節拍 CPU 的計算方式略有不同。這反過來可能會擾亂即時任務的負載平衡。

雖然預計隨著時間的推移會有所改進,但自適應節拍對於許多型別的即時和計算密集型應用程式非常有用。但是,上面列出的缺點意味著不應(尚未)預設啟用自適應節拍。

RCU 含義

在某些情況下,不允許空閒 CPU 進入 dyntick-idle 模式或自適應節拍模式,最常見的是該 CPU 具有掛起的 RCU 回撥。

使用 CONFIG_RCU_NOCB_CPU=y Kconfig 選項將 RCU 回撥處理解除安裝到“rcuo” kthread 來避免這種情況。可以使用“rcu_nocbs=”核心啟動引數選擇要解除安裝的特定 CPU,該引數採用以逗號分隔的 CPU 和 CPU 範圍列表,例如,“1,3-5”選擇 CPU 1、3、4 和 5。請注意,由“nohz_full”核心啟動引數指定的 CPU 也被解除安裝。

解除安裝的 CPU 將永遠不會將 RCU 回撥排隊,因此 RCU 永遠不會阻止解除安裝的 CPU 進入 dyntick-idle 模式或自適應節拍模式。也就是說,請注意,如果需要,由使用者空間將“rcuo” kthread 固定到特定 CPU。否則,排程器將決定在哪裡執行它們,這可能不是您希望它們執行的位置。

測試

因此,您啟用了本文件中描述的所有作業系統抖動功能,但沒有看到您的工作負載行為發生任何變化。是因為您的工作負載受作業系統抖動的影響不大,還是因為其他因素在起作用?本節透過提供一個簡單的作業系統抖動測試套件來幫助回答這個問題,該套件可在以下 git 存檔的 master 分支上找到

git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git

克隆此存檔並按照 README 檔案中的說明進行操作。此測試過程將生成一個跟蹤,您可以使用該跟蹤來評估是否已成功從系統中刪除作業系統抖動。如果此跟蹤顯示您已儘可能多地刪除了作業系統抖動,那麼您可以得出結論,您的工作負載對作業系統抖動並不那麼敏感。

注意:此測試要求您的系統至少有兩個 CPU。我們目前沒有很好的方法從單 CPU 系統中刪除作業系統抖動。

已知問題

  • Dyntick-idle 會稍微減慢進入和退出空閒狀態的轉換速度。實際上,這並不是問題,除非對於最具侵略性的即時工作負載,它們可以選擇停用 dyntick-idle 模式,這是它們大多數都選擇的選項。但是,毫無疑問,某些工作負載將希望使用自適應節拍來消除排程時鐘中斷延遲。以下是這些工作負載的一些選項

    1. 使用來自使用者空間的 PMQOS 來通知核心您的延遲要求(首選)。

    2. 在 x86 系統上,使用“idle=mwait”啟動引數。

    c. 在 x86 系統上,使用“intel_idle.max_cstate=”來限制 ` 最大 C 狀態深度。

    1. 在 x86 系統上,使用“idle=poll”啟動引數。但是,請注意,使用此引數會導致您的 CPU 過熱,這可能會導致熱節流降低您的延遲 - 並且這種降低甚至可能比 dyntick-idle 的降低更嚴重。此外,此引數有效地停用了 Intel CPU 上的 Turbo Mode,這會顯著降低最大效能。

  • 自適應節拍會稍微減慢使用者/核心轉換的速度。預計這對於計算密集型工作負載來說不是問題,因為它們很少進行此類轉換。需要仔細的基準測試才能確定其他工作負載是否會受到此效應的顯著影響。

  • 僅當給定 CPU 只有一個可執行任務時,自適應節拍才會執行任何操作,即使在許多其他情況下不需要排程時鐘節拍。舉一個例子,考慮一個 CPU,它有一個可執行的高優先順序 SCHED_FIFO 任務和任意數量的低優先順序 SCHED_OTHER 任務。在這種情況下,要求 CPU 執行 SCHED_FIFO 任務,直到它阻塞或某個其他更高優先順序的任務在此 CPU 上喚醒(或分配給此 CPU),因此沒有必要向此 CPU 傳送排程時鐘中斷。但是,當前實現仍然向具有單個可執行 SCHED_FIFO 任務和多個可執行 SCHED_OTHER 任務的 CPU 傳送排程時鐘中斷,即使這些中斷是不必要的。

    即使在給定的 CPU 上有多個可執行任務,在當前執行任務的時間片到期之前中斷該 CPU 也沒有多大意義,這幾乎總是比下一個排程時鐘中斷的時間長得多。

    更好地處理這些情況是未來的工作。

  • 需要重新啟動才能重新配置自適應空閒和 RCU 回撥解除安裝。如果需要,可以提供執行時重新配置,但是,由於在執行時重新配置 RCU 的複雜性,需要有一個非常充分的理由。特別是考慮到您可以透過簡單地從所有 CPU 解除安裝 RCU 回撥並將它們固定在您希望它們被固定的地方來隨時隨地執行此操作。

  • 需要額外的配置來處理其他作業系統抖動源,包括中斷和系統實用程式任務和程序。此配置通常涉及將中斷和任務繫結到特定的 CPU。

  • 某些作業系統抖動源目前只能透過約束工作負載來消除。例如,消除由於全域性 TLB 重新整理導致的作業系統抖動的唯一方法是避免導致這些重新整理的取消對映操作(例如核心模組解除安裝操作)。對於另一個示例,可以使用大頁面並透過約束應用程式使用的記憶體量來減少(並且在某些情況下消除)頁面錯誤和 TLB 未命中。預先錯誤地處理工作集也可能很有幫助,尤其是與 mlock() 和 mlockall() 系統呼叫結合使用時。

  • 除非所有 CPU 都處於空閒狀態,否則至少一個 CPU 必須保持排程時鐘中斷執行,以支援準確的計時。

  • 如果可能存在一些自適應節拍 CPU,則至少會有一個 CPU 保持排程時鐘中斷執行,即使所有 CPU 都在其他情況下處於空閒狀態。

    更好地處理這種情況是正在進行的工作。

  • 某些程序處理操作仍然需要偶爾的排程時鐘節拍。這些操作包括計算 CPU 負載、維護排程平均值、計算 CFS 實體 vruntime、計算 avenrun 和執行負載平衡。它們目前透過每秒左右排程時鐘節拍來容納。正在進行的工作將消除即使是這些不頻繁的排程時鐘節拍的需要。