linux ksm实现与代码简述

KSM 全称是 Kernel Samepage Merging,表示相同的物理页只映射一份拷贝。

原理

在ksm初始化时(ksm_init),注册了一个ksm_scan_thread线程,这个线程的核心入口是ksm_do_scan。当对一个进程第一次通过madvice(MADV_MERGEABLE)标记一段内存可合并时,会触发__ksm_enter将当前进程标记为MMF_VM_MERGEABLE,并把进程的mm_struct放在ksm_mm_head链表上。ksm_scan_thread会在ksm_mm_head链表上做扫描,找到标记合并的匿名页中,page内容的checksum不变的页(说明最近没有写入),如果是将找到的mergable 页合并到stable_tree 的 node上,将相应pte置为同一个物理地址。当有写操作时,会因为write_protected标记触发cow机制,生成新的页,并从stable tree里移除。

实现

ksm_scan_thread线程的核心是 ksm_do_scan,它会扫描所有进程(ksm_mm_head链表上的所有进程)的可合并 vma,找到checksum不变的页,如果stable tree没有,就添加到page所在numa 节点的unstable tree上,如果原本unstable tree上有,就一起移至stable tree(即引用超过2页的mergable 页才会移至stable tree中)。一轮扫描结束后,unstable tree会被清空,并在下轮扫描中重建。

每个numa 节点都有一个 stable tree和unstable tree。如果开启了ksm_merge_across_nodes,则所有numa node共用0号节点。

stable tree 是一个红黑树,当共享页的vma很多,超过ksm_max_page_sharing(256)个时,会将stable tree 的node 转为chain list node,每个chain list node 上最多存256个vma节点。它们指向同一个物理页。

unstable tree也是一个红黑树,一轮扫描结束后,unstable tree会被清空,并在下轮扫描中重建。

代码简述

ksm_do_scan主要由scan_get_next_rmap_item找可合并匿名页,由cmp_and_merge_page到对应numa节点找页尝试合并

scan_get_next_rmap_item

找mergable 的mapping了物理页的page。最终会连成一个链存在mm_struct->rmap_list上。

会顺带将不再mapping或设置unmergable的rmap_item删掉。

scan_get_next_rmap_item():// 新一轮扫描if (mm_slot == &ksm_mm_head) {/*** 新一轮扫描前首先触发一次lru_add_drain_all* 因为lru如果一直不刷新的话,有些无用的页会因为引用计数而不能做merge。*/lru_add_drain_all();/*** 如果一页做了迁移,在一轮结束时应该已经有对应节点加在了正确numa节点的stable tree上* 并增加了ref,可以安全地将ref减1了*/if (ksm_merge_across_nodes) {list_for_each_entry_safe(stable_node, next, &migrate_nodes, list) {page = get_ksm_page(stable_node, GET_KSM_PAGE_NOLOCK);if (page)put_page(page);cond_resched();}}}vma_iter_init(&vmi, mm, ksm_scan.address);for_each_vma(vmi, vma) {/*** 遍历一个进程所有mergeable anon vma中的有物理页的page,跳过device页,* 找到对应 address 的 rmap_item,或为它新创建一个rmap_item,* 上一次扫描到的ksm_scan.rmap_list 到它之间的所有item都* 不再mergable或没有物理页了,需要删除 rmap_item。* (这样一轮下来,整个进程的全部mergable的物理页的rmap,*   就全放在mm_struct->rmap_list上了)*/rmap_item = get_next_rmap_item(mm_slot, ksm_scan.rmap_list, ksm_scan.address);return rmap_item; // 找到了一个mergable匿名页}// 如果扫描一轮发现这个进程没有ksm页了,就删掉对应mm_slothash_del(&mm_slot->slot.hash);list_del(&mm_slot->slot.mm_node);

cmp_and_merge_page

如果目标页的ksm页大于等于2个,则能找目标页所在numa节点上的stable node,加入上去。

在还没找到时,会先把自己加在unstable tree对应numa节点上,等后面的ksm页发现自己,并与自己一同加到stable tree上。

如果一个numa节点的stable tree上的一个ksm页,有多个dup节点,它们会连成一个chain,在stable_tree_search->chain_prune时会优先找到映射最多page结构的dup节点,与它合并。

