blob: 0029c4fd2201ab66857ef77d78dad1cf27787450 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
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日。
|