高解析度定時器和動態節拍設計說明

更多資訊可以在 OLS 2006 會議的論文 “hrtimers and beyond” 中找到。 該論文是 OLS 2006 會議錄第 1 卷的一部分,可以在 OLS 網站上找到:https://kernel.linux.club.tw/doc/ols/2006/ols2006v1-pages-333-346.pdf

本次會議的幻燈片可從以下網址獲得:http://www.cs.columbia.edu/~nahum/w6998/papers/ols2006-hrtimers-slides.pdf

幻燈片包含五個圖表(第 2、15、18、20、22 頁),說明了與時間(定時器)相關的 Linux 子系統的變化。 圖 1(第 2 頁)顯示了在 hrtimers 和其他構建塊合併到主線之前 Linux 時間(定時器)系統的設計。

注意:論文和幻燈片談論的是 “時鐘事件源”,而我們同時切換到名稱 “時鐘事件裝置”。

該設計包含以下基本構建塊

  • hrtimer 基礎架構

  • timeofday 和時鐘源管理

  • 時鐘事件管理

  • 高解析度定時器功能

  • 動態節拍

hrtimer 基礎架構

hrtimer 基礎架構已合併到 2.6.16 核心中。 基本實現的詳細資訊在 hrtimers - 高解析度核心定時器的子系統 中介紹。 另請參見圖 2(OLS 幻燈片第 15 頁)

與儲存已啟用 timer_list 型別定時器的定時器輪相比,主要區別在於

  • 按時間順序排隊到 rb-tree 中

  • 獨立於節拍(處理基於納秒)

timeofday 和時鐘源管理

John Stultz 的通用每日時間 (GTOD) 框架將大部分程式碼從特定於架構的區域移到通用管理框架中,如圖 3(OLS 幻燈片第 18 頁)所示。 特定於架構的部分減少到時鐘源的低階硬體細節,這些時鐘源在框架中註冊,並根據質量進行選擇。 低階程式碼提供硬體設定和讀取例程,並初始化資料結構,通用時間保持程式碼使用這些資料結構將時鐘節拍轉換為基於納秒的時間值。 所有其他與時間保持相關的功能都移到通用程式碼中。 GTOD 基本補丁已合併到 2.6.18 核心中。

有關通用每日時間框架的更多資訊,請參見 OLS 2005 會議錄第 1 卷

論文 “我們不再年輕:時間和定時器的新方法” 由 J. Stultz、D.V. Hart 和 N. Aravamudan 撰寫。

圖 3(OLS 幻燈片第 18 頁)說明了轉換。

時鐘事件管理

雖然時鐘源提供對單調遞增的時間值的讀取訪問,但時鐘事件裝置用於排程下一個事件中斷。 下一個事件當前定義為週期性的,其週期在編譯時定義。 各種事件驅動功能的事件裝置的設定和選擇硬連線到依賴於架構的程式碼中。 這導致所有架構上的程式碼重複,並且使得更改系統配置以使用除已構建到架構中的事件中斷裝置之外的其他裝置極其困難。 當前設計的另一個含義是,必須觸及所有特定於架構的實現,才能提供諸如高解析度定時器或動態節拍之類的新功能。

時鐘事件子系統試圖透過提供一種通用解決方案來管理時鐘事件裝置及其在各種時鐘事件驅動的核心功能中的使用來解決此問題。 時鐘事件子系統的目標是將與時鐘事件相關的特定於架構的程式碼最小化到純粹的硬體相關處理,並允許輕鬆新增和利用新的時鐘事件裝置。 它還最大限度地減少了架構之間的重複程式碼,因為它提供了通用功能,直到中斷服務處理程式,這幾乎是硬體固有的。

時鐘事件裝置由依賴於架構的引導程式碼或在模組插入時註冊。 每個時鐘事件裝置都用時鐘特定的屬性引數和回撥函式填充資料結構。 時鐘事件管理透過使用指定的屬性引數,決定時鐘事件裝置將用於支援的系統功能集。 這包括區分每個 CPU 和每個系統的全域性事件裝置。

系統級全域性事件裝置用於 Linux 週期性節拍。 每個 CPU 事件裝置用於提供本地 CPU 功能,例如程序記帳、效能分析和高解析度定時器。

管理層將以下一個或多個功能分配給時鐘事件裝置

  • 系統全域性週期性節拍(jiffies 更新)

  • cpu 本地 update_process_times

  • cpu 本地效能分析

  • cpu 本地下一個事件中斷(非週期性模式)

時鐘事件裝置將那些與定時器中斷相關的功能的選擇完全委派給管理層。 時鐘管理層在裝置描述結構中儲存一個函式指標,該函式指標必須從硬體級別處理程式中呼叫。 這從特定於架構的定時器中斷處理程式中刪除了大量重複程式碼,並將控制權交給時鐘事件裝置以及將定時器中斷相關功能分配給核心程式碼。

時鐘事件層 API 相當小。 除了時鐘事件設備註冊介面之外,它還提供用於排程下一個事件中斷、時鐘事件裝置通知服務以及支援掛起和恢復的功能。

該框架添加了大約 700 行程式碼,導致核心二進位制檔案大小增加了 2KB。 i386 的轉換刪除了大約 100 行程式碼。 二進位制檔案大小減少量在 400 位元組範圍內。 我們認為,靈活性的提高和避免架構之間重複程式碼證明了二進位制檔案大小的略微增加是合理的。

架構的轉換沒有功能影響,但允許利用高解析度和動態節拍功能,而無需對時鐘事件裝置和定時器中斷程式碼進行任何更改。 轉換後,只需將 kernel/time/Kconfig 檔案新增到特定於架構的 Kconfig 並將動態節拍特定呼叫新增到空閒例程(總共 3 行新增到空閒函式和 Kconfig 檔案)即可啟用高解析度定時器和動態節拍。

