| RFC-0016:啟動時間頁面大小 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 將 PAGE_SIZE 常數替換為 vdsocall。 |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2020-12-02 |
| 審查日期 (年-月-日) | 2021-01-12 |
摘要
如果需要最佳效能,Fuchsia 系統應可利用較大的頁面大小。如要實現這點,頁面大小必須是執行階段常數,而非編譯階段常數。這個常數應由核心在啟動期間以某種方式決定,然後透過 VDSO 提供給使用者,以便在執行階段查詢。
提振精神
為達到最佳效能,系統應能根據靜態已知資訊或啟動時查詢的資訊,選取頁面大小。此外,靜態決策應可隨著需求或規定變更,最好不要以 ABI 中斷的方式變更。
不同頁面大小的效能取捨不同。較大的頁面可增加有效的 TLB 涵蓋範圍,進而減少 CPU 負荷,並按比例提升以頁面精細度運作的任何演算法或作業效能,例如頁面分配、錯誤和掃描。大頁面可減少頁面表的記憶體用量,但也會造成過度分配,浪費記憶體,因此較小的頁面可提供更理想的記憶體用量。
這項效能與記憶體用量之間的取捨,會因硬體和系統工作負載而異。在啟動時通知使用者頁面大小,可讓您在核心編譯時靜態變更頁面大小,或在核心啟動時動態變更頁面大小,而不會破壞與使用者層級元件的二進位檔相容性。
設計
方法是在 VDSO 中新增額外常數,並使用 VDSO 呼叫 (zx_system_get_page_size) 擷取該常數。然後,即可將現有編譯時間常數的任何用法,遷移至使用 VDSO 呼叫,直到編譯時間常數可移除為止。
此外,也應為每個平台宣告最小和最大頁面大小。這是為了讓使用者瞭解可連結的最大網頁大小,確保元件可攜性。
實作
導入程序分為三個階段。雖然使用的是 C/C++ 名稱,但所有 Fuchsia 支援的語言都必須進行對等作業。
- 新增
zx_system_get_page_sizeVDSO 呼叫和相關聯的 VDSO 常數,以及PAGE_MIN_SIZE和PAGE_MAX_SIZE定義。 - 將
PAGE_SIZE(或同等語言) 的用法遷移至 VDSO 呼叫 - 不再使用時,請移除
PAGE_SIZE(或語言對等項目) 定義。
第一和第三階段微不足道,只會是小型的單一 CL。
遷移階段應簡單明瞭,但應盡可能完成多個以元件為範圍的 CL。
雖然這並非本 RFC 的嚴格規定,但如要實際變更特定產品的頁面大小,還需要完成下列事項:
- 支援較大頁面的低層級核心實作。
- 使用者元件 (例如 BlobFS) 需要修改,才能支援非 4KiB 頁面。
- 必須提高 ELF 區段的對齊程度,避免網頁需要重疊的安全權限。
效能
雖然這會將編譯時間常數遷移至執行階段查詢,但預期不會對效能造成任何可衡量的影響,因為網頁大小計算並不在任何熱路徑上。不過,在執行 VDSO 呼叫的遷移作業時,應注意所有不在初始化或測試程式碼中的用法,並評估受影響元件的效能。
安全性考量
無
隱私權注意事項
無
測試
現有的測試應該足以找出遷移期間可能發生的任何愚蠢錯誤。遷移元件中的任何程式碼時,都應檢查測試的程式碼涵蓋範圍。
說明文件
zx_system_get_page_size VDSO 呼叫必須記錄在文件中。文件應說明
- 這是最小的頁面大小,也是所有配置的基本單位。
- vdsocall 絕不會失敗。
- 頁面大小保證是 2 的乘冪。
- 頁面大小一經讀取即為常數,可供使用者快取。
VMO 和其他記憶體相關的系統呼叫和物件現有說明文件,原本就已是抽象概念,而且一律是指「系統網頁大小」。
平台文件應記錄最小和最大頁面大小,並反映 PAGE_MIN_SIZE 和 PAGE_MAX_SIZE 常數。這些值是
- ARM aarch64:最小值為 4KiB,最大值為 64KiB。
- x86-64:下限為 4 KiB,上限為 2 MiB。
缺點、替代方案和未知事項
系統網頁大小與使用者正確執行 VMO 作業,或實作與其他 Fuchsia 服務的通訊協定有很大關聯。因此,目前尚不清楚非 Fuchsia 原生程式碼何時需要瞭解或依附於頁面大小,但如果發生這種情況,可能需要修改來源才能移植。
從編譯時間常數執行遷移作業雖然概念上不複雜,但會導致大量程式碼異動,且過程中很有可能發生錯誤。
不過,移除對編譯時間常數的參照,並不代表程式碼實際上能夠容許不同的頁面大小。演算法有許多機會可將假設納入目前的 4KiB 頁面大小,或單純定義自己的頁面大小常數。如果編譯時間常數有所變更,也會造成這些問題,因此應視為無關的錯誤。
主要替代方案是繼續使用編譯時間常數,但要修正特定產品的常數,或是修正特定產品的常數組合。針對特定產品進行修正可能適用於某些嚴格控管的產品,但對於希望在不同硬體疊代中長期保持二進位檔相容性的長期執行產品,則不太適合。需要使用不同頁面大小建構多個二進位檔版本,可提供所需的彈性,但會耗費大量開發人員時間和儲存空間。一般來說,堅持使用編譯時間常數有很多缺點,唯一可察覺的優點是避免一次性遷移。
網頁大小可能隨時間變動,或因元件而異,因此無法使用啟動時間常數。雖然這提供了極大的彈性,但由於具有與網頁大小相關聯語意的物件 (例如 VMO) 可以在元件之間任意共用,因此嘗試使用不同網頁大小會對使用者造成不合理的負擔,因為他們必須查詢並避免網頁大小變更的競爭條件。如果頁面大小與系統頁面大小不同,但對特定子系統有益,則應開發獨立機制,明確選擇加入 VMO,或以其他方式最佳化頁面大小。
應用程式也需要知道頁面大小 (以位元為單位),才能執行位移算術。為此,除了 zx_system_get_page_size 之外,也可以新增 zx_system_get_page_shift,或改為新增 zx_system_get_page_shift。由於使用位移是微調作業,因此只有在應用程式快取 vdsocall 的結果時,才可能帶來好處。因此,使用者將頁面大小轉換為位移並快取該位移,就等同於執行這項操作。因此,以 vdsocall 形式提供這兩種變體,實際上並無好處。
既有技術和參考資料
Unix 衍生產品會透過 sysconf(_SC_PAGE_SIZE) 報告頁面大小。
PAGE_SIZE 編譯時間常數會以核心程式碼中的常數形式提供,並由部分發行版本以 <sys/user.h> 的一部分提供,但這並非標準或可攜式常數。
Windows 會透過 GetSystemInfo() 系統呼叫回報頁面大小。
macOS 會透過 sysctl() 呼叫或 vm_page_size 變數回報頁面大小。