基于 DAMON 的 LRU 列表排序

基于 DAMON 的 LRU 列表排序 (DAMON_LRU_SORT) 是一个静态内核模块,旨在用于基于数据访问模式(de)优先级的主动和轻量级页面在其 LRU 列表上,以使 LRU 列表成为更值得信赖的数据访问模式来源。

在何处需要主动 LRU 列表排序?

由于页面粒度访问检查开销在大型系统上可能很大,因此 LRU 列表通常不会主动排序,而是部分和被动地针对特殊事件进行排序,包括特定用户请求、系统调用和内存压力。因此,有时 LRU 列表并没有很好地准备好用作某些情况(包括在突然内存压力下回收目标页面选择)的可靠访问模式来源。

由于 DAMON 可以识别最佳精度的访问模式,同时仅引发用户指定的开销范围,因此主动运行 DAMON_LRU_SORT 可能有助于使 LRU 列表成为更值得信赖的低且可控开销的访问模式来源。

它是如何工作的?

DAMON_LRU_SORT 使用 DAMON 查找热页面(显示高于用户指定阈值的访问速率的内存区域的页面)和冷页面(显示在超过用户指定的时间内没有访问的内存区域的页面),并优先处理热页面,同时降低其 LRU 列表上的冷页面的优先级。为了避免它消耗过多的 CPU 用于优先级排序,可以配置 CPU 时间使用限制。在该限制下,它分别优先处理和降低更多热页面和冷页面的优先级。系统管理员还可以配置在此方案应在三种内存压力水位线的情况下自动激活和停用。

其热/冷阈值和 CPU 配额限制的默认参数经过保守选择。也就是说,默认参数下的模块可以广泛使用而不会对常见情况造成损害,同时为在内存压力下具有清晰的热/冷访问模式的系统提供一定程度的优势,同时仅消耗有限的一小部分 CPU 时间。

接口:模块参数

要使用此功能,您应该首先确保您的系统运行在构建了 CONFIG_DAMON_LRU_SORT=y 的内核上。

为了让系统管理员启用或禁用它并针对给定系统进行调整,DAMON_LRU_SORT 利用了模块参数。也就是说,您可以将 damon_lru_sort.<parameter>=<value> 放在内核启动命令行上,或将适当的值写入 /sys/module/damon_lru_sort/parameters/<parameter> 文件。

以下是每个参数的描述。

enabled

启用或禁用 DAMON_LRU_SORT。

您可以通过将此参数的值设置为 Y 来启用 DAMON_LRU_SORT。将其设置为 N 会禁用 DAMON_LRU_SORT。请注意,由于基于水位线的激活条件,DAMON_LRU_SORT 可能不会进行真正的监控和 LRU 列表排序。有关此水位线参数,请参阅以下说明。

commit_inputs

使 DAMON_LRU_SORT 再次读取输入参数,除了 enabled

默认情况下,DAMON_LRU_SORT 运行时更新的输入参数不会应用。一旦此参数设置为 Y,DAMON_LRU_SORT 会再次读取参数的值,除了 enabled。重新读取完成后,此参数将设置为 N。如果在重新读取时发现无效参数,DAMON_LRU_SORT 将被禁用。

hot_thres_access_freq

用于识别热内存区域的访问频率阈值,以千分比表示。

如果内存区域以该频率或更高的频率被访问,DAMON_LRU_SORT 会将该区域识别为热,并在 LRU 列表上将其标记为已访问,这样它就不会在内存压力下被回收。默认值为 50%。

cold_min_age

用于识别冷内存区域的时间阈值,以微秒为单位。

如果内存区域在该时间或更长时间内未被访问,DAMON_LRU_SORT 会将该区域识别为冷,并在 LRU 列表上将其标记为未访问,这样它就可以在内存压力下首先被回收。默认值为 120 秒。

quota_ms

尝试 LRU 列表排序的时间限制,以毫秒为单位。

DAMON_LRU_SORT 尝试在时间窗口 (quota_reset_interval_ms) 内仅使用最多此时间来尝试 LRU 列表排序。这可用于限制 DAMON_LRU_SORT 的 CPU 消耗。如果该值为零,则禁用该限制。

默认值为 10 毫秒。

quota_reset_interval_ms

时间配额充电重置间隔,以毫秒为单位。

时间配额 (quota_ms) 的充电重置间隔。也就是说,DAMON_LRU_SORT 不会尝试在 quota_reset_interval_ms 毫秒内对 LRU 列表进行超过 quota_ms 毫秒或 quota_sz 字节的排序。

默认值为 1 秒。

wmarks_interval

水位线检查时间间隔,以微秒为单位。

