.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst

:Original: Documentation/admin-guide/mm/damon/reclaim.rst

:翻译:

 司延腾 Yanteng Si <siyanteng@loongson.cn>

:校译:

===============
基于DAMON的回收
===============

基于DAMON的回收（DAMON_RECLAIM）是一个静态的内核模块，旨在用于轻度内存压力下的主动和轻
量级的回收。它的目的不是取代基于LRU列表的页面回收，而是有选择地用于不同程度的内存压力和要
求。

哪些地方需要主动回收？
======================

在一般的内存超量使用（over-committed systems，虚拟化相关术语）的系统上，主动回收冷页
有助于节省内存和减少延迟高峰，这些延迟是由直接回收进程或kswapd的CPU消耗引起的，同时只产
生最小的性能下降 [1]_ [2]_ 。

基于空闲页报告 [3]_ 的内存过度承诺的虚拟化系统就是很好的例子。在这样的系统中，客户机
向主机报告他们的空闲内存，而主机则将报告的内存重新分配给其他客户。因此，系统的内存得到了充
分的利用。然而，客户可能不那么节省内存，主要是因为一些内核子系统和用户空间应用程序被设计为
使用尽可能多的内存。然后，客户机可能只向主机报告少量的内存是空闲的，导致系统的内存利用率下降。
在客户中运行主动回收可以缓解这个问题。

它是如何工作的？
================

DAMON_RECLAIM找到在特定时间内没有被访问的内存区域并分页。为了避免它在分页操作中消耗过多
的CPU，可以配置一个速度限制。在这个速度限制下，它首先分页出那些没有被访问过的内存区域。系
统管理员还可以配置在什么情况下这个方案应该自动激活和停用三个内存压力水位。

接口: 模块参数
==============

要使用这个功能，你首先要确保你的系统运行在一个以 ``CONFIG_DAMON_RECLAIM=y`` 构建的内
核上。

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

下面是每个参数的描述。

enabled
-------

启用或禁用DAMON_RECLAIM。

你可以通过把这个参数的值设置为 ``Y`` 来启用DAMON_RCLAIM，把它设置为 ``N`` 可以禁用
DAMON_RECLAIM。注意，由于基于水位的激活条件，DAMON_RECLAIM不能进行真正的监测和回收。
这一点请参考下面关于水位参数的描述。

commit_inputs
-------------

让 DAMON_RECLAIM 再次读取除 ``enabled`` 外的输入参数。

DAMON_RECLAIM 运行期间更新的输入参数默认不会应用。一旦该参数被设置为
``Y``，DAMON_RECLAIM 会再次读取除 ``enabled`` 外的参数值。重新读取完成后，
该参数会被设置为 ``N``。如果重新读取时发现无效参数，DAMON_RECLAIM 会被
禁用。

一旦向该参数写入 ``Y``，用户在再次读取 ``commit_inputs`` 返回 ``N`` 之前，
不得写入任何参数。如果用户违反该规则，内核可能表现出未定义行为。

min_age
-------

识别冷内存区域的时间阈值，单位是微秒。

如果一个内存区域在这个时间或更长的时间内没有被访问，DAMON_RECLAIM会将该区域识别为冷的，
并回收它。

默认为120秒。

autotune_monitoring_intervals
-----------------------------

如果该参数设置为 ``Y``，DAMON_RECLAIM 会自动调优 DAMON 的采样和聚集间隔。
自动调优的目标是在每个 DAMON 快照中捕获有意义数量的访问事件，同时将采样
间隔限制在最小 5 毫秒、最大 10 秒。将其设置为 ``N`` 会禁用自动调优。

默认禁用。

quota_ms
--------

回收的时间限制，以毫秒为单位。

DAMON_RECLAIM 试图在一个时间窗口（quota_reset_interval_ms）内只使用到这个时间，以
尝试回收冷页。这可以用来限制DAMON_RECLAIM的CPU消耗。如果该值为零，则该限制被禁用。

默认为10ms。

quota_sz
--------

回收的内存大小限制，单位为字节。

DAMON_RECLAIM 收取在一个时间窗口（quota_reset_interval_ms）内试图回收的内存量，并
使其不超过这个限制。这可以用来限制CPU和IO的消耗。如果该值为零，则限制被禁用。

默认情况下是128 MiB。

quota_reset_interval_ms
-----------------------

时间/大小配额收取重置间隔，单位为毫秒。

时间（quota_ms）和大小（quota_sz）的配额的目标重置间隔。也就是说，DAMON_RECLAIM在
尝试回收‘不’超过quota_ms毫秒或quota_sz字节的内存。

默认为1秒。

quota_mem_pressure_us
---------------------

期望的内存压力停滞时间水平，单位为微秒。

在保持其他配额设置的上限的同时，DAMON_RECLAIM 会自动增减配额的有效水平，
目标是产生该水平的内存压力。系统范围的 ``some`` 内存 PSI 会按每个配额重置
间隔（``quota_reset_interval_ms``）以微秒为单位收集，并与该值比较，以判断
目标是否满足。值为零表示禁用该自动调优功能。

默认禁用。

quota_autotune_feedback
-----------------------

用户可指定的有效配额自动调优反馈。

在保持其他配额设置的上限的同时，DAMON_RECLAIM 会自动增减配额的有效水平，
目标是从用户接收到值为 ``10,000`` 的反馈。DAMON_RECLAIM 假定反馈值和配额
成正比。值为零表示禁用该自动调优功能。

默认禁用。

wmarks_interval
---------------

当DAMON_RECLAIM被启用但由于其水位规则而不活跃时，在检查水位之前的最小等待时间。

wmarks_high
-----------

高水位的可用内存率（每千字节）。

如果系统的可用内存（以每千字节为单位）高于这个数值，DAMON_RECLAIM就会变得不活跃，所以
它什么也不做，只是定期检查水位。

wmarks_mid
----------

中间水位的可用内存率（每千字节）。

如果系统的空闲内存（以每千字节为单位）在这个和低水位线之间，DAMON_RECLAIM就会被激活，
因此开始监测和回收。

wmarks_low
----------

低水位的可用内存率（每千字节）。

如果系统的空闲内存（以每千字节为单位）低于这个数值，DAMON_RECLAIM就会变得不活跃，所以
它除了定期检查水位外什么都不做。在这种情况下，系统会退回到基于LRU列表的页面粒度回收逻辑。

sample_interval
---------------

监测的采样间隔，单位是微秒。

DAMON用于监测冷内存的采样间隔。更多细节请参考DAMON文档 (:doc:`usage`) 。

aggr_interval
-------------

监测的聚集间隔，单位是微秒。

DAMON对冷内存监测的聚集间隔。更多细节请参考DAMON文档 (:doc:`usage`)。

min_nr_regions
--------------

监测区域的最小数量。

DAMON用于冷内存监测的最小监测区域数。这可以用来设置监测质量的下限。但是，设
置的太高可能会导致监测开销的增加。更多细节请参考DAMON文档 (:doc:`usage`) 。

请注意，该值必须为 3 或更高。该下限的理由请参考设计文档的 :ref:`监测 <damon_design_monitoring_zh_CN>` 章节。

max_nr_regions
--------------

监测区域的最大数量。

DAMON用于冷内存监测的最大监测区域数。这可以用来设置监测开销的上限值。但是，
设置得太低可能会导致监测质量不好。更多细节请参考DAMON文档 (:doc:`usage`) 。

monitor_region_start
--------------------

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

DAMON_RECLAIM将对其进行工作的内存区域的起始物理地址。也就是说，DAMON_RECLAIM
将在这个区域中找到冷的内存区域并进行回收。默认情况下，该区域使用系统的整个物理内存。

monitor_region_end
------------------

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

DAMON_RECLAIM将对其进行工作的内存区域的末端物理地址。也就是说，DAMON_RECLAIM将
在这个区域内找到冷的内存区域并进行回收。默认情况下，该区域使用系统的整个物理内存。

addr_unit
---------

内存地址和字节数的缩放因子。

该参数用于设置和获取 DAMON_RECLAIM 的 DAMON 实例的 :ref:`地址单位 <damon_design_addr_unit_zh_CN>` 参数。

``monitor_region_start`` 和 ``monitor_region_end`` 应以该单位提供。例如，
假设 ``addr_unit``、``monitor_region_start`` 和 ``monitor_region_end``
分别设置为 ``1024``、``0`` 和 ``10``。那么 DAMON_RECLAIM 将处理从地址零
开始、长度为 10 KiB 的物理地址范围（以字节表示为
``[0 * 1024, 10 * 1024)``）。

``bytes_reclaim_tried_regions`` 和 ``bytes_reclaimed_regions`` 也使用该单位。
例如，假设 ``addr_unit``、``bytes_reclaim_tried_regions`` 和
``bytes_reclaimed_regions`` 的值分别为 ``1024``、``42`` 和 ``32``。那么这
表示 DAMON_RECLAIM 总共尝试回收 42 KiB 内存，并成功回收了 32 KiB 内存。

如果不确定，只使用默认值（``1``）并忘记这个参数即可。

skip_anon
---------

跳过匿名页回收。

如果该参数设置为 ``Y``，DAMON_RECLAIM 不会回收匿名页。默认值为 ``N``。


kdamond_pid
-----------

DAMON线程的PID。

如果DAMON_RECLAIM被启用，这将成为工作线程的PID。否则，为-1。

nr_reclaim_tried_regions
------------------------

试图通过DAMON_RECLAIM回收的内存区域的数量。

bytes_reclaim_tried_regions
---------------------------

试图通过DAMON_RECLAIM回收的内存区域的总字节数。

nr_reclaimed_regions
--------------------

通过DAMON_RECLAIM成功回收的内存区域的数量。

bytes_reclaimed_regions
-----------------------

通过DAMON_RECLAIM成功回收的内存区域的总字节数。

nr_quota_exceeds
----------------

超过时间/空间配额限制的次数。

例子
====

下面的运行示例命令使DAMON_RECLAIM找到30秒或更长时间没有访问的内存区域并“回收”？
为了避免DAMON_RECLAIM在分页操作中消耗过多的CPU时间，回收被限制在每秒1GiB以内。
它还要求DAMON_RECLAIM在系统的可用内存率超过50%时不做任何事情，但如果它低于40%时
就开始真正的工作。如果DAMON_RECLAIM没有取得进展，因此空闲内存率低于20%，它会要求
DAMON_RECLAIM再次什么都不做，这样我们就可以退回到基于LRU列表的页面粒度回收了::

    # cd /sys/module/damon_reclaim/parameters
    # echo 30000000 > min_age
    # echo $((1 * 1024 * 1024 * 1024)) > quota_sz
    # echo 1000 > quota_reset_interval_ms
    # echo 500 > wmarks_high
    # echo 400 > wmarks_mid
    # echo 200 > wmarks_low
    # echo Y > enabled

请注意，该模块（damon_reclaim）不能与其他基于 DAMON 的专用模块同时运行。
更多细节请参考 :ref:`DAMON 设计文档的专用模块互斥性 <damon_design_special_purpose_modules_exclusivity_zh_CN>`。

.. [1] https://research.google/pubs/pub48551/
.. [2] https://lwn.net/Articles/787611/
.. [3] https://www.kernel.org/doc/html/latest/mm/free_page_reporting.html
