背景

巨页(gigantic folio)分配走 alloc_contig_pages() 路径,需要找到一段连续的、可隔离的物理页。profile 显示,这条路径上 87% 的时间花在 pfn_range_valid_contig() 里逐页验证区间有效性,其中 pfn_to_online_page 是最大的热点。

┌──────────────────────────────────────┐
│   连续大页分配大量时间花在验证区间   │
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐
│ 验证对复合页和高阶伙伴页做不必要迭代 │  某些页根本不可移动,却逐个检查
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐
│           单次分配耗时数秒           │  120 个 1G 大页要 3.6 秒
└──────────────────────────────────────┘

问题在于验证逻辑对很多本来不可移动的复合页(如不在 LRU 上的 THP、高阶 buddy 页)也逐个检查,做了大量无意义的迭代。这些页根本不能用于连续分配,却不早早跳过。在 114G 空闲内存的机器上,分配 120 个 1G HugeTLB folio 要花 3.6 秒。

问题

  • 连续大页分配大量时间花在逐页验证区间
  • 对不可移动的复合页和高阶伙伴页做不必要迭代
  • 替换空闲巨页时对巨页也做无意义的遍历
  • 120 个 1G 大页分配要 3.6 秒

方案

整条分配路径被同一种浪费拖慢:它对很多本就无法用于连续分配的页,也要逐页走完检查。

系列的全部改动遵循同一个原则:能在更早处判定无效,就尽早跳过,把时间留给真正可能成型的连续区间。这道“尽早跳过”在两个层面落地:跨过整段无效页,以及在源头短路掉注定空转的逻辑。

旧:逐页验证区间有效性
┌────────────────────────────────┐
│   复合页和高阶伙伴页逐个检查   │
└───────────────┬────────────────┘
                ▼
┌────────────────────────────────┐
│ 大量时间浪费在不可移动页的检查 │
└────────────────────────────────┘

新:新判别跳过无效迭代
┌──────────────────────────────────────┐
│ 新不可移动判别跳过复合页与高阶伙伴页 │
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐
│ 无空闲巨页则跳过替换;提前检查巨页特 │  多处分层短路,分配时间降到约 1/8
│ 殊分配区                             │
└──────────────────────────────────────┘

跨过整段无效页

区间验证循环是 87% 热点的所在,也是收益最大的改动。系列先把“一页是否不可移动”的判断从页面隔离逻辑里抽出来,单独成一个判定。这一步只是重构,不改变行为,却是后续优化的共用工具。验证循环据此改为按整段跨过复合页(如不在 LRU 上的 THP)和高阶 buddy 页,而不再逐页验证;这些页本就无法满足连续分配,原先逐个检查纯属空转,循环里占比最大的逐页在线检查也因此大幅减少。同一道判定随后复用到空闲巨页替换的遍历上,让替换路径同样跳过这些页。

在源头短路

另一组改动针对结果早已注定、却仍要完整跑一遍的逻辑。空闲巨页替换只有在系统真有空闲巨页时才有意义,没有就整段跳过;gigantic 巨页无论如何都不该被换走,替换路径因此只考察非 gigantic 巨页,并复用既有的“隔离或消解”判定拦住对 gigantic 巨页的误碰。CMA 分配路径原先无差别地试探 GFP 标志、遍历 nodemask,现在先确认启动期是否配置过 CMA 区域,没有就直接返回;顺带把两个 CMA 全局量标为启动后只读。它们在初始化期间赋值一次,之后永不改变。

收益

作者在 114G 空闲内存的机器上测试(分配 120×1G HugeTLB folios,104 个成功返回):

阶段 分配耗时 变化
Before(基线) 3.605s
区间验证优化后 0.602s ~83% 降幅
叠加巨页替换路径优化后 0.431s ~88% 降幅(约 8 倍提速)

核心优化叠加后,120 个 1G HugeTLB folio 的分配时间从 3.6 秒降到 0.43 秒,约 8 倍提速。分配路径上 87% 的逐页验证开销被消除,巨页分配效率大幅提升。