等待检查水位线的最小时间,当 DAMON_LRU_SORT 由于其水位线规则而启用但未激活时。默认值为 5 秒。

wmarks_high

高水位线的可用内存率(每千)。

如果系统的可用内存(以每千字节的字节数为单位)高于此值,则 DAMON_LRU_SORT 变为非活动状态,因此它什么也不做,只会定期检查水位线。默认值为 200 (20%)。

wmarks_mid

中间水位线的可用内存率(每千)。

如果系统的可用内存(以每千字节的字节数为单位)介于此值和低水位线之间,则 DAMON_LRU_SORT 变为活动状态,因此开始监控和 LRU 列表排序。默认值为 150 (15%)。

wmarks_low

低水位线的可用内存率(每千)。

如果系统的可用内存(以每千字节的字节数为单位)低于此值,则 DAMON_LRU_SORT 变为非活动状态,因此它什么也不做,只会定期检查水位线。默认值为 50 (5%)。

sample_interval

监控的采样间隔,以微秒为单位。

DAMON 用于冷内存监控的采样间隔。有关更多详细信息,请参阅 DAMON 文档 (详细用法)。默认值为 5 毫秒。

aggr_interval

监控的聚合间隔,以微秒为单位。

DAMON 用于冷内存监控的聚合间隔。有关更多详细信息,请参阅 DAMON 文档 (详细用法)。默认值为 100 毫秒。

min_nr_regions

最小监控区域数。

DAMON 用于冷内存监控的最小监控区域数。这可用于设置监控质量的下限。但是,将其设置得太高可能会导致监控开销增加。有关更多详细信息,请参阅 DAMON 文档 (详细用法)。默认值为 10。

max_nr_regions

最大监控区域数。

DAMON 用于冷内存监控的最大监控区域数。这可用于设置监控开销的上限。但是,将其设置得太低可能会导致监控质量不佳。有关更多详细信息,请参阅 DAMON 文档 (详细用法)。默认值为 1000。

monitor_region_start

目标内存区域的起始物理地址。

DAMON_LRU_SORT 将对其执行工作的内存区域的起始物理地址。默认情况下,最大的系统 RAM 用作该区域。

monitor_region_end

目标内存区域的结束物理地址。

DAMON_LRU_SORT 将对其执行工作的内存区域的结束物理地址。默认情况下,最大的系统 RAM 用作该区域。

kdamond_pid

DAMON 线程的 PID。

如果启用了 DAMON_LRU_SORT,则这成为工作线程的 PID。否则,为 -1。

nr_lru_sort_tried_hot_regions

尝试进行 LRU 排序的热内存区域的数量。

bytes_lru_sort_tried_hot_regions

尝试进行 LRU 排序的热内存区域的总字节数。

nr_lru_sorted_hot_regions

成功进行 LRU 排序的热内存区域的数量。

bytes_lru_sorted_hot_regions

成功进行 LRU 排序的热内存区域的总字节数。

nr_hot_quota_exceeds

热区域的时间配额限制超过的次数。

nr_lru_sort_tried_cold_regions

尝试进行 LRU 排序的冷内存区域的数量。

bytes_lru_sort_tried_cold_regions

尝试进行 LRU 排序的冷内存区域的总字节数。

nr_lru_sorted_cold_regions

成功进行 LRU 排序的冷内存区域的数量。

bytes_lru_sorted_cold_regions

成功进行 LRU 排序的冷内存区域的总字节数。

nr_cold_quota_exceeds

冷区域的时间配额限制超过的次数。

示例

以下运行时示例命令使 DAMON_LRU_SORT 查找具有 >= 50% 访问频率的内存区域并进行 LRU 优先级排序,同时对 120 秒未访问的内存区域进行 LRU 降级。优先级排序和降级被限制为仅使用高达 1% 的 CPU 时间来完成,以避免 DAMON_LRU_SORT 消耗过多的 CPU 时间用于(de)优先级排序。如果系统的可用内存率超过 50%,它还会要求 DAMON_LRU_SORT 不执行任何操作,但如果低于 40%,则开始实际工作。如果 DAMON_RECLAIM 没有取得进展,因此可用内存率低于 20%,它会再次要求 DAMON_LRU_SORT 不执行任何操作,这样我们就可以回退到基于 LRU 列表的页面粒度回收。

# cd /sys/module/damon_lru_sort/parameters
# echo 500 > hot_thres_access_freq
# echo 120000000 > cold_min_age
# echo 10 > quota_ms
# echo 1000 > quota_reset_interval_ms
# echo 500 > wmarks_high
# echo 400 > wmarks_mid
# echo 200 > wmarks_low
# echo Y > enabled