圖 4(OLS 幻燈片第 20 頁)說明了轉換。

高解析度定時器功能

在系統啟動期間,無法使用高解析度定時器功能,而使其成為可能將是困難的,並且不會有任何有用的功能。 必須完成時鐘事件裝置框架、時鐘源框架 (GTOD) 和 hrtimers 本身的初始化,並且必須在註冊高解析度功能之前註冊適當的時鐘源和時鐘事件裝置才能工作。 在 hrtimers 初始化之前,系統以通常的低解析度週期性模式工作。 時鐘源和時鐘事件裝置層提供通知功能,通知 hrtimers 有關新硬體的可用性。 hrtimers 在切換到高解析度模式之前,會驗證已註冊時鐘源和時鐘事件裝置的可用性。 這也確保了配置為高解析度定時器的核心可以在缺少必要硬體支援的系統上執行。

高解析度定時器程式碼不支援只有全域性時鐘事件裝置的 SMP 機器。 對此類硬體的支援將涉及發生中斷時的 IPI 呼叫。 開銷將遠大於收益。 這就是為什麼我們目前在 i386 SMP 系統上停用高解析度和動態節拍,這些系統會停止 C3 電源狀態下的本地 APIC。 一種解決方法作為一種想法可用,但問題尚未得到解決。

定時器的按時間順序插入提供了所有基礎架構,以確定在新增定時器時是否必須重新程式設計事件裝置。 該決定是按定時器庫做出的,並在支援函式中跨每個 CPU 定時器庫同步。 該設計允許系統為每個 CPU 定時器庫利用單獨的每個 CPU 時鐘事件裝置,但目前每個 CPU 僅利用一個可重新程式設計的時鐘事件裝置。

當定時器中斷髮生時,下一個事件中斷處理程式從時鐘事件分發程式碼中呼叫,並將過期的定時器從紅黑樹移動到單獨的雙向連結串列中,並呼叫 softirq 處理程式。 hrtimer 結構中的附加模式欄位允許系統直接從下一個事件中斷處理程式執行回撥函式。 這僅限於可以在硬中斷上下文中安全執行的程式碼。 例如,這適用於 nanosleep 使用的喚醒函式的常見情況。 在中斷上下文中執行處理程式的優點是可以避免最多兩次上下文切換 - 從中斷的上下文到 softirq,以及到由過期定時器喚醒的任務。

一旦系統切換到高解析度模式,週期性節拍就會關閉。 這將停用每個系統全域性週期性時鐘事件裝置 - 例如 i386 SMP 系統上的 PIT。

週期性節拍功能由每個 CPU hrtimer 提供。 回撥函式在下一個事件中斷上下文中執行,並更新 jiffies 並呼叫 update_process_times 和效能分析。 基於 hrtimer 的週期性節拍的實現旨在透過動態節拍功能進行擴充套件。 這允許使用單個時鐘事件裝置在 UP 系統上排程高解析度定時器和週期性事件(jiffies 節拍、效能分析、程序記帳)。 這已被證明可以與 i386 上的 PIT 和 PPC 上的 Incrementer 一起使用。

用於執行 hrtimer 佇列和執行回撥的 softirq 已從與節拍繫結的定時器 softirq 中分離出來,以允許準確傳遞 itimer 和 POSIX 間隔定時器使用的高解析度定時器訊號。 此 softirq 的執行仍然可能被其他 softirq 延遲,但透過這種分離,整體延遲已得到顯著改善。

圖 5(OLS 幻燈片第 22 頁)說明了轉換。

動態節拍

動態節拍是基於 hrtimer 的週期性節拍替換(sched_tick)的邏輯結果。 sched_tick hrtimer 的功能由三個函式擴充套件

  • hrtimer_stop_sched_tick

  • hrtimer_restart_sched_tick

  • hrtimer_update_jiffies

當 CPU 進入空閒狀態時,呼叫 hrtimer_stop_sched_tick()。 該程式碼評估下一個排程的定時器事件(來自 hrtimers 和定時器輪),並且如果下一個事件比下一個節拍更遠,它會將 sched_tick 重新程式設計為這個未來的事件,以允許更長的空閒睡眠而不會被週期性節拍無價值地中斷。 當空閒期間發生不會導致重新排程的中斷時,也會呼叫該函式。 此呼叫是必要的,因為中斷處理程式可能已激活了一個新定時器,其到期時間早於之前呼叫 hrtimer_stop_sched_tick 時識別為最近事件的時間。

當 CPU 在呼叫 schedule() 之前離開空閒狀態時,呼叫 hrtimer_restart_sched_tick()。 hrtimer_restart_sched_tick() 恢復週期性節拍,該節拍保持活動狀態,直到下次呼叫 hrtimer_stop_sched_tick()。

在空閒期間發生中斷時,從 irq_enter() 呼叫 hrtimer_update_jiffies() 以確保 jiffies 是最新的,並且中斷處理程式不必處理可能陳舊的 jiffy 值。

動態節拍功能提供統計值,這些統計值透過 /proc/stat 匯出到使用者空間,並且可用於增強的電源管理控制。

該實現為進一步開發留下了空間,例如完全無節拍系統,其中時間片由排程程式控制、可變頻率效能分析以及未來完全刪除 jiffies。

除了當前 i386 支援的初始提交之外,該補丁集已擴充套件到 x86_64 和 ARM。 初始(正在進行中)支援也適用於 MIPS 和 PowerPC。

Thomas, Ingo