搜索可合并stable node过程中会顺带发现不属于当前numa 节点的ksm页,从树上删除,并在之后整一轮扫描结束时,将ref减1。

cmp_and_merge_page():stable_node = page_stable_node(page);if (stable_node) {如果不支持ksm迁移,且物理页做了 numa node 迁移。则把 stable node 迁移至migrate_nodes上。否则它已经在 stable 树上了,直接返回}// 找出一个 ksm 页kpage = stable_tree_search();// 如果有这样的 ksm 页,则将此页的pte映射到ksm页上去。并插入 stable tree。if (kpage) {try_to_merge_with_ksm_page();stable_tree_append(rmap_item, page_stable_node(kpage));}// 还没有这样的 ksm 页,计算 checksum ,看是不是与上次一样,一样则认为没有修改calc_checksum(page);// 如果checksum变了, 它可能被频繁修改,不对这样的页做合并if (rmap_item->oldchecksum != checksum) {rmap_item->oldchecksum = checksum;return;}// 如果checksum是0页,则与0页合并(0页是刚初始化的页)try_to_merge_one_page(vma, page, ZERO_PAGE(rmap_item->address));// 尝试从本轮的对应 numa 节点的 unstable tree 上找有没有出现过相同内容页,// 没有则插入 unstable treeunstable_tree_search_insert()// 如果unstable tree有,说明有两个同样内容的页内容一直没变,可以合并到 stable treetry_to_merge_two_pages()stable_tree_append(tree_rmap_item, stable_node);stable_tree_append(rmap_item, stable_node);// 如果两个相同内容页出现在同一个 compound page 上// 则只是拆分复合页,先不合并ksm,因为需要重新拿锁,可以等到下一轮split_huge_page(); 

stable_tree_search

搜索过程中,如果自己的page已经是migrate stable node了,就可以找个树上的节点替换,并返回自己。

在stable tree搜索过程中,会顺便发现物理页已经迁移了的node,并将其从树上移除。

stable_tree_search():// 如果页对应的stable node存在,则前面的cmp_and_merge_page// 保证了它在migrate_nodes上page_node = page_stable_node(page);// 在对应numa节点的红黑树查找nid = get_kpfn_nid(page_to_pfn(page));root = root_stable_tree + nid;new = &root->rb_node;while (*new) /* 一层层找到叶子节点 */{// 红黑树的节点可能是一个dup节点,如果vma超过了256,节点会组成dup链chain// 如果超过一定时间,则红黑树上chain节点的dup链,看是否只有一个dup节了。// 如果是,则用dup节点代替红黑树上的chain节点。// 这同时,会尝试把最多vma的dup节点放在chain的头上,作为下次合并首选dupchain_prune();// 比较页的内容,从而在红黑树上向下找ret = memcmp_pages(page, tree_page);// 如果目标页有stable node节点,且是一个物理页迁移了的 stable 节点if (page_node) {// 修改它的nid为它迁移到的numa节点id,并加回 stable tree //(mapcount > 1 时,以dup形式加到node chain上,等于1时走if后的逻辑加到dup上)DO_NUMA(page_node->nid = nid);stable_node_chain_add_dup(page_node, stable_node)}// chain_prune已经取了最多map页的dup节点// 这里判断下如果numa id不变,说明没有迁移过,可直接返回tree_page = get_ksm_page(stable_node_dup);if (get_kpfn_nid(stable_node_dup->kpfn) == NUMA(stable_node_dup->nid)) {return tree_page;}/*** 如果numa id 变过,则刚好发现了一个 numa 节点迁移了的 node* 可顺便将其从树上删除。并尝试将原page的stable migrate node 加回树上* (调用它的 cmp_and_merge_page 保证了如果page有stable node对应,则一定是migrate node)*/if (dup节点在红黑树上的chain上) {// 可直接将原节点删掉__stable_node_dup_del(stable_node_dup);if (page没有对应stable node migrate 节点))return null;// 如果page有节点,就把page改numa id后加到chain上去DO_NUMA(page_node->nid = nid);stable_node_chain_add_dup(page_node, stable_node);return page;} else /* dup 节点直接在红黑树上 */{if (page有对应stable node migrate 节点) {// 直接交换,并返回原页(因为它已经在树上了)rb_replace_node(&stable_node_dup->node, &page_node->node, root);return page;} else /* page 没有 stable node节点对应 */ {// 移除原节点,返回null(因为它没在树上了)rb_erase(&stable_node_dup->node, root);return null;}}}

