背景
MGLRU 在回收与老化之间有一个反馈环:shrink_folio_list() 走 rmap 反查时发现 young PTE,lru_gen_look_around() 顺势扫描同一 PMD 下的相邻 PTE,利用空间局部性把命中的热 folio 晋升到新 generation。
这段扫描有成本,值不值得下轮再扫由 young 计数裁决:循环数出窗口内扫过的 PTE 总数与其中 young 的数量,suitable_to_scan() 按「平均每条 cacheline 至少 1 个 young PTE」判定,通过则把指向这张 PTE 表的 PMD 加进 bloom filter,下轮 aging 的页表遍历复查它。
look-around 反馈环
┌────────────────────────────────────────┐
│ rmap 发现 young PTE 之后,look-around │
│ 顺势扫同 PMD 相邻 PTE │
└───────────────────┬────────────────────┘
▼
┌────────────────────────────────────────┐
│ 热 folio 晋升新 generation,循环累计 │
│ 窗口内 young 计数 │
└───────────────────┬────────────────────┘
▼
┌────────────────────────────────────────┐
│ young 足够密集则 PMD 进 bloom filter, │
│ 下轮 aging 复查 │
└────────────────────────────────────────┘
PTE 批量化之后,循环里每个 young folio 按批量计 young += nr,nr 是它在这张 PTE 表里连续映射的 PTE 数。
问题
- 触发 look-around 的 folio 在函数入口清过 accessed 位,循环不会再数它
- 它的贡献固定按 young=1 初始化,large folio 少计 nr-1
- 少计使 suitable_to_scan() 误判,PMD 进不了 bloom filter,下轮 aging 不复查
- 仍有热 folio 的 PMD 被漏过,热 folio 可能被误回收
方案
把 young 的初值从 1 改为 nr:触发 folio 与循环里其他 young folio 按同一口径批量计数。
- int young = 1;
+ int young = nr;
触发 folio 与其余 folio 同一口径
┌────────────────────────────────────────┐
│ 入口清触发 folio 的 accessed 位,young │
│ 初值给批量大小 nr │
└───────────────────┬────────────────────┘
▼
┌────────────────────────────────────────┐
│ 循环扫窗口,其余 young folio 按 young │
│ += nr 批量计 │
└───────────────────┬────────────────────┘
▼
┌────────────────────────────────────────┐
│ 口径统一,热 PMD 正常进 bloom filter │
└────────────────────────────────────────┘
初值给 nr 是刻意高估而非实测:test_and_clear_young_ptes_notify() 只报告 nr 个 PTE 中是否有 young,不报具体几个。mm 核心本来就按 folio 粒度跟踪 accessed 状态,逐页计数既不可得也无意义。唯一消费者是 suitable_to_scan(),它喂的 bloom filter 容忍误差。高估是安全方向:顶多让访问少的 PMD 被多扫一轮,低估才会漏掉仍热的 PMD 造成误回收。
收益
作者未提供性能数据,从代码逻辑推断的预期收益:
- large folio 的 young 贡献与全窗口同一口径,mTHP 负载下 aging 准确性恢复
- 仍有热 folio 的 PMD 正常进 bloom filter 接受复查,减少误回收
- 高估方向安全,bloom filter 容忍误差,代价至多 PMD 多扫一轮