RFC-0209:記憶體優先順序設定檔

RFC-0209:記憶體優先順序設定檔
狀態已接受
區域
  • Kernel
說明

使用設定檔標示 VMAR 的優先順序。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2022-08-16
審查日期 (年-月-日)2023-02-15

摘要

使用設定檔物件,指示核心盡量減少頁面錯誤和其他可能增加記憶體存取延遲的操作,方法是允許將設定檔套用至 VMAR。

提振精神

Zircon 是過度提交系統,並採用不同的回收系統,嘗試支援這些應用程式。這些回收方法包括逐出、頁面表格回收、零頁面掃描等,可能會與截止期限工作發生衝突,因為這些方法可能會在記憶體存取中加入無法接受的延遲量。此外,未來可能採用的回收方法 (例如網頁壓縮) 也會造成問題。

音訊是重複出現的例子,核心的任何回收作業都會導致音訊執行緒發生後續的頁面錯誤,進而導致音訊執行緒錯過期限。

目前為止,解決方案都是核心中的特殊案例解決方法,目的是停用所有類型的回收,僅適用於音訊相關元件。不過,這種做法非常脆弱,無法擴展到有類似需求的其他使用者。

本 RFC 的目標是提供適用於音訊和其他元件的一般機制,以取代現有的暫時性解決方法。

利害關係人

協助人員:

jamesr@google.com

審查者:

eieio@google.com、rashaeqbal@google.com、tombergan@google.com

已諮詢:

andresoportus@google.com

社交:

Zircon 團隊和 Kernel Evolution Working Group (KEWG) 都在文件中討論過這個問題和提案。

API 設計

如要將回收控制權交給使用者,個人資料物件會透過兩種方式擴充:

  1. 系統會新增 ZX_PROFILE_INFO_FLAG_MEMORY_PRIORITYzx_profile_create 旗標,以及 memory_priority 欄位。
  2. 透過 zx_object_set_profile,即可將設定檔套用至 VMAR。

一開始系統只會支援 memory_priority 欄位的兩個值:ZX_PRIORITY_DEFAULTZX_PRIORITY_HIGH,其中高值會永久停用所有回收作業。Room 會保留支援其他層級的空間,以便在日後允許在延遲時間和避免 OOM 之間進行取捨。

將設定檔套用至 VMAR 時,假設該設定檔具有有效的 memory_priority,系統會立即將設定檔套用至該 VMAR 和所有子區域,並覆寫先前套用的任何設定檔。

核心必須遵守 ZX_PRIORITY_HIGH 設定,且核心「必須」在標記的 VMAR 中停用任何動態回收功能。

ZX_PRIORITY_DEFAULT 設定沒有特殊意義,也不一定要遵守。特別是核心,主要是為了簡化實作,可將 ZX_PRIORITY_HIGH 要求擴展至標示為 ZX_PRIORITY_DEFAULT 的更廣範圍。

雖然一律允許超額應用程式,但如果位址空間從具有某些 ZX_PRIORITY_HIGH VMAR 變成沒有任何 VMAR,核心「應」會返回與從未套用任何設定檔時相同的狀態。

資訊查詢

zx_object_get_infoZX_INFO_KMEM_STATS_EXTENDED 主題將擴充為回報額外欄位:

    // The amount of memory in VMOs that would otherwise be tracked for
    // reclamation, but has had reclamation disabled.
    uint64_t vmo_reclaim_disabled_bytes;

元件用量

使用者空間元件通常不會直接使用 zx_profile_create 等,而是叫用 ProfileProvider 服務。這裡的 SetProfileByRole 方法會放寬 ProfileProvider,接受任意控制代碼,而非僅限執行緒。

核心設計

本節說明如何變更核心中的物件,以配合設定檔中的資訊。目標是確保系統中可能需要瞭解記憶體優先順序的任何部分,都能有效存取該優先順序,以利做出決策。在可能的情況下,這個設計會偏好在設定檔應用程式套用時執行作業,因為與其他作業相比,設定檔應用程式套用作業不常執行。

縮減為布林值

回收作業涉及的核心物件包括:

  • VmAspace - Controls page table mappings and page table reclamation goes through here.
  • VmAddressRegion - 目前未參與回收作業,但所有頁面資料表對應都是透過這個物件建立。
  • VmObject - 任何逐出或未來的頁面回收策略,都會經過 VmObject

