read() 读文件
先去 page cache 找 folio
filemap_get_read_batch()
服务常规读,一次收一批
filemap_get_folios_contig()
服务连续段收集
两个函数都靠 xarray 迭代器逐个走
xas_load() 取 folio → 装批 → xas_next() / xas_advance() 前进
本该走到读请求范围的末端为止
一次读只关心一段 index 范围
从 start 开始,收到 max 就够;范围之外的一页都不需要
旧循环:先前进,再查边界
xarray 里的 folio 按 index 排开
folio 0
folio 1
folio 2
folio 3
folio 4
所需范围结束
多走的一步
max 边界
多出来的一步,包含三样东西
一次 xarray 查找
一次边界判断
一次分支
这一趟对结果没有任何贡献
边界判断本身没错,错在它出现得太晚
小读 · 通常只取一个 folio
读 1 个 folio 也要
多走一次迭代器前进
一次有效读取,配一次无效前进
大读 · 收一整批
批量再大,收尾前
仍要多走一轮 xarray 查找
收尾这一步省不掉
共同点:拿到最后一个所需 folio 之后,循环还要再走一步
差别只在占比:小读摊得最狠,大读被批量稀释
这一步不产生任何新 folio
小读、大读,都得为它付一次查找
新写法:先查边界,到位就收工
最后一个所需 folio
先查边界
是否已到 max
直接退出循环
不再多走一步
filemap_get_read_batch()
入口先查 index 越界即返回
xas_advance() 到达或越过 max 就 break
循环条件里原来的越界检查删掉
filemap_get_folios_contig()
入口先查 start 越界
边界判断挪到 xas_next() 之前
同一手法,同一个效果
两处改动合起来只做一件事
让「最后一个 folio」成为循环的最后一次查找
快路径上不再有多余查找与分支
边界前移,会不会让 put 后重试误判?
XAS_RESTART 状态
xas_next() 不更新 xa_index
重试看到的 index 不变
边界值没变,不会误判越界
所以安全性没有打折
变的是检查时机,不是判据:index 还是那个 index,max 还是那个 max
只把检查挪前,不改边界值
语义不变,少走一步
4k 读测试 · filemap_get_read_batch() 函数级开销占比
Before
2.91%
After
2.53%
省下的是一次查找、一次边界判断与一次分支
落在读路径的快路径上
占比是函数级开销,不是端到端吞吐
改动只有一类:边界检查从「前进之后」挪到「前进之前」
小读少一次前进,大读少一轮查找
filemap_get_read_batch():2.91% → 2.53%
两个函数同改,语义一行没动
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x