页回收

当页被回收时,物理页的flag上swapcache标记会清理,导致get_ksm_page中观察到这个现象,并触发stable node 的删除,下次触发缺页时每个进程的页需要重新建立页的pte,再由ksmd线程重新扫描发现可合并的页。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/218858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux高级管理-基于域名的虚拟Web主机搭建

客服机限制地址 通过 Require 配置项&#xff0c;可以根据主机的主机名或P地址来决定是否允许客户端访问。在httpd服 务器的主配置文件的<Location>&#xff0c;<Directory>、<Files>、<Limit>配置段中均可以使用Require 配置 项来控制客户端的访问。使…

Java基础:如何创建多层文件夹

一、单层多个 代码实现如下&#xff1a; public class Main {public static void main(String[] args) {//在D盘中创建File file new File("D:"File.separator"docum");file.mkdir();//在D盘中的docum目录中创建file new File("D:\\docum" Fi…

kafka 详细介绍

目录 前言 分布式架构&#xff1a; 消息发布-订阅模型&#xff1a; 持久性存储&#xff1a; 分区和副本&#xff1a; 水平扩展&#xff1a; 高性能&#xff1a; 生态系统&#xff1a; 我的其他博客 前言 Kafka 是由 Apache 软件基金会开发的一种开源流处理平台&#xf…

微信小程序自定义提示框组件并使用插槽 tooltip

创建tooltip组件引用 创建一个自定义组件&#xff0c;例如命名为 tooltip tooltip.wxml&#xff1a;用于定义组件的结构&#xff1b; <!--components/tooltip/tooltip.wxml--> <view class"tooltip-wrapper" hidden"{{hidden}}" style"lef…

纺织辅料小程序商城制作全攻略

随着互联网的普及和移动支付的便捷性&#xff0c;越来越多的消费者喜欢在线购物&#xff0c;尤其是购买纺织辅料这类产品。为了满足消费者的需求&#xff0c;纺织辅料企业或商家需要制作一个专业的小程序商城&#xff0c;以便更好地展示和销售自己的产品。本文将详细介绍如何制…

Fine-Grained Semantically Aligned Vision-Language Pre-Training细粒度语义对齐的视觉语言预训练

abstract 大规模的视觉语言预训练在广泛的下游任务中显示出令人印象深刻的进展。现有方法主要通过图像和文本的全局表示的相似性或对图像和文本特征的高级跨模态关注来模拟跨模态对齐。然而&#xff0c;他们未能明确学习视觉区域和文本短语之间的细粒度语义对齐&#xff0c;因为…

Java开发环境简介(JDK、JRE、JVM)

目录 1、Java开发环境 2、JDK和JRE 3、JDK下载和安装 3.1 下载 3.2 安装 3.3 配置path环境变量 JDK8配置方案1&#xff1a;只配置path ⭐JDK8配置方案2&#xff1a;配置JAVA_HOMEpath&#xff08;推荐&#xff09; path配置小结 JDK17配置方案&#xff1a;自动配置 …

redis-学习笔记(Jedis 前置知识)

自定义的 Redis 客户端 咱们可以实现编写出一个自定义的 Redis 客户端 因为 Redis 公开了自己使用的自定义协议 ---- RESP 协议清楚了, 那么通信数据格式就清除了, 就能完成各层次之间的数据传输, 就能开发服务器和客户端 RESP — Redis 的 序列化 协议 特点: 简单好实现快读进…

AC修炼计划(AtCoder Beginner Contest 332)

传送门&#xff1a;AtCoder Beginner Contest 332 - AtCoder a,b,c都还是很基础了。d题是一个bfs的纯暴力问题。 E - Lucky bag 看看范围&#xff0c;n15&#xff0c;第一个想法是dfs纯暴力&#xff0c;但所有的情况太大&#xff0c;各种决策层出不穷&#xff0c;会t。所以转…

RocketMQ可视化工具 打包遇到的yarn intall 问题

