基于 DAMON 的 LRU 列表排序

基于 DAMON 的 LRU 列表排序 (DAMON_LRU_SORT) 是一个静态内核模块,旨在用于基于主动和轻量级数据访问模式(根据它们的 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 毫秒内执行超过 quota_ms 毫秒或 quota_sz 字节的 LRU 列表排序。

默认为 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 时间。它还要求如果系统的可用内存率超过 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