162306a36Sopenharmony_ci.. include:: ../../disclaimer-zh_CN.rst 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci:Original: Documentation/admin-guide/mm/ksm.rst 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci:翻译: 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 徐鑫 xu xin <xu.xin16@zte.com.cn> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci============ 1162306a36Sopenharmony_ci内核同页合并 1262306a36Sopenharmony_ci============ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci概述 1662306a36Sopenharmony_ci==== 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciKSM是一种能节省内存的数据去重功能,由CONFIG_KSM=y启用,并在2.6.32版本时被添 1962306a36Sopenharmony_ci加到Linux内核。详见 ``mm/ksm.c`` 的实现,以及http://lwn.net/Articles/306704 2062306a36Sopenharmony_ci和https://lwn.net/Articles/330589 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciKSM最初目的是为了与KVM(即著名的内核共享内存)一起使用而开发的,通过共享虚拟机 2362306a36Sopenharmony_ci之间的公共数据,将更多虚拟机放入物理内存。但它对于任何会生成多个相同数据实例的 2462306a36Sopenharmony_ci应用程序都是很有用的。 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciKSM的守护进程ksmd会定期扫描那些已注册的用户内存区域,查找内容相同的页面,这些 2762306a36Sopenharmony_ci页面可以被单个写保护页面替换(如果进程以后想要更新其内容,将自动复制)。使用: 2862306a36Sopenharmony_ci引用:`sysfs intraface <ksm_sysfs>` 接口来配置KSM守护程序在单个过程中所扫描的页 2962306a36Sopenharmony_ci数以及两个过程之间的间隔时间。 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciKSM只合并匿名(私有)页面,从不合并页缓存(文件)页面。KSM的合并页面最初只能被 3262306a36Sopenharmony_ci锁定在内核内存中,但现在可以就像其他用户页面一样被换出(但当它们被交换回来时共 3362306a36Sopenharmony_ci享会被破坏: ksmd必须重新发现它们的身份并再次合并)。 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci以madvise控制KSM 3662306a36Sopenharmony_ci================ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciKSM仅在特定的地址空间区域时运行,即应用程序通过使用如下所示的madvise(2)系统调 3962306a36Sopenharmony_ci用来请求某块地址成为可能的合并候选者的地址空间:: 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci int madvise(addr, length, MADV_MERGEABLE) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci应用程序当然也可以通过调用:: 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci int madvise(addr, length, MADV_UNMERGEABLE) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci来取消该请求,并恢复为非共享页面:此时KSM将去除合并在该范围内的任何合并页。注意: 4862306a36Sopenharmony_ci这个去除合并的调用可能突然需要的内存量超过实际可用的内存量-那么可能会出现EAGAIN 4962306a36Sopenharmony_ci失败,但更可能会唤醒OOM killer。 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci如果KSM未被配置到正在运行的内核中,则madvise MADV_MERGEABLE 和 MADV_UNMERGEABLE 5262306a36Sopenharmony_ci的调用只会以EINVAL 失败。如果正在运行的内核是用CONFIG_KSM=y方式构建的,那么这些 5362306a36Sopenharmony_ci调用通常会成功:即使KSM守护程序当前没有运行,MADV_MERGEABLE 仍然会在KSM守护程序 5462306a36Sopenharmony_ci启动时注册范围,即使该范围不能包含KSM实际可以合并的任何页面,即使MADV_UNMERGEABLE 5562306a36Sopenharmony_ci应用于从未标记为MADV_MERGEABLE的范围。 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci如果一块内存区域必须被拆分为至少一个新的MADV_MERGEABLE区域或MADV_UNMERGEABLE区域, 5862306a36Sopenharmony_ci当该进程将超过 ``vm.max_map_count`` 的设定,则madvise可能返回ENOMEM。(请参阅文档 5962306a36Sopenharmony_ciDocumentation/admin-guide/sysctl/vm.rst)。 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci与其他madvise调用一样,它们在用户地址空间的映射区域上使用:如果指定的范围包含未 6262306a36Sopenharmony_ci映射的间隙(尽管在中间的映射区域工作),它们将报告ENOMEM,如果没有足够的内存用于 6362306a36Sopenharmony_ci内部结构,则可能会因EAGAIN而失败。 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciKSM守护进程sysfs接口 6662306a36Sopenharmony_ci==================== 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciKSM守护进程可以由``/sys/kernel/mm/ksm/`` 中的sysfs文件控制,所有人都可以读取,但 6962306a36Sopenharmony_ci只能由root用户写入。各接口解释如下: 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cipages_to_scan 7362306a36Sopenharmony_ci ksmd进程进入睡眠前要扫描的页数。 7462306a36Sopenharmony_ci 例如, ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan`` 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci 默认值:100(该值被选择用于演示目的) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cisleep_millisecs 7962306a36Sopenharmony_ci ksmd在下次扫描前应休眠多少毫秒 8062306a36Sopenharmony_ci 例如, ``echo 20 > /sys/kernel/mm/ksm/sleep_millisecs`` 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci 默认值:20(该值被选择用于演示目的) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cimerge_across_nodes 8562306a36Sopenharmony_ci 指定是否可以合并来自不同NUMA节点的页面。当设置为0时,ksm仅合并在物理上位 8662306a36Sopenharmony_ci 于同一NUMA节点的内存区域中的页面。这降低了访问共享页面的延迟。在有明显的 8762306a36Sopenharmony_ci NUMA距离上,具有更多节点的系统可能受益于设置该值为0时的更低延迟。而对于 8862306a36Sopenharmony_ci 需要对内存使用量最小化的较小系统来说,设置该值为1(默认设置)则可能会受 8962306a36Sopenharmony_ci 益于更大共享页面。在决定使用哪种设置之前,您可能希望比较系统在每种设置下 9062306a36Sopenharmony_ci 的性能。 ``merge_across_nodes`` 仅当系统中没有ksm共享页面时,才能被更改设 9162306a36Sopenharmony_ci 置:首先将接口`run` 设置为2从而对页进行去合并,然后在修改 9262306a36Sopenharmony_ci ``merge_across_nodes`` 后再将‘run’又设置为1,以根据新设置来重新合并。 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci 默认值:1(如早期的发布版本一样合并跨站点) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cirun 9762306a36Sopenharmony_ci * 设置为0可停止ksmd运行,但保留合并页面, 9862306a36Sopenharmony_ci * 设置为1可运行ksmd,例如, ``echo 1 > /sys/kernel/mm/ksm/run`` , 9962306a36Sopenharmony_ci * 设置为2可停止ksmd运行,并且对所有目前已合并的页进行去合并,但保留可合并 10062306a36Sopenharmony_ci 区域以供下次运行。 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci 默认值:0(必须设置为1才能激活KSM,除非禁用了CONFIG_SYSFS) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciuse_zero_pages 10562306a36Sopenharmony_ci 指定是否应当特殊处理空页(即那些仅含zero的已分配页)。当该值设置为1时, 10662306a36Sopenharmony_ci 空页与内核零页合并,而不是像通常情况下那样空页自身彼此合并。这可以根据 10762306a36Sopenharmony_ci 工作负载的不同,在具有着色零页的架构上可以提高性能。启用此设置时应小心, 10862306a36Sopenharmony_ci 因为它可能会降低某些工作负载的KSM性能,比如,当待合并的候选页面的校验和 10962306a36Sopenharmony_ci 与空页面的校验和恰好匹配的时候。此设置可随时更改,仅对那些更改后再合并 11062306a36Sopenharmony_ci 的页面有效。 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 默认值:0(如同早期版本的KSM正常表现) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cimax_page_sharing 11562306a36Sopenharmony_ci 单个KSM页面允许的最大共享站点数。这将强制执行重复数据消除限制,以避免涉 11662306a36Sopenharmony_ci 及遍历共享KSM页面的虚拟映射的虚拟内存操作的高延迟。最小值为2,因为新创 11762306a36Sopenharmony_ci 建的KSM页面将至少有两个共享者。该值越高,KSM合并内存的速度越快,去重 11862306a36Sopenharmony_ci 因子也越高,但是对于任何给定的KSM页面,虚拟映射的最坏情况遍历的速度也会 11962306a36Sopenharmony_ci 越慢。减慢了这种遍历速度就意味着在交换、压缩、NUMA平衡和页面迁移期间, 12062306a36Sopenharmony_ci 某些虚拟内存操作将有更高的延迟,从而降低这些虚拟内存操作调用者的响应能力。 12162306a36Sopenharmony_ci 其他任务如果不涉及执行虚拟映射遍历的VM操作,其任务调度延迟不受此参数的影 12262306a36Sopenharmony_ci 响,因为这些遍历本身是调度友好的。 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistable_node_chains_prune_millisecs 12562306a36Sopenharmony_ci 指定KSM检查特定页面的元数据的频率(即那些达到过时信息数据去重限制标准的 12662306a36Sopenharmony_ci 页面)单位是毫秒。较小的毫秒值将以更低的延迟来释放KSM元数据,但它们将使 12762306a36Sopenharmony_ci ksmd在扫描期间使用更多CPU。如果还没有一个KSM页面达到 ``max_page_sharing`` 12862306a36Sopenharmony_ci 标准,那就没有什么用。 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciKSM与MADV_MERGEABLE的工作有效性体现于 ``/sys/kernel/mm/ksm/`` 路径下的接口: 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cipages_shared 13362306a36Sopenharmony_ci 表示多少共享页正在被使用 13462306a36Sopenharmony_cipages_sharing 13562306a36Sopenharmony_ci 表示还有多少站点正在共享这些共享页,即节省了多少 13662306a36Sopenharmony_cipages_unshared 13762306a36Sopenharmony_ci 表示有多少页是唯一的,但被反复检查以进行合并 13862306a36Sopenharmony_cipages_volatile 13962306a36Sopenharmony_ci 表示有多少页因变化太快而无法放在tree中 14062306a36Sopenharmony_cifull_scans 14162306a36Sopenharmony_ci 表示所有可合并区域已扫描多少次 14262306a36Sopenharmony_cistable_node_chains 14362306a36Sopenharmony_ci 达到 ``max_page_sharing`` 限制的KSM页数 14462306a36Sopenharmony_cistable_node_dups 14562306a36Sopenharmony_ci 重复的KSM页数 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci比值 ``pages_sharing/pages_shared`` 的最大值受限制于 ``max_page_sharing`` 14862306a36Sopenharmony_ci的设定。要想增加该比值,则相应地要增加 ``max_page_sharing`` 的值。 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci监测KSM的收益 15162306a36Sopenharmony_ci============= 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciKSM可以通过合并相同的页面来节省内存,但也会消耗额外的内存,因为它需要生成一些rmap_items 15462306a36Sopenharmony_ci来保存每个扫描页面的简要rmap信息。其中有些页面可能会被合并,但有些页面在被检查几次 15562306a36Sopenharmony_ci后可能无法被合并,这些都是无益的内存消耗。 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci1) 如何确定KSM在全系统范围内是节省内存还是消耗内存?这里有一个简单的近似计算方法供参考:: 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci general_profit =~ pages_sharing * sizeof(page) - (all_rmap_items) * 16062306a36Sopenharmony_ci sizeof(rmap_item); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci 其中all_rmap_items可以通过对 ``pages_sharing`` 、 ``pages_shared`` 、 ``pages_unshared`` 16362306a36Sopenharmony_ci 和 ``pages_volatile`` 的求和而轻松获得。 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci2) 单一进程中KSM的收益也可以通过以下近似的计算得到:: 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci process_profit =~ ksm_merging_pages * sizeof(page) - 16862306a36Sopenharmony_ci ksm_rmap_items * sizeof(rmap_item). 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci 其中ksm_merging_pages显示在 ``/proc/<pid>/`` 目录下,而ksm_rmap_items 17162306a36Sopenharmony_ci 显示在 ``/proc/<pid>/ksm_stat`` 。 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci从应用的角度来看, ``ksm_rmap_items`` 和 ``ksm_merging_pages`` 的高比例意 17462306a36Sopenharmony_ci味着不好的madvise-applied策略,所以开发者或管理员必须重新考虑如何改变madvis策 17562306a36Sopenharmony_ci略。举个例子供参考,一个页面的大小通常是4K,而rmap_item的大小在32位CPU架构上分 17662306a36Sopenharmony_ci别是32B,在64位CPU架构上是64B。所以如果 ``ksm_rmap_items/ksm_merging_pages`` 17762306a36Sopenharmony_ci的比例在64位CPU上超过64,或者在32位CPU上超过128,那么应用程序的madvise策略应 17862306a36Sopenharmony_ci该被放弃,因为ksm收益大约为零或负值。 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci监控KSM事件 18162306a36Sopenharmony_ci=========== 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci在/proc/vmstat中有一些计数器,可以用来监控KSM事件。KSM可能有助于节省内存,这是 18462306a36Sopenharmony_ci一种权衡,因为它可能会在KSM COW或复制中的交换上遭受延迟。这些事件可以帮助用户评估 18562306a36Sopenharmony_ci是否或如何使用KSM。例如,如果cow_ksm增加得太快,用户可以减少madvise(, , MADV_MERGEABLE) 18662306a36Sopenharmony_ci的范围。 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cicow_ksm 18962306a36Sopenharmony_ci 在每次KSM页面触发写时拷贝(COW)时都会被递增,当用户试图写入KSM页面时, 19062306a36Sopenharmony_ci 我们必须做一个拷贝。 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciksm_swpin_copy 19362306a36Sopenharmony_ci 在换入时,每次KSM页被复制时都会被递增。请注意,KSM页在换入时可能会被复 19462306a36Sopenharmony_ci 制,因为do_swap_page()不能做所有的锁,而需要重组一个跨anon_vma的KSM页。 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci-- 19762306a36Sopenharmony_ciIzik Eidus, 19862306a36Sopenharmony_ciHugh Dickins, 2009年11月17日。 199