文章目录 RocketMQ可视化工具1.github上下载2.修改参数3.运行4.打包5.出错6.解决7.重试8.再解决9.很奇怪运行没错&#xff0c;但是测试错啦10.不想深究&#xff0c;直接跳过测试11.展示成功 RocketMQ可视化工具 1.github上下载 下载地址 https://github.com/apache/rocketmq-…

redis:二、缓存击穿的定义、解决方案(互斥锁、逻辑过期)的优缺点和适用场景、面试回答模板

缓存击穿的定义 缓存击穿是一种现象&#xff0c;具体就是某一个数据过期时&#xff0c;恰好有大量的并发请求过来&#xff0c;这些并发的请求可能会瞬间把DB压垮。典型场景就是双十一等抢购活动中&#xff0c;首页广告页面的数据过期&#xff0c;此时刚好大量用户进行请求&…

Unity 置顶OpenFileDialog文件选择框

置顶文件选择框 &#x1f32d;处理前&#x1f959;处理后 &#x1f32d;处理前 &#x1f959;处理后 解决方案

【TI毫米波雷达入门-10】TI毫米波速度检测思路

知识回顾 FMCW chirp 雷达收发流程 中频信号 傅里叶变换 多目标检测 距离分辨率 最大距离 公式总结 FMCW数据处理流程示例 两个维度看图表 从range维度&#xff0c;水平方向上&#xff0c;反映每个chirp 发出的FMCW被接收天线检测到&#xff0c;2个点的目标&#xff0c;对应两个…

滑动窗口如人生,回顾往事不复还———力扣刷题

第一题&#xff1a;长度最小的子数组 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 思路&#xff1a; 第一想法肯定时暴力枚举&#xff0c;枚举数组任何一个元素&#xff0c;把他当起始位置&#xff0c;然后从起始位置找最短区间&#xff0c;使得…

uniapp原生插件之安卓app添加到其他应用打开原生插件

插件介绍 安卓app添加到其他应用打开原生插件&#xff0c;接收分享的文本和文件&#xff0c;支持获取和清空剪切板内容 插件地址 安卓app添加到其他应用打开原生插件&#xff0c;支持获取剪切板内容 - DCloud 插件市场 超级福利 uniapp 插件购买超级福利 详细使用文档 u…

Nyquist Theorem(取样定理)

取样定理&#xff0c;又称为奈奎斯特定理&#xff08;Nyquist Theorem&#xff09;&#xff0c;是信号处理领域中一项至关重要的基本原理。它规定了对于连续时间信号&#xff0c;为了能够完全准确地还原出原始信号&#xff0c;即使是在离散时间下进行采样和再构建&#xff0c;都…

【JUC】二十七、synchronized锁升级之无锁

文章目录 1、背景2、Monitor、Java对象、线程如何关联起来的&#xff1f;3、synchronized锁升级4、锁升级之无锁 关于synchronized同步&#xff0c;能用无锁结构就不要用锁&#xff1b;能锁块&#xff0c;就不要锁整个方法&#xff1b;能用对象锁&#xff0c;就不要用类锁。 用…

python算法例18 滑动窗口的最大值

1. 问题描述 给定一个可能包含重复整数的数组和一个大小为k的滑动窗口&#xff0c;从左到右在数组中滑动这个窗口&#xff0c;找到数组中每个窗口内的最大值。 2. 问题示例 给出数组[1&#xff0c;2&#xff0c;7&#xff0c;7&#xff0c;8]&#xff0c;滑动窗口大小为k3&a…

Redis - 主从集群下的主从复制原理

主从复制过程 数据同步演变过程 sync 同步 Redis 2.8 版本之前&#xff0c;首次通信成功后&#xff0c; slave 会向 master 发送 sync 数据同步请求。然后 master 就会将其所有数据全部发送给 slave &#xff0c;由 slave 保存到其本地的持久化文件中。这个过 程…

conda的安装及使用 以pycharm 为例

下载 https://docs.conda.io/en/latest/miniconda.html 下载 window版本 74M且下着吧。 安装 一路next或agree &#xff0c;不同意人家也不会按装 。重要的是安装目录 让andconda当老大 pycharm的使用 创建项目时如下图选择 成功后进入项目的Terminal则如下图表示成功