除了設定檔套用的物件 VmAddressRegion 之外,每個物件都可以查詢任何子範圍,瞭解該範圍中存在的 VMAR 和套用的記憶體優先順序。

如果有多個 VMAR 具有不同優先順序,並套用至 VMO 區域,系統會採用優先順序最高的 VMAR。

為避免在所有 VMAR 中重複執行長時間的搜尋作業,物件需要有效率地判斷是否有任何記憶體優先順序適用於自身。為簡化追蹤作業,初步建議的實作方式會將任何優先順序範圍升級為完整物件。也就是說,如果設定檔參照 VmObject 的任何部分,系統會將整個物件視為具有該設定檔。

這兩項簡化實作方式,可讓記憶體設定檔查詢作業更有效率,只需要透過物件連結傳播布林聯集即可。

傳播

這項停用回收布林值的傳播作業,是以邊緣轉換和計數為基礎。

如果 VMAR 已設定設定檔,請考量以下三種結果:

  1. VMAR 回收程序維持不變。
  2. 回收功能從停用狀態轉換為啟用狀態。
  3. 回收功能從啟用狀態轉換為停用狀態。

在第一種情況下,不會發生直接傳播,但仍須遍歷所有子區域,並將設定檔套用至這些區域。由於子區域套用了不同的設定檔,因此需要覆寫,所以必須進行這項無條件遍歷。

在任一轉場效果中,兩個可能的參照物件 (VmAspaceVmObject) 都需要更新。

VmAspaceVmObject 物件不會是單一布林值,而是會計算有多少參照物件停用回收功能。因此,判斷這些物件是否停用回收功能,就是比較計數是否為零。

VmObject 可能有其他 VmObject 父項,需要將旗標傳播至這些父項。由於回收作業是由計數器控制 (是否為零),因此當計數器轉換為零或從零轉換時,就會發生傳播。

這項參照計數傳播策略可確保設定檔變更盡可能有效率,與只追蹤布林值相比,幾乎沒有額外負荷。

VmObject 轉場

除了傳播回收旗標,VmObject 也需要執行動作,做為更新頁面轉換的一部分。

停用回收功能後,所有可回收的頁面都會移至獨立的頁面佇列。將網頁加入這個佇列,可避免遭到回收,並提供計算網頁數量的管道。

同樣地,啟用回收功能後,網頁必須移回預設佇列,才能再次成為回收候選項目。當這些網頁放回預設佇列時,系統會將網頁視為多長時間的網頁,這是實作細節。如果平台沒有硬體存取權標記,就無法取得任何年齡資訊,因此必須自行編造年齡。

實作

實作作業會透過一系列步驟完成,從核心實作開始,逐步完成各層 API。

核心實作

建議的 Kernel 物件變更設計可完全實作,以便新增設定記憶體優先順序的功能,且不會變更任何行為。這項作業會透過多個 CL 完成,並使用核心單元測試進行測試。

核心 API 異動

ZX_INFO_KMEM_STATS_EXTENDED 查詢需要相當於系統資源的權限,且只有少數用途,全都在樹狀結構中。因此,這項查詢可以在單一 CL 中修改,不必進行多階段結構演變。

更新設定檔 API 和說明文件,並將設定檔系統呼叫連結至先前實作的 Kernel 支援。zx_profile_createsyscall 和相關聯的設定結構體 zx_profile_info_t 是具備權限的系統呼叫,因此同樣可以在單一 CL 中修改。

ProfileProvider 變更

擴充 ProfileProvider 的實作項目,支援在 .profiles 中指定記憶體優先順序的方法。

變更 ProfileProvider FIDL API,使其接受任意控制代碼,而不只是執行緒。由於這是 API 的放寬措施,因此不會破壞任何回溯相容性。

媒體遷移

媒體相關元件的相關設定檔將會變更,以納入 memory_priorityZX_PRIORITY_HIGH,然後任何媒體元件都會以與套用至執行緒完全相同的方式,將這些設定檔套用至根 VMAR。

確認設定檔運作正常後,即可移除現有的硬式編碼核心解決方法。

效能

