在 Linux 內核中,一個 folio 可以只包含 1 個 page,也可以包含多個 page。當一個 folio 包含多個 page 的時候,我們稱它為一個 large folio,在中文社區,我們一般稱呼其為大頁。采用 large folio 可潛在帶來諸多好處,比如:
1. TLB miss 減小,比如許多硬件都支持 PMD 映射,可以直接把 2MB 做成一個 large folio,只占用一個 TLB entry;部分硬件支持 contiguous PTE 映射,比如 ARM64 可以讓 16 個連續的 page 通過 CONT-PTE 只占一個 TLB entry。
2. page fault 次數減小,比如 do_anonymous_page() 在某個 PTE 的 page fault 后,直接申請一個 large folio 并映射一個 CONT-PTE 的話,則剩下的 15 個 PTE 不再發生 page fault。
3. 降低 LRU 的規模和內存 reclamation 的成本,以 large folio 為單位進行回收,整個 large folio 在 folio_referenced() 等的反向映射成本低于多個 small folio 單獨進行 rmap 的成本;try_to_unmap_one() 理論上也如此。
4. 潛在的以更大粒度在 zRAM/zsmalloc 進行壓縮/解壓的機會,從而降低壓縮/解壓的 CPU 利用率、提高壓縮率。比如 64KiB 的 large folio 整體壓縮,比分成 16個4KiB 的 small folio 來進行壓縮,有明顯優勢。
在 Linux 內核的整個內存管理中,large folios 將與 small folios(只有一個page)混合存在。比如在 LRU 鏈表上,掛在上面的 folio 既可能是 large,也可能是 small;一個進程的某個 VMA 里面的內存,可由 large folios 和 small folios 混合組成;文件的 pagecache 上,不同的 offset 上面對應的可能是 small folios 也可能是 large folios。
文件頁 large folios
Linux 社區在文件頁方面,發展出多個文件系統支持 large folio。這類文件系統會通過 mapping_set_large_folios()告訴 page cache 這層,它支持 large folio:
afs
bcachefs
erofs非壓縮文件
xfs
而 pagecache 這層,則會關注到這一情況,在 mapping_large_folio_support() 為真的情況下,允許申請 large folios 來填充 pagecache 的 xarray:
目前文件頁 large folios 支持的文件系統非常有限,所以在許多行業還沒法用起來,比如手機行業廣泛使用的 erofs、f2fs 等。目前我們看到,社區里面華為公司 Zhang Yi 正在完成一個 patchset:ext4: use iomap for regular file's buffered IO path and enable large foilo[1],尋求對 ext4 的 iomap 和 large folios 支持。Zhang Yi 提供的性能數據,在某種意義上可以證明文件系統支持 large folios 的好處:
匿名頁 large folios
社區里面 ARM 公司 Ryan Roberts 是這個項目的主要發起者以及相關 patchset 的主要貢獻者之一。目前匿名頁相關的 patchset 有多個議題,部分已經merge,部分在 Andrew Morton 的 mm tree 迭代,部分還在社區討論或萌芽階段。
1. Ryan Roberts(ARM)貢獻的 Multi-size THP for anonymous memory[2]
這個 patchset,允許匿名頁發生缺頁中斷的時候,申請多種不同 size 的 PTE-mapped 的 large folios。而內核原先的 THP 主要針對的是 PMD-mapped 的2MiB size,在支持多種 size 后,我們把 multi-size THP 簡稱為 mTHP?,F在 /sys/kernel/mm/transparent_hugepage 目錄下面,會有多個 hugepages- 子目錄:
比如你開啟 64KiB 的 large folios:
這樣在發生 PF 的時候,do_anonymous_page () 可以申請 64KiB 的 mTHP,并一次性透過 set_ptes 把 16 個 PTE 全部設置上:
后面 15 個 PTE 就不會再發生 PF 了。Ryan 的 patchset,保持了 mTHP 與之前THP在ABI方面的兼容,比如之前的MADV_HUGEPAGE、MADV_NOHUGEPAGE 針對 mTHP 仍然適用。
2、 Ryan Roberts(ARM)貢獻的 Transparent Contiguous PTEs for User Mappings[3]
這個 patchset 主要讓 mTHP 可以自動用上 ARM64 的 CONT-PTE,即 16 個 PTE 對應的 PFN 如果物理連續且自然對界,則設 CONT bit 以便讓它們只占用一個 TLB entry。Ryan 的這個 patchset 比較精彩的地方在于,mm 的 core 層其實不必意識到 CONT-PTE 的存在(因為不是啥硬件 ARCH 都有這個優化),保持了 PTE 相關 API 向 mm 的完全兼容,而在 ARM64 arch 的實現層面,自動加上或者去掉 CONT bit。
比如原先 16 個 PTE 滿足 CONT 的條件,如果有人 unmap 掉了其中 1 個 PTE 或者 mprotect 改變了 16 個 PTE 中一部分 PTE 的屬性導致 CONT 不再能滿足,set_ptes() 調用的 contpte_try_unfold() 則可將 CONT bit 自動 unfold 掉:
CONT-PTE 的采用有效提升了一些 benchmark 的性能,比如內核編譯: