背景

vmalloc 在做大映射(如 huge mapping)时会向 buddy 申请高阶页,紧接着 split_page 把它拆成 order-0,以兼容需要访问底层 struct page 的用户。最近一个改动(a06157804399,让 vmalloc 更倾向申请高阶页)本意是省事,却带来了回归:高阶页从 buddy 取走、拆成 order-0,释放时只能逐页归还到 order-0 的 per-CPU 缓存(pcp)。而过去直接申请 order-0 页是从 pcp 回收的,现在这条快路径断了,紧密的 vmalloc/vfree 循环就明显变慢。

┌───────────────────────────────┐
│   分配高阶页后拆成 order-0    │
└───────────────┬───────────────┘
                ▼
┌───────────────────────────────┐
│ 释放时逐页归还到 order-0 缓存 │  高阶页的回收优势丢了,释放慢
└───────────────┬───────────────┘
                ▼
┌───────────────────────────────┐
│  紧密的分配释放循环显著回归   │
└───────────────────────────────┘

作者同时注意到,page_alloc 里的 free_contig_range(CMA 等连续页释放路径)做的本质是同一件事:把一段连续 order-0 页归还给分配器,旧实现同样是逐页 loop 释放。

问题

  • vmalloc 高阶页拆成 order-0 后逐页释放
  • 释放到 order-0 pcp,高阶回收优势丢失
  • 紧密的 vmalloc/vfree 循环显著回归
  • free_contig_range 等路径同样逐页释放

方案

核心是把"一整段连续 order-0 页"当作一批来释放,而不是逐页 loop。

旧:逐页释放到 order-0 缓存
┌────────────────────────────┐
│  连续 order-0 页逐个释放   │
└─────────────┬──────────────┘
              ▼
┌────────────────────────────┐
│ 高阶块被打散,回收优势丢失 │
└────────────────────────────┘

新:连续页按最大块批量释放
┌────────────────────────────────┐
│     连续范围切成最大对齐块     │
└───────────────┬────────────────┘
                ▼
┌────────────────────────────────┐
│ 整块归还高阶缓存,恢复回收优势 │  vmalloc 经批量接口释放连续页
└────────────────────────────────┘

具体做法是把待释放的连续 order-0 范围,分解成若干个尽可能大、且自然对齐的 2 的幂块。每个 order-0 页仍要单独递减引用计数、单独走 free_pages_prepare 维护 struct page 状态与全局记账;但这些都做完后,得到的不再是散落的 order-0 页,而是一组高阶块,可以整块归还给 pcp 或 buddy。这既快得多,还顺带让高阶块留在 pcp、内存更易以高阶形式被再次取用。

vmalloc 这条回归路径由一个新的批量释放接口落地:它把连续 pfn 范围批量归还(底层复用优化后的连续范围释放例程),让 vmalloc 申请 order-3 页时也能把 order-3 页归还到 order-3 pcp,恢复(并超越)原来的回收优势。CMA 等连续页释放路径与冻结连续页的释放路径,原本同样逐页释放,也一并改成批量。

实现上还要确认连续范围落在同一 section(memdesc_section,未启用时 if 条件被编译器优化掉)。

收益

作者在 arm64 服务器级机器上测了 page_alloc_high_order_test(反复 alloc 高阶页 + split + free_contig_range,10 万次):

指标 Before After
执行时间 4,097,358 us 729,831 us(约 5.6 倍)

并用 test_vmalloc 跑了三组对比(v6.18 baseline / mm-new 含致回归改动 / this series),下表选列 this series 相对 v6.18 的变化(>0 更快,(I) 统计显著改进):

场景 this series vs v6.18
fix_size_alloc_test p:16 h:1 +15.75% (I)
fix_size_alloc_test p:64 h:0 +9.05% (I)
fix_size_alloc_test p:64 h:1 +38.45% (I)
fix_size_alloc_test p:256 h:1 +38.61% (I)
fix_size_alloc_test p:512 h:1 +49.21% (I)
long_busy_list_alloc_test p:1 +4.63% (I)
vm_map_ram_test p:1 +4.98% (I)

多数高并发大块场景统计显著提升 +9%~+49%;个别场景(如 fix_align_alloc_test p:1)仍残留约 -14% 的小回归,但相较 mm-new 的 -50% 已大幅缓解。整体而言,本系列平均缓解了回归,并相对 baseline 给出 -14% 到 +49% 的区间。