建議的 Kernel 設計與 Kernel 中使用的暫時性解決方法非常接近,但目前的暫時性方法無法取消套用,且會永久套用至所有相關的 VMAR 和 VMO。因此,就功能和核心行為 (包括 CPU 和記憶體用量) 而言,從這個方法切換至設定檔應該完全不會有任何作業。

安全性考量

如要使用設定檔,進而設定記憶體優先順序,必須先取得根工作控制代碼。因此,阻斷服務攻擊的任何安全考量,都等同於 ProfileProvider 現有的阻斷服務可能性。

測試

大部分的測試都可以著重於各別核心和設定檔供應商實作的單元測試,並進行一些整合測試,以驗證完整的使用路徑。

說明文件

系統會更新設定檔物件、相關系統呼叫和 FIDL 通訊協定的相關文件。

替代方案

VMAR 上的屬性或對等項目

您可以直接在 VMAR 物件上設定屬性 (或同等項目),藉此指出優先順序,而不必使用設定檔物件。這樣可避免擴充排程器物件,並簡化使用者空間用量,且不需要 ProfileProvider 參與。

這種做法無法限制設定優先順序的能力。雖然任何元件都可分配任意記憶體並執行阻斷服務,但這不一定是理想做法,而且停用回收功能可能會提高效能,但這可能會導致公地悲劇。

雖然可以設計某種形式的專屬存取權控管機制來解決這個問題,但現在使用設定檔的優勢已不復存在。

透過汙染進行推論

除了使用者空間的任何直接標記外,您也可以假設任何期限執行緒都需要期限記憶體存取,並將存取的任何記憶體標記為高優先順序。這項作業不需要變更使用者空間,但需要過度標記,且每個位址空間至少有一個期限執行緒,其中所有對應都已標記,或對應/VMO 在期限執行緒使用/觸控後標記。

過度標記會造成問題,因為並非所有期限執行緒都有相同的記憶體延遲時間需求,且並非所有執行緒的位址空間都相同。延遲汙染表示無法預先錯誤,因此在最糟的情況下,截止期限執行緒可能總是會錯過截止期限,以錯誤項目。

此外,在延遲標記機制中,系統如何取消標記項目也不明確。

將 memory_priority 套用至執行緒

您不必將設定檔套用至 VMAR,而是可以在設定檔套用至執行緒時解讀 memory_priority 欄位,並將優先順序套用至根 VMAR。

雖然這項做法簡化了 ProfileProvider 通訊協定和系統呼叫介面,但會阻礙使用者和核心在未來提高效率。有效率的元件可以將延遲時間敏感的重要資料整理到位址空間的一個子區域,將非重要資料整理到另一個區域,然後只將設定檔套用至重要區域。這樣一來,非重要資料仍可做為回收考量,有助於提升記憶體使用率。

單一優先順序欄位

可以重複使用執行緒優先權的相同 priority 欄位,不必導入額外的 memory_priority 欄位。這樣做理論上可簡化設定結構,但現在如果需要不同的記憶體和排程器優先順序,就必須建立不同的設定檔物件。

展開 ALWAYS_NEED 提示

現有 API 可透過 VMO 或 VMAR 上的 ALWAYS_NEEDDONT_NEED 提示控制回收作業。目前這些提示僅適用於分頁支援的 VMO,但可擴充至匿名 VMO。

將語意擴展至涵蓋匿名 VMO 僅會留下一些缺口:

  • ALWAYS_NEED 只是提示,無法保證不會發生回收作業。
  • 系統仍會追蹤年齡,因此網頁可能仍需存取錯誤。
  • 不會停用頁面資料表回收。
  • 只能套用至現有對應。

使用類似主要提案所述的內部實作方式,即可解決上述各項限制,但 API 本身有兩個基本問題。

主要提案清楚說明如何得知回收功能已重新啟用,方法是將設定檔套用至所有 VMAR (或僅套用至根 VMAR)。提示無法移除 ALWAYS_NEED,因為 DONT_NEED 比復原 ALWAYS_NEED 更強大。

提示 API 採用提示而非 Promise 的原因之一,是缺乏存取權控管,因此可在任何 VMAR 或 VMO 上使用。工作政策或類似政策可用於控管提示的用途,但這類機制也需要設計。