Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,29 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/index.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
============
监测数据访问
============
:doc:`DAMON </mm/damon/index>` 允许轻量级的数据访问监测。使用DAMON,
用户可以分析他们系统的内存访问模式,并优化它们。
.. toctree::
:maxdepth: 2
start
usage
reclaim
lru_sort
@@ -0,0 +1,263 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/lru_sort.rst
:翻译:
臧雷刚 Leigang Zang <zangleigang@hisilicon.com>
:校译:
==================
基于DAMON的LRU排序
==================
基于DAMON的LRU排序是一个静态的内核模块,旨在用于以主动的、轻量级的数据访问模型
为基础的页面优先级处理的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/modules/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进行排序。这个可以用来作为CPU计算资源的约束。如果值为0,则表示无限制。
默认10毫秒。
quota_reset_interval_ms
-----------------------
配额计时重置周期,毫秒。
配额计时重置周期。即,在quota_reset_interval_ms毫秒内,DAMON_LRU_SORT对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文档 (:doc:`usage`) 。默认5
毫秒。
aggr_interval
-------------
监测的收集周期,微秒。
DAMON对冷内存进行收集的时间周期。更多细节请参考DAMON文档 (:doc:`usage`) 。默认
100毫秒。
min_nr_regions
--------------
最小监测区域数量。
对冷内存区域监测的最小数量。这个值可以作为监测质量的下限。不过,这个值设置的过
大会增加开销。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为10。
max_nr_regions
--------------
最大监测区域数量。
对冷内存区域监测的最大数量。这个值可以作为监测质量的上限。然而,这个值设置的过
低会导致监测结果变差。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为1000。
monitor_region_start
--------------------
目标内存区域的起始物理地址。
DAMON_LRU_SORT要处理的目标内存区域的起始物理地址。默认,使用系统最大内存。
monitor_region_end
------------------
目标内存区域的结束物理地址。
DAMON_LRU_SORT要处理的目标内存区域的结束物理地址。默认,使用系统最大内存。
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
---------------------
冷区域时间约束超过限制的次数。
Example
=======
如下是一个运行时的命令示例,使DAMON_LRU_SORT查找访问频率超过50%的区域并对其进行
LRU的优先级的提升,同时降低那些超过120秒无人访问的内存区域的优先级。优先级的处
理被限制在最多1%的CPU以避免DAMON_LRU_SORT消费过多CPU时间。在系统空闲内存超过50%
时DAMON_LRU_SORT停止工作,并在低于40%时重新开始工作。如果DAMON_RECLAIM没有取得
进展且空闲内存低于20%,再次让DAMON_LRU_SORT停止工作,以此回退到以LRU链表为基础
以页面为单位的内存回收上。 ::
# cd /sys/modules/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
@@ -0,0 +1,228 @@
.. 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不能进行真正的监测和回收。
这一点请参考下面关于水位参数的描述。
min_age
-------
识别冷内存区域的时间阈值,单位是微秒。
如果一个内存区域在这个时间或更长的时间内没有被访问,DAMON_RECLAIM会将该区域识别为冷的,
并回收它。
默认为120秒。
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秒。
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`) 。
max_nr_regions
--------------
监测区域的最大数量。
DAMON用于冷内存监测的最大监测区域数。这可以用来设置监测开销的上限值。但是,
设置得太低可能会导致监测质量不好。更多细节请参考DAMON文档 (:doc:`usage`) 。
monitor_region_start
--------------------
目标内存区域的物理地址起点。
DAMON_RECLAIM将对其进行工作的内存区域的起始物理地址。也就是说,DAMON_RECLAIM
将在这个区域中找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
monitor_region_end
------------------
目标内存区域的结束物理地址。
DAMON_RECLAIM将对其进行工作的内存区域的末端物理地址。也就是说,DAMON_RECLAIM将
在这个区域内找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
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
.. [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
@@ -0,0 +1,124 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/start.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
========
入门指南
========
本文通过演示DAMON的默认用户空间工具,简要地介绍了如何使用DAMON。请注意,为了简洁
起见,本文档只描述了它的部分功能。更多细节请参考该工具的使用文档。
`doc <https://github.com/damonitor/damo/blob/next/USAGE.md>`_ .
前提条件
========
内核
----
首先,你要确保你当前系统中跑的内核构建时选定了这个功能选项 ``CONFIG_DAMON_*=y``.
用户空间工具
------------
在演示中,我们将使用DAMON的默认用户空间工具,称为DAMON Operator(DAMO)。它可以在
https://github.com/damonitor/damo找到。下面的例子假设DAMO在你的$PATH上。当然,但
这并不是强制性的。
因为DAMO使用了DAMON的sysfs接口(详情请参考:doc:`usage`),你应该确保
:doc:`sysfs </filesystems/sysfs>` 被挂载。
记录数据访问模式
================
下面的命令记录了一个程序的内存访问模式,并将监测结果保存到文件中。 ::
$ git clone https://github.com/sjp38/masim
$ cd masim; make; ./masim ./configs/zigzag.cfg &
$ sudo damo record -o damon.data $(pidof masim)
命令的前两行下载了一个人工内存访问生成器程序并在后台运行。生成器将重复地逐一访问两个
100 MiB大小的内存区域。你可以用你的真实工作负载来代替它。最后一行要求 ``damo`` 将
访问模式记录在 ``damon.data`` 文件中。
将记录的模式可视化
==================
你可以在heatmap中直观地看到这种模式,显示哪个内存区域(X轴)何时被访问(Y轴)以及访
问的频率(数字)。::
$ sudo damo report heats --heatmap stdout
22222222222222222222222222222222222222211111111111111111111111111111111111111100
44444444444444444444444444444444444444434444444444444444444444444444444444443200
44444444444444444444444444444444444444433444444444444444444444444444444444444200
33333333333333333333333333333333333333344555555555555555555555555555555555555200
33333333333333333333333333333333333344444444444444444444444444444444444444444200
22222222222222222222222222222222222223355555555555555555555555555555555555555200
00000000000000000000000000000000000000288888888888888888888888888888888888888400
00000000000000000000000000000000000000288888888888888888888888888888888888888400
33333333333333333333333333333333333333355555555555555555555555555555555555555200
88888888888888888888888888888888888888600000000000000000000000000000000000000000
88888888888888888888888888888888888888600000000000000000000000000000000000000000
33333333333333333333333333333333333333444444444444444444444444444444444444443200
00000000000000000000000000000000000000288888888888888888888888888888888888888400
[...]
# access_frequency: 0 1 2 3 4 5 6 7 8 9
# x-axis: space (139728247021568-139728453431248: 196.848 MiB)
# y-axis: time (15256597248362-15326899978162: 1 m 10.303 s)
# resolution: 80x40 (2.461 MiB and 1.758 s for each character)
你也可以直观地看到工作集的大小分布,按大小排序。::
$ sudo damo report wss --range 0 101 10
# <percentile> <wss>
# target_id 18446632103789443072
# avr: 107.708 MiB
0 0 B | |
10 95.328 MiB |**************************** |
20 95.332 MiB |**************************** |
30 95.340 MiB |**************************** |
40 95.387 MiB |**************************** |
50 95.387 MiB |**************************** |
60 95.398 MiB |**************************** |
70 95.398 MiB |**************************** |
80 95.504 MiB |**************************** |
90 190.703 MiB |********************************************************* |
100 196.875 MiB |***********************************************************|
在上述命令中使用 ``--sortby`` 选项,可以显示工作集的大小是如何按时间顺序变化的。::
$ sudo damo report wss --range 0 101 10 --sortby time
# <percentile> <wss>
# target_id 18446632103789443072
# avr: 107.708 MiB
0 3.051 MiB | |
10 190.703 MiB |***********************************************************|
20 95.336 MiB |***************************** |
30 95.328 MiB |***************************** |
40 95.387 MiB |***************************** |
50 95.332 MiB |***************************** |
60 95.320 MiB |***************************** |
70 95.398 MiB |***************************** |
80 95.398 MiB |***************************** |
90 95.340 MiB |***************************** |
100 95.398 MiB |***************************** |
数据访问模式感知的内存管理
==========================
以下三个命令使每一个大小>=4K的内存区域在你的工作负载中没有被访问>=60秒,就会被换掉。 ::
$ echo "#min-size max-size min-acc max-acc min-age max-age action" > test_scheme
$ echo "4K max 0 0 60s max pageout" >> test_scheme
$ damo schemes -c test_scheme <pid of your workload>
@@ -0,0 +1,345 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/usage.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
========
详细用法
========
DAMON 为不同的用户提供了下面这些接口。
- *DAMON用户空间工具。*
`这 <https://github.com/damonitor/damo>`_ 为有这特权的人, 如系统管理员,希望有一个刚好
可以工作的人性化界面。
使用它,用户可以以人性化的方式使用DAMON的主要功能。不过,它可能不会为特殊情况进行高度调整。
它同时支持虚拟和物理地址空间的监测。更多细节,请参考它的 `使用文档
<https://github.com/damonitor/damo/blob/next/USAGE.md>`_。
- *sysfs接口。*
:ref:`这 <sysfs_interface>` 是为那些希望更高级的使用DAMON的特权用户空间程序员准备的。
使用它,用户可以通过读取和写入特殊的sysfs文件来使用DAMON的主要功能。因此,你可以编写和使
用你个性化的DAMON sysfs包装程序,代替你读/写sysfs文件。 `DAMON用户空间工具
<https://github.com/damonitor/damo>`_ 就是这种程序的一个例子 它同时支持虚拟和物理地址
空间的监测。
- *内核空间编程接口。*
:doc:`这 </mm/damon/api>` 这是为内核空间程序员准备的。使用它,用户可以通过为你编写内
核空间的DAMON应用程序,最灵活有效地利用DAMON的每一个功能。你甚至可以为各种地址空间扩展DAMON。
详细情况请参考接口 :doc:`文件 </mm/damon/api>`。
sysfs接口
=========
DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其sysfs目录下创建多
个目录和文件, ``<sysfs>/kernel/mm/damon/`` 。你可以通过对该目录下的文件进行写入和
读取来控制DAMON。
对于一个简短的例子,用户可以监测一个给定工作负载的虚拟地址空间,如下所示::
# cd /sys/kernel/mm/damon/admin/
# echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
# echo vaddr > kdamonds/0/contexts/0/operations
# echo 1 > kdamonds/0/contexts/0/targets/nr_targets
# echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
# echo on > kdamonds/0/state
文件层次结构
------------
DAMON sysfs接口的文件层次结构如下图所示。在下图中,父子关系用缩进表示,每个目录有
``/`` 后缀,每个目录中的文件用逗号(",")分开。 ::
/sys/kernel/mm/damon/admin
│ kdamonds/nr_kdamonds
│ │ 0/state,pid
│ │ │ contexts/nr_contexts
│ │ │ │ 0/operations
│ │ │ │ │ monitoring_attrs/
│ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
│ │ │ │ │ │ nr_regions/min,max
│ │ │ │ │ targets/nr_targets
│ │ │ │ │ │ 0/pid_target
│ │ │ │ │ │ │ regions/nr_regions
│ │ │ │ │ │ │ │ 0/start,end
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ │ schemes/nr_schemes
│ │ │ │ │ │ 0/action
│ │ │ │ │ │ │ access_pattern/
│ │ │ │ │ │ │ │ sz/min,max
│ │ │ │ │ │ │ │ nr_accesses/min,max
│ │ │ │ │ │ │ │ age/min,max
│ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
│ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
│ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
│ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds
│ │ │ │ │ │ │ tried_regions/
│ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ ...
│ │ ...
根
--
DAMON sysfs接口的根是 ``<sysfs>/kernel/mm/damon/`` ,它有一个名为 ``admin`` 的
目录。该目录包含特权用户空间程序控制DAMON的文件。拥有根权限的用户空间工具或deamons可以
使用这个目录。
kdamonds/
---------
与监测相关的信息包括请求规格和结果被称为DAMON上下文。DAMON用一个叫做kdamond的内核线程
执行每个上下文,多个kdamonds可以并行运行。
在 ``admin`` 目录下,有一个目录,即``kdamonds``,它有控制kdamonds的文件存在。在开始
时,这个目录只有一个文件,``nr_kdamonds``。向该文件写入一个数字(``N``),就会创建名为
``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个kdamond。
kdamonds/<N>/
-------------
在每个kdamond目录中,存在两个文件(``state`` 和 ``pid`` )和一个目录( ``contexts`` )。
读取 ``state`` 时,如果kdamond当前正在运行,则返回 ``on`` ,如果没有运行则返回 ``off`` 。
写入 ``on`` 或 ``off`` 使kdamond处于状态。向 ``state`` 文件写 ``update_schemes_stats`` ,
更新kdamond的每个基于DAMON的操作方案的统计文件的内容。关于统计信息的细节,请参考
:ref:`stats section <sysfs_schemes_stats>`. 将 ``update_schemes_tried_regions`` 写到
``state`` 文件,为kdamond的每个基于DAMON的操作方案,更新基于DAMON的操作方案动作的尝试区域目录。
将`clear_schemes_tried_regions`写入`state`文件,清除kdamond的每个基于DAMON的操作方案的动作
尝试区域目录。 关于基于DAMON的操作方案动作尝试区域目录的细节,请参考:ref:tried_regions 部分
<sysfs_schemes_tried_regions>`。
如果状态为 ``on``,读取 ``pid`` 显示kdamond线程的pid。
``contexts`` 目录包含控制这个kdamond要执行的监测上下文的文件。
kdamonds/<N>/contexts/
----------------------
在开始时,这个目录只有一个文件,即 ``nr_contexts`` 。向该文件写入一个数字( ``N`` ),就会创
建名为``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个监测背景。目前,每个kdamond只支持
一个上下文,所以只有 ``0`` 或 ``1`` 可以被写入文件。
contexts/<N>/
-------------
在每个上下文目录中,存在一个文件(``operations``)和三个目录(``monitoring_attrs``,
``targets``, 和 ``schemes``)。
DAMON支持多种类型的监测操作,包括对虚拟地址空间和物理地址空间的监测。你可以通过向文件
中写入以下关键词之一,并从文件中读取,来设置和获取DAMON将为上下文使用何种类型的监测操作。
- vaddr: 监测特定进程的虚拟地址空间
- paddr: 监视系统的物理地址空间
contexts/<N>/monitoring_attrs/
------------------------------
用于指定监测属性的文件,包括所需的监测质量和效率,都在 ``monitoring_attrs`` 目录中。
具体来说,这个目录下有两个目录,即 ``intervals`` 和 ``nr_regions`` 。
在 ``intervals`` 目录下,存在DAMON的采样间隔(``sample_us``)、聚集间隔(``aggr_us``)
和更新间隔(``update_us``)三个文件。你可以通过写入和读出这些文件来设置和获取微秒级的值。
在 ``nr_regions`` 目录下,有两个文件分别用于DAMON监测区域的下限和上限(``min`` 和 ``max`` ),
这两个文件控制着监测的开销。你可以通过向这些文件的写入和读出来设置和获取这些值。
关于间隔和监测区域范围的更多细节,请参考设计文件 (:doc:`/mm/damon/design`)。
contexts/<N>/targets/
---------------------
在开始时,这个目录只有一个文件 ``nr_targets`` 。向该文件写入一个数字(``N``),就可以创建
名为 ``0`` 到 ``N-1`` 的子目录的数量。每个目录代表每个监测目标。
targets/<N>/
------------
在每个目标目录中,存在一个文件(``pid_target``)和一个目录(``regions``)。
如果你把 ``vaddr`` 写到 ``contexts/<N>/operations`` 中,每个目标应该是一个进程。你
可以通过将进程的pid写到 ``pid_target`` 文件中来指定DAMON的进程。
targets/<N>/regions
-------------------
当使用 ``vaddr`` 监测操作集时( ``vaddr`` 被写入 ``contexts/<N>/operations`` 文
件),DAMON自动设置和更新监测目标区域,这样就可以覆盖目标进程的整个内存映射。然而,用户可
能希望将初始监测区域设置为特定的地址范围。
相反,当使用 ``paddr`` 监测操作集时,DAMON不会自动设置和更新监测目标区域( ``paddr``
被写入 ``contexts/<N>/operations`` 中)。因此,在这种情况下,用户应该自己设置监测目标
区域。
在这种情况下,用户可以按照自己的意愿明确设置初始监测目标区域,将适当的值写入该目录下的文件。
开始时,这个目录只有一个文件, ``nr_regions`` 。向该文件写入一个数字(``N``),就可以创
建名为 ``0`` 到 ``N-1`` 的子目录。每个目录代表每个初始监测目标区域。
regions/<N>/
------------
在每个区域目录中,你会发现两个文件( ``start`` 和 ``end`` )。你可以通过向文件写入
和从文件中读出,分别设置和获得初始监测目标区域的起始和结束地址。
每个区域不应该与其他区域重叠。 目录“N”的“结束”应等于或小于目录“N+1”的“开始”。
contexts/<N>/schemes/
---------------------
对于一版的基于DAMON的数据访问感知的内存管理优化,用户通常希望系统对特定访问模式的内存区
域应用内存管理操作。DAMON从用户那里接收这种形式化的操作方案,并将这些方案应用于目标内存
区域。用户可以通过读取和写入这个目录下的文件来获得和设置这些方案。
在开始时,这个目录只有一个文件,``nr_schemes``。向该文件写入一个数字(``N``),就可以
创建名为``0``到``N-1``的子目录的数量。每个目录代表每个基于DAMON的操作方案。
schemes/<N>/
------------
在每个方案目录中,存在五个目录(``access_pattern``、``quotas``、``watermarks``、
``stats`` 和 ``tried_regions``)和一个文件(``action``)。
``action`` 文件用于设置和获取你想应用于具有特定访问模式的内存区域的动作。可以写入文件
和从文件中读取的关键词及其含义如下。
- ``willneed``: 对有 ``MADV_WILLNEED`` 的区域调用 ``madvise()`` 。
- ``cold``: 对具有 ``MADV_COLD`` 的区域调用 ``madvise()`` 。
- ``pageout``: 为具有 ``MADV_PAGEOUT`` 的区域调用 ``madvise()`` 。
- ``hugepage``: 为带有 ``MADV_HUGEPAGE`` 的区域调用 ``madvise()`` 。
- ``nohugepage``: 为带有 ``MADV_NOHUGEPAGE`` 的区域调用 ``madvise()``。
- ``lru_prio``: 在其LRU列表上对区域进行优先排序。
- ``lru_deprio``: 对区域的LRU列表进行降低优先处理。
- ``stat``: 什么都不做,只计算统计数据
schemes/<N>/access_pattern/
---------------------------
每个基于DAMON的操作方案的目标访问模式由三个范围构成,包括以字节为单位的区域大小、每个
聚合区间的监测访问次数和区域年龄的聚合区间数。
在 ``access_pattern`` 目录下,存在三个目录( ``sz``, ``nr_accesses``, 和 ``age`` ),
每个目录有两个文件(``min`` 和 ``max`` )。你可以通过向 ``sz``, ``nr_accesses``, 和
``age`` 目录下的 ``min`` 和 ``max`` 文件分别写入和读取来设置和获取给定方案的访问模式。
schemes/<N>/quotas/
-------------------
每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载,所以不容易找到。更糟糕的是,将某些动作
的方案设置得过于激进会造成严重的开销。为了避免这种开销,用户可以为每个方案限制时间和大小配额。
具体来说,用户可以要求DAMON尽量只使用特定的时间(``时间配额``)来应用动作,并且在给定的时间间
隔(``重置间隔``)内,只对具有目标访问模式的内存区域应用动作,而不使用特定数量(``大小配额``)。
当预计超过配额限制时,DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄,对找到的内存区域
进行优先排序。为了进行个性化的优先排序,用户可以为这三个属性设置权重。
在 ``quotas`` 目录下,存在三个文件(``ms``, ``bytes``, ``reset_interval_ms``)和一个
目录(``weights``),其中有三个文件(``sz_permil``, ``nr_accesses_permil``, 和
``age_permil``)。
你可以设置以毫秒为单位的 ``时间配额`` ,以字节为单位的 ``大小配额`` ,以及以毫秒为单位的 ``重
置间隔`` ,分别向这三个文件写入数值。你还可以通过向 ``weights`` 目录下的三个文件写入数值来设
置大小、访问频率和年龄的优先权,单位为千分之一。
schemes/<N>/watermarks/
-----------------------
为了便于根据系统状态激活和停用每个方案,DAMON提供了一个称为水位的功能。该功能接收五个值,称为
``度量`` 、``间隔`` 、``高`` 、``中`` 、``低`` 。``度量值`` 是指可以测量的系统度量值,如
自由内存比率。如果系统的度量值 ``高`` 于memoent的高值或 ``低`` 于低值,则该方案被停用。如果
该值低于 ``中`` ,则该方案被激活。
在水位目录下,存在五个文件(``metric``, ``interval_us``,``high``, ``mid``, and ``low``)
用于设置每个值。你可以通过向这些文件的写入来分别设置和获取这五个值。
可以写入 ``metric`` 文件的关键词和含义如下。
- none: 忽略水位
- free_mem_rate: 系统的自由内存率(千分比)。
``interval`` 应以微秒为单位写入。
schemes/<N>/stats/
------------------
DAMON统计每个方案被尝试应用的区域的总数量和字节数,每个方案被成功应用的区域的两个数字,以及
超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。
可以通过读取 ``stats`` 目录下的文件(``nr_tried``, ``sz_tried``, ``nr_applied``,
``sz_applied``, 和 ``qt_exceeds``))分别检索这些统计数据。这些文件不是实时更新的,所以
你应该要求DAMON sysfs接口通过在相关的 ``kdamonds/<N>/state`` 文件中写入一个特殊的关键字
``update_schemes_stats`` 来更新统计信息的文件内容。
schemes/<N>/tried_regions/
--------------------------
当一个特殊的关键字 ``update_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
文件时,DAMON会在这个目录下创建从 ``0`` 开始命名的整数目录。每个目录包含的文件暴露了关于每个
内存区域的详细信息,在下一个 :ref:`聚集区间 <sysfs_monitoring_attrs>`,相应的方案的 ``动作``
已经尝试在这个目录下应用。这些信息包括地址范围、``nr_accesses`` 以及区域的 ``年龄`` 。
当另一个特殊的关键字 ``clear_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
文件时,这些目录将被删除。
tried_regions/<N>/
------------------
在每个区域目录中,你会发现四个文件(``start``, ``end``, ``nr_accesses``, and ``age``)。
读取这些文件将显示相应的基于DAMON的操作方案 ``动作`` 试图应用的区域的开始和结束地址、``nr_accesses``
和 ``年龄`` 。
用例
~~~~
下面的命令应用了一个方案:”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间间隔内
显示出每一个聚合时间间隔[0, 5]的访问量,请分页该区域。对于分页,每秒最多只能使用10ms,而且每
秒分页不能超过1GiB。在这一限制下,首先分页出具有较长年龄的内存区域。另外,每5秒钟检查一次系统
的可用内存率,当可用内存率低于50%时开始监测和分页,但如果可用内存率大于60%,或低于30%,则停
止监测。“ ::
# cd <sysfs>/kernel/mm/damon/admin
# # populate directories
# echo 1 > kdamonds/nr_kdamonds; echo 1 > kdamonds/0/contexts/nr_contexts;
# echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
# cd kdamonds/0/contexts/0/schemes/0
# # set the basic access pattern and the action
# echo 4096 > access_pattern/sz/min
# echo 8192 > access_pattern/sz/max
# echo 0 > access_pattern/nr_accesses/min
# echo 5 > access_pattern/nr_accesses/max
# echo 10 > access_pattern/age/min
# echo 20 > access_pattern/age/max
# echo pageout > action
# # set quotas
# echo 10 > quotas/ms
# echo $((1024*1024*1024)) > quotas/bytes
# echo 1000 > quotas/reset_interval_ms
# # set watermark
# echo free_mem_rate > watermarks/metric
# echo 5000000 > watermarks/interval_us
# echo 600 > watermarks/high
# echo 500 > watermarks/mid
# echo 300 > watermarks/low
请注意,我们强烈建议使用用户空间的工具,如 `damo <https://github.com/damonitor/damo>`_ ,
而不是像上面那样手动读写文件。以上只是一个例子。
监测结果的监测点
================
DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果. 当监测开启时,你可
以记录追踪点事件,并使用追踪点支持工具如perf显示结果。比如说::
# echo on > monitor_on_DEPRECATED
# perf record -e damon:damon_aggregated &
# sleep 5
# kill 9 $(pidof perf)
# echo off > monitor_on_DEPRECATED
# perf script
@@ -0,0 +1,49 @@
.. include:: ../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/index.rst
:翻译:
徐鑫 xu xin <xu.xin16@zte.com.cn>
========
内存管理
========
Linux内存管理子系统,顾名思义,是负责系统中的内存管理。它包括了虚拟内存与请求
分页的实现,内核内部结构和用户空间程序的内存分配、将文件映射到进程地址空间以
及许多其他很酷的事情。
Linux内存管理是一个具有许多可配置设置的复杂系统, 且这些设置中的大多数都可以通
过 ``/proc`` 文件系统获得,并且可以使用 ``sysctl`` 进行查询和调整。这些API接
口被描述在Documentation/admin-guide/sysctl/vm.rst文件和 `man 5 proc`_ 中。
.. _man 5 proc: http://man7.org/linux/man-pages/man5/proc.5.html
Linux内存管理有它自己的术语,如果你还不熟悉它,请考虑阅读下面参考:
Documentation/admin-guide/mm/concepts.rst.
在此目录下,我们详细描述了如何与Linux内存管理中的各种机制交互。
.. toctree::
:maxdepth: 1
damon/index
ksm
Todolist:
* concepts
* cma_debugfs
* hugetlbpage
* idle_page_tracking
* memory-hotplug
* nommu-mmap
* numa_memory_policy
* numaperf
* pagemap
* soft-dirty
* swap_numa
* transhuge
* userfaultfd
* zswap
@@ -0,0 +1,198 @@
.. include:: ../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/ksm.rst
:翻译:
徐鑫 xu xin <xu.xin16@zte.com.cn>
============
内核同页合并
============
概述
====
KSM是一种能节省内存的数据去重功能,由CONFIG_KSM=y启用,并在2.6.32版本时被添
加到Linux内核。详见 ``mm/ksm.c`` 的实现,以及http://lwn.net/Articles/306704
和https://lwn.net/Articles/330589
KSM最初目的是为了与KVM(即著名的内核共享内存)一起使用而开发的,通过共享虚拟机
之间的公共数据,将更多虚拟机放入物理内存。但它对于任何会生成多个相同数据实例的
应用程序都是很有用的。
KSM的守护进程ksmd会定期扫描那些已注册的用户内存区域,查找内容相同的页面,这些
页面可以被单个写保护页面替换(如果进程以后想要更新其内容,将自动复制)。使用:
引用:`sysfs intraface <ksm_sysfs>` 接口来配置KSM守护程序在单个过程中所扫描的页
数以及两个过程之间的间隔时间。
KSM只合并匿名(私有)页面,从不合并页缓存(文件)页面。KSM的合并页面最初只能被
锁定在内核内存中,但现在可以就像其他用户页面一样被换出(但当它们被交换回来时共
享会被破坏: ksmd必须重新发现它们的身份并再次合并)。
以madvise控制KSM
================
KSM仅在特定的地址空间区域时运行,即应用程序通过使用如下所示的madvise(2)系统调
用来请求某块地址成为可能的合并候选者的地址空间::
int madvise(addr, length, MADV_MERGEABLE)
应用程序当然也可以通过调用::
int madvise(addr, length, MADV_UNMERGEABLE)
来取消该请求,并恢复为非共享页面:此时KSM将去除合并在该范围内的任何合并页。注意:
这个去除合并的调用可能突然需要的内存量超过实际可用的内存量-那么可能会出现EAGAIN
失败,但更可能会唤醒OOM killer。
如果KSM未被配置到正在运行的内核中,则madvise MADV_MERGEABLE 和 MADV_UNMERGEABLE
的调用只会以EINVAL 失败。如果正在运行的内核是用CONFIG_KSM=y方式构建的,那么这些
调用通常会成功:即使KSM守护程序当前没有运行,MADV_MERGEABLE 仍然会在KSM守护程序
启动时注册范围,即使该范围不能包含KSM实际可以合并的任何页面,即使MADV_UNMERGEABLE
应用于从未标记为MADV_MERGEABLE的范围。
如果一块内存区域必须被拆分为至少一个新的MADV_MERGEABLE区域或MADV_UNMERGEABLE区域,
当该进程将超过 ``vm.max_map_count`` 的设定,则madvise可能返回ENOMEM。(请参阅文档
Documentation/admin-guide/sysctl/vm.rst)。
与其他madvise调用一样,它们在用户地址空间的映射区域上使用:如果指定的范围包含未
映射的间隙(尽管在中间的映射区域工作),它们将报告ENOMEM,如果没有足够的内存用于
内部结构,则可能会因EAGAIN而失败。
KSM守护进程sysfs接口
====================
KSM守护进程可以由``/sys/kernel/mm/ksm/`` 中的sysfs文件控制,所有人都可以读取,但
只能由root用户写入。各接口解释如下:
pages_to_scan
ksmd进程进入睡眠前要扫描的页数。
例如, ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan``
默认值:100(该值被选择用于演示目的)
sleep_millisecs
ksmd在下次扫描前应休眠多少毫秒
例如, ``echo 20 > /sys/kernel/mm/ksm/sleep_millisecs``
默认值:20(该值被选择用于演示目的)
merge_across_nodes
指定是否可以合并来自不同NUMA节点的页面。当设置为0时,ksm仅合并在物理上位
于同一NUMA节点的内存区域中的页面。这降低了访问共享页面的延迟。在有明显的
NUMA距离上,具有更多节点的系统可能受益于设置该值为0时的更低延迟。而对于
需要对内存使用量最小化的较小系统来说,设置该值为1(默认设置)则可能会受
益于更大共享页面。在决定使用哪种设置之前,您可能希望比较系统在每种设置下
的性能。 ``merge_across_nodes`` 仅当系统中没有ksm共享页面时,才能被更改设
置:首先将接口`run` 设置为2从而对页进行去合并,然后在修改
``merge_across_nodes`` 后再将‘run’又设置为1,以根据新设置来重新合并。
默认值:1(如早期的发布版本一样合并跨站点)
run
* 设置为0可停止ksmd运行,但保留合并页面,
* 设置为1可运行ksmd,例如, ``echo 1 > /sys/kernel/mm/ksm/run`` ,
* 设置为2可停止ksmd运行,并且对所有目前已合并的页进行去合并,但保留可合并
区域以供下次运行。
默认值:0(必须设置为1才能激活KSM,除非禁用了CONFIG_SYSFS)
use_zero_pages
指定是否应当特殊处理空页(即那些仅含zero的已分配页)。当该值设置为1时,
空页与内核零页合并,而不是像通常情况下那样空页自身彼此合并。这可以根据
工作负载的不同,在具有着色零页的架构上可以提高性能。启用此设置时应小心,
因为它可能会降低某些工作负载的KSM性能,比如,当待合并的候选页面的校验和
与空页面的校验和恰好匹配的时候。此设置可随时更改,仅对那些更改后再合并
的页面有效。
默认值:0(如同早期版本的KSM正常表现)
max_page_sharing
单个KSM页面允许的最大共享站点数。这将强制执行重复数据消除限制,以避免涉
及遍历共享KSM页面的虚拟映射的虚拟内存操作的高延迟。最小值为2,因为新创
建的KSM页面将至少有两个共享者。该值越高,KSM合并内存的速度越快,去重
因子也越高,但是对于任何给定的KSM页面,虚拟映射的最坏情况遍历的速度也会
越慢。减慢了这种遍历速度就意味着在交换、压缩、NUMA平衡和页面迁移期间,
某些虚拟内存操作将有更高的延迟,从而降低这些虚拟内存操作调用者的响应能力。
其他任务如果不涉及执行虚拟映射遍历的VM操作,其任务调度延迟不受此参数的影
响,因为这些遍历本身是调度友好的。
stable_node_chains_prune_millisecs
指定KSM检查特定页面的元数据的频率(即那些达到过时信息数据去重限制标准的
页面)单位是毫秒。较小的毫秒值将以更低的延迟来释放KSM元数据,但它们将使
ksmd在扫描期间使用更多CPU。如果还没有一个KSM页面达到 ``max_page_sharing``
标准,那就没有什么用。
KSM与MADV_MERGEABLE的工作有效性体现于 ``/sys/kernel/mm/ksm/`` 路径下的接口:
pages_shared
表示多少共享页正在被使用
pages_sharing
表示还有多少站点正在共享这些共享页,即节省了多少
pages_unshared
表示有多少页是唯一的,但被反复检查以进行合并
pages_volatile
表示有多少页因变化太快而无法放在tree中
full_scans
表示所有可合并区域已扫描多少次
stable_node_chains
达到 ``max_page_sharing`` 限制的KSM页数
stable_node_dups
重复的KSM页数
比值 ``pages_sharing/pages_shared`` 的最大值受限制于 ``max_page_sharing``
的设定。要想增加该比值,则相应地要增加 ``max_page_sharing`` 的值。
监测KSM的收益
=============
KSM可以通过合并相同的页面来节省内存,但也会消耗额外的内存,因为它需要生成一些rmap_items
来保存每个扫描页面的简要rmap信息。其中有些页面可能会被合并,但有些页面在被检查几次
后可能无法被合并,这些都是无益的内存消耗。
1) 如何确定KSM在全系统范围内是节省内存还是消耗内存?这里有一个简单的近似计算方法供参考::
general_profit =~ pages_sharing * sizeof(page) - (all_rmap_items) *
sizeof(rmap_item);
其中all_rmap_items可以通过对 ``pages_sharing`` 、 ``pages_shared`` 、 ``pages_unshared``
和 ``pages_volatile`` 的求和而轻松获得。
2) 单一进程中KSM的收益也可以通过以下近似的计算得到::
process_profit =~ ksm_merging_pages * sizeof(page) -
ksm_rmap_items * sizeof(rmap_item).
其中ksm_merging_pages显示在 ``/proc/<pid>/`` 目录下,而ksm_rmap_items
显示在 ``/proc/<pid>/ksm_stat`` 。
从应用的角度来看, ``ksm_rmap_items`` 和 ``ksm_merging_pages`` 的高比例意
味着不好的madvise-applied策略,所以开发者或管理员必须重新考虑如何改变madvis策
略。举个例子供参考,一个页面的大小通常是4K,而rmap_item的大小在32位CPU架构上分
别是32B,在64位CPU架构上是64B。所以如果 ``ksm_rmap_items/ksm_merging_pages``
的比例在64位CPU上超过64,或者在32位CPU上超过128,那么应用程序的madvise策略应
该被放弃,因为ksm收益大约为零或负值。
监控KSM事件
===========
在/proc/vmstat中有一些计数器,可以用来监控KSM事件。KSM可能有助于节省内存,这是
一种权衡,因为它可能会在KSM COW或复制中的交换上遭受延迟。这些事件可以帮助用户评估
是否或如何使用KSM。例如,如果cow_ksm增加得太快,用户可以减少madvise(, , MADV_MERGEABLE)
的范围。
cow_ksm
在每次KSM页面触发写时拷贝(COW)时都会被递增,当用户试图写入KSM页面时,
我们必须做一个拷贝。
ksm_swpin_copy
在换入时,每次KSM页被复制时都会被递增。请注意,KSM页在换入时可能会被复
制,因为do_swap_page()不能做所有的锁,而需要重组一个跨anon_vma的KSM页。
--
Izik Eidus,
Hugh Dickins, 2009年11月17日。