多代 LRU

多代 LRU 是一种替代的 LRU 实现,它优化了页回收并在内存压力下提高了性能。页回收决定了内核的缓存策略以及过度使用内存的能力。它直接影响 kswapd 的 CPU 使用率和 RAM 效率。

快速开始

使用以下配置构建内核。

  • CONFIG_LRU_GEN=y

  • CONFIG_LRU_GEN_ENABLED=y

准备就绪!

运行时选项

/sys/kernel/mm/lru_gen/ 包含以下小节中描述的稳定 ABI。

禁用开关

enabled 接受不同的值来启用或禁用以下组件。其默认值取决于 CONFIG_LRU_GEN_ENABLED。除非其中一些有不可预见的副作用,否则所有组件都应该被启用。当硬件不支持某个组件时,写入到 enabled 不起作用;即使主开关关闭,有效值也会被接受。

组件

0x0001

多代 LRU 的主开关。

0x0002

当 MMU 设置访问位时(例如,在 x86 上),以大批量方式清除叶页表项中的访问位。这种行为理论上会加剧锁竞争(mmap_lock)。如果禁用它,对于连续映射热页的工作负载,多代 LRU 的性能将略微下降,因为它们的访问位原本可以通过更少、更大的批次清除。

0x0004

当 MMU 设置访问位时(例如,在 x86 上),同样清除非叶页表项中的访问位。这种行为尚未在 Intel 和 AMD 之外的 x86 变体上验证。如果禁用它,多代 LRU 的性能下降将可以忽略不计。

[yYnN]

应用于上述所有组件。

例如,

echo y >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0007
echo 5 >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0005

内存抖动预防

个人电脑对内存抖动更敏感,因为它会导致卡顿(渲染 UI 时的延迟)并对用户体验产生负面影响。多代 LRU 为大多数没有 oomd 的笔记本和桌面用户提供了内存抖动预防功能。

用户可以向 min_ttl_ms 写入 N 来防止 N 毫秒的工作集被驱逐。如果这个工作集无法保留在内存中,OOM killer 将被触发。换句话说,此选项可作为可调节的泄压阀,开启后,它会终止那些可能未被使用的应用程序。

根据人类平均可察觉的延迟(约 100 毫秒),N=1000 通常可以消除因内存抖动引起的无法忍受的卡顿。较大的值,例如 N=3000,会使卡顿不那么明显,但存在过早触发 OOM 杀死的风险。

默认值 0 表示禁用。

实验性功能

/sys/kernel/debug/lru_gen 接受以下小节中描述的命令。支持多条命令行,也支持使用分隔符 ,; 进行连接。

/sys/kernel/debug/lru_gen_full 提供额外的统计信息用于调试。CONFIG_LRU_GEN_STATS=y 将被驱逐世代的历史统计信息保留在此文件中。

工作集估算

工作集估算衡量一个应用程序在给定时间间隔内需要多少内存,并且通常对应用程序的性能影响很小。例如,数据中心希望优化作业调度(装箱)以提高内存利用率。当一个新作业到来时,作业调度程序需要确定其管理的每台服务器是否可以为这个新作业分配一定量的内存,然后才能选择一个候选。为此,作业调度程序需要估算现有作业的工作集。

读取时,lru_gen 返回一个在不同时间间隔内访问的页数的直方图,针对每个 memcg 和节点。MAX_NR_GENS 决定了每个直方图的 bin 数量。这些直方图是非累积的。

memcg  memcg_id  memcg_path
   node  node_id
       min_gen_nr  age_in_ms  nr_anon_pages  nr_file_pages
       ...
       max_gen_nr  age_in_ms  nr_anon_pages  nr_file_pages

每个 bin 包含一个估计的页数,这些页在 age_in_ms 内被访问过。例如,min_gen_nr 包含最冷的页,而 max_gen_nr 包含最热的页,因为前者的 age_in_ms 最大,后者的最小。

用户可以向 lru_gen 写入以下命令,以创建新的世代 max_gen_nr+1

+ memcg_id node_id max_gen_nr [can_swap [force_scan]]

can_swap 默认为 swap 设置,如果将其设置为 1,则在 swap 关闭时强制扫描匿名页,反之亦然。force_scan 默认为 1,如果将其设置为 0,则它会采用启发式方法来减少开销,这可能也会降低覆盖率。

一个典型的用例是,作业调度程序在某个时间间隔运行此命令以创建新的世代,并根据此时间间隔定义的冷页大小对其管理的服务器进行排名。

主动回收

主动回收会在没有内存压力时触发页回收。它通常只针对冷页。例如,当一个新作业到来时,作业调度程序希望在其选择的服务器上主动回收冷页,以提高成功部署此新作业的机会。

用户可以向 lru_gen 写入以下命令,以驱逐小于或等于 min_gen_nr 的世代。

- memcg_id node_id min_gen_nr [swappiness [nr_to_reclaim]]

min_gen_nr 应该小于 max_gen_nr-1,因为 max_gen_nrmax_gen_nr-1 尚未完全老化(相当于活动列表),因此不能被驱逐。swappiness 覆盖了 /proc/sys/vm/swappiness 中的默认值,有效范围是 [0-200, max],其中 max 专门用于回收匿名内存。nr_to_reclaim 限制了要驱逐的页数。

一个典型的用例是,作业调度程序在尝试将新作业部署到服务器之前运行此命令。如果由于过度估算而未能具体化足够的冷页,它会根据从工作集估算步骤中获得的排名结果在下一台服务器上重试。这种力度较小的方法限制了对现有作业的影响。