首页 > 其他分享 >KSM的使用

KSM的使用

时间:2024-03-20 15:02:33浏览次数:24  
标签:mm pages ksm 使用 KSM 节点 页面

使能KSM

KSM只会处理通过madvise系统调用显式指定的用户进程地址空间,因此用户程序想使用这个功能就必须在分配地址空间时显式地调用madvise(addr,length,MADV_MERGEA BLE)。如果用户想在KSM中取消某一个用户进程地址空间的合并功能,也需要显式地调用madvise(addr,length,MADV_UNMERGEABLE)。 下面是测试KSM的test.c程序的代码片段,使用mmap():来创建一个文件的私有映射,并且调用memset()写入这些私有映射的内容缓存页面中。

《测试KSM的test.c程序的代码片段》
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
    char *buf;
    char filename[64]="";
    struct stat stat;
    int size =100*4096;
    int fd =0;

    strcpy(filename, argv[1]);

    fd = open(filename,O_RDWR | O_CREAT,0664);

    fstat(fd, &stat);

    buf = mmap (NULL,stat.st_size,PROT_WRITE,MAP_PRIVATE,fd,0);

    memset(buf,0x55,stat.st_size);

    madvise(buf,stat.st_size, MADV_MERGEABLE);

    while (1)
        sleep(1);
}

编译上述test.c程序。

gcc test.c -o test

使用dd命令创建一个ksm.dat文件,即创建100MB大小的文件。

echo 1 >/sys/kernel/mm/ksm/run

运行test.c程序。

#./test ksm.dat

过一段时间之后,查看系统有多少页面合并了。

root@benshushu#cat /sys/kernel/mm/ksm/pages_sharing
25500
root@benshushu#cat /sys/kernel/mm/ksm/pages_shared
100
root@benshushu:/home#cat /sys/kernel/mm/ksm/pages_unshared
0

可以看到pages_shared为100说明系统有100个共享的页面。若有100个页面的内同,它们可以合并成一个页面,这时pages_shared为1。 pages_sharing 为25500说明有25500个页面合并了。 100MB的内存可存放25600个页面。因此,我们可以看到,KSM把这25600个页面分别合并成1共享的页面,每一个共享页面里共享了其他的255个页面,为什么会这样?我们稍后详细解析。 pages_unshared表示当前未合并页面的数量。

rootebenshushut cat /sys/kernel/mn/ksm/stable_node_chains
1
rootebenshushut cat /sys/kernel/mm/ksm/stable_node_dups
100

stable_node_chains表示包含了链式的稳定节点的个数,当前系统中为1,说明只有一个链式的稳定节点,但是这个稳定的节点里包含了链表。 stable_node_dups表示稳定的节点所在的链表包含的元素总数。 KSM的sysfs节点在/sys/kernel/mm/ksm/目录下,其主要节点的描述如下所示。

  • run:可以设置为0~2。若设置0,暂停ksmd内核线程;若设置1,启动ksmd内核线程;若设置2,取消所有已经合并好的页面
  • full_scans: 完整扫描和合并区域的次数
  • pages_volatile: 表示还没扫描和合并的页面数量。若由于页面内容更改过快导致两次计算的校验值不相等,那么这些页面是无法添加到红黑树里的
  • sleep_millisecs: ksmd内核线程扫描一次的时间间隔
  • pages_to_scan: 单次扫描页面的数量
  • pages_shared: 合并后的页面数。如果100个页面的内容相同,那么可以把它们合并成一个页面,这时pages_shared的值为1
  • pages_sharing: 共享的页面数。如果两个页面的内容相同,它们可以合并成一个页面,那么有一个页面要作为稳定的节点,这时pages_shared的值为1,pages_sharing也为1。第3个页面也合并进来后,pages_sharing的值为2,表示两个页面共享同一个稳定的节点
  • pages_unshared: 当前未合并页面数量
  • max_page_sharing: 这是在Linux4.3内核中新增的参数,表示一个稳定的节点最多可以合并的页面数量。这个值默认是256
  • stable_node_chains: 链表类型的稳定节点的个数。每个链式的稳定节点代表页面内容相同的KM页面。这个链式的稳定节点可以包含多个dup成员,每个dup成员最多包含256个共享的页面
  • stable_node_dups: 链表中dup成员的个数。这些dup成员会连接到链式的稳定节点的hlist链表中

KSM在初始化时会创建一个名为ksmd的内核线程。

<mm/ksm.c>
static int __init ksm_init(void)
{
    ksm_thread = kthread_run(ksm_scan_thread, NULL, "ksmd");
}
subsys_initcall(ksm_init);

在tes.c程序中创建私有映射(MAP_PRIVATE)之后,显式地调用madvise系统调用把用户进程地址空间添加到 Linux内核的KSM系统中。

<madvise()->ksm_madvise()-> ksm_enter()>

int __ksm_enter(struct mm_struct *mm)
{
    mm_slot = alloc_mm_slot();
    insert_to_mm_slots_hash(mm, mm_slot);
    list_add_tail(&mm slot->mm_list, &ksm_scan.mm_slot->mm list);
    set_bit(MME_VM_MERGEABLE, &mm->flags);
}

ksm_enter()函数会把当前的 mm_struct数据结构添加到 mm_slots_hash哈希表中。另外把 mm_slot添加到 ksm_scan.mm_slot->mm_list 链表中。最后,设置mm->flags中的 MMF_VM_MERGEABLE标志位,表示这个进程已经被添加到KSM系统中.

<ksm内核线程>

static int ksm_scan_thread(void *nothing)
{
    while (!kthread_should_stop())
        if (ksmd_should_run())
            ksm_do_scan(ksm_thread_pages_to_scan)
    if (ksmd_should_run()) {
        sleep_ms =READ_ONCE(ksm_thread_sleep_millisecs);
        wait_event_interruptible_timeout(ksm_iter_wait,
        sleep_ms != READ_ONCE(ksm_thread_sleep_millisecs),
        secs_to_jiffies(sleep_ms));
    }
    return 0;
}

ksm_scan_thread()是ksmd内核线程的主干,它运行 ksm_do_scan()函数,扫描和合并100个页面,见 ksm_thread_pages_to_scan参数,然后等待20ms,见 ksm_thread_sleep_millisecs参数,这两个参数可以在/sys/kernel/mm/ksm目录下设置和修改。

<ksmd内核线程>

static void ksm_do_scan(unsignd int scan_npages)
{
    while(scan_npages-- && likely(!freezing(current))) {
        cond_resched();
        rmap_item = scan_get_next_rmap_item(&page);
        if (!rmap_item)
            return;
        cmp_and_merge_page(page, rmap_item);
        put_page(page)
    }
}

ksm_do_scan()函数在while循环中尝试合并scan_npages个页面, scan_get_next_rmap_item()获取一个合适的匿名页面。 cmp_and_merge_page()函数会让页面在KSM中稳定和不稳定的两棵红黑树中查找是否有可以合并的对象,并且尝试合并他们。

KSM基本实现

为了让读者先有一个初步的认识,本节先介绍Lnux4.13内核之前的KSM实现,后文会介绍Linux5.0内核中的实现。

KSM机制下采用两棵红黑树来管理扫描的页面和己经合并的页面。第一棵红黑树称为不稳定红黑树,里面存放了还没有合并的页面;第二棵红黑树称为稳定红黑树,已经合并的页面会生成一个节点,这个节点为稳定节点。如两个页面的内容是一样的,KSM扫描并发现了它们,因此这两个页面就可以合并成一个页面。对于这个合并后的页面,会设置只读属性,其中一个页面会作为稳定的节点挂载到稳定的红黑树中之后,另外一个页面就会被释放了。但是这两个页面的 rmap_item数据结构会被添如到稳定节点中的 hist 链表中,如下图所示。

我们假设有3个VMA(表示进程地址空间,VMA的大小正好是一个页面的大小,分别有3个页面映射这3个VMA。这3个页面准备通过KSM来扫描和合并,这3个页面的内容是相同的。具体步骤如下。

  • 3个页面会被添加到KSM中,第一轮扫描中分别给这3个页面分配 rmap_item数据结构来描述它们,并且分别给它计算校验和,如图(a)所示
  • 第二轮扫描中,先扫描page0,若当前稳定的红黑树没有成员,那么不能比较和加入稳定的红黑树。接着,第二次计算校验值,如果 page0的校验值没有发生变化,那么把page0的rmap_item()添加到不稳定的红黑树中,如图(b)所示。如果此时校验值发生了变化,说明页面内容发生变化,这种页面不适合添加到不稳定的红黑树中
  • 扫描 page1,当前稳定的红黑树中没有成员,略过稳定的红黑树的搜索。搜索不稳定的红黑树,遍历红黑树中所有成员。 page1发现自己的内容与不稳定的红黑树中的 rmap_item()一致,因此尝试将page0和 page1合并成一个稳定的节点,合并过程就是让WMA0对映的虚拟地址、vaddr0映时到page1上。,并且把对应的PTE属性修改成只读展性。另外,VMA1映射到 page1的PTE属性也设置为只读属性。新创建一个稳定的节点,这个节点包含了page1的页帧号等信息,把这个稳定的节点添加到稳定的红黑树中。把代表page0的 map _item0和page1的rmap_item1添加到这个稳定的节点的hlist链表中,最后释放page0页面,如图(c)所示
  • 扫描page2。因为稳定的红黑树中有成员,因此,先和稳定的红黑树中的成员进行比较,检査是否可以合并。若发现page2的内容和稳定的节点内容一致,那么把VMA2中的vaddr2映射到稳定的节点对应的 page1上,并且把PTE属性设置为只读属性。把代表page2的rmap_item2添加到稳定的节点的 hlist 链表中,最后释放page2页面,如图(d)所示

标签:mm,pages,ksm,使用,KSM,节点,页面
From: https://www.cnblogs.com/linhaostudy/p/18085243

相关文章

  • UVR下载使用
    UVR全称UltimateVocalRemover,可用于伴奏分离等,可在github下载下载地址——https://github.com/Anjok07/ultimatevocalremovergui(github具体下载方式可参考我上一篇博客)下载没什么难点,不写过程了完成后可以直接使用(参考B站视频)使用教程—— https://www.bilibili.com/v......
  • 使用Python-psycopg访问postgres、openGauss、MogDB
    摘要Psycopg是一种用于执行SQL语句的PythonAPI,可以为PostgreSQL、GaussDB数据库提供统一访问接口,应用程序可基于它进行数据操作。Psycopg2是对libpq的封装,主要使用C语言实现,既高效又安全。它具有客户端游标和服务器端游标、异步通信和通知、支持“COPYTO/COPYFROM”......
  • Python-Openpyxl使用教程
    在数据处理和报表生成过程中,Excel是一个经常使用的工具。Python中的openpyxl库可以让您通过编程方式读取、写入和操作Excel文件,从而实现自动化的数据处理和报表生成。本文将介绍openpyxl库的基本用法和常见操作,帮助您快速上手使用Python处理Excel文件。安装openpyxl首先,您需要......
  • MySQL - 使用navicate连接虚拟机中linux的mysql
    1、首先在命令行中使用ifconfig命令查看虚拟机IP地址,这个地址是输入到navicat主机名中的。 2、查看window本地Telnet有没有选上;没有的话就勾选上。 3、虚拟机Linux防火墙设置 使用systemctlstopfirewalld命令关闭防火墙#检查Linux防火墙设置状态systemctlstat......
  • Spring中@NotNull注解@Valid注解简介及使用
    前言在开发中,为了代码的稳定性不报空指针异常,经常需要判断前端传过来的值是否为空,为空的话就返回前端值为空的提示,才能进行下一步的操作,例如登录操作需要判断传过来的登录名和密码是否为空:@GetMapping("login")publicResultlogin(Useruser){if(StringUti......
  • 大模型应用开发:手把手教你部署并使用清华智谱GLM大模型
    部署一个自己的大模型,没事的时候玩两下,这可能是很多技术同学想做但又迟迟没下手的事情,没下手的原因很可能是成本太高,近万元的RTX3090显卡,想想都肉疼,又或者官方的部署说明过于简单,安装的时候总是遇到各种奇奇怪怪的问题,难以解决。本文就来分享下我的安装部署经验,包括本地和租用云......
  • Python APScheduler介绍及使用
    在许多应用程序中,需要定期执行某些任务,例如发送电子邮件、生成报告或清理临时文件等。为了管理和调度这些任务,Python中有许多优秀的调度器库,其中APScheduler是一个流行且功能强大的选择。本文将介绍APScheduler的基本概念,并展示如何使用它来实现定时任务调度。一、APScheduler简......
  • 国内如何才能使用GPT4
    ......
  • 美国政府敦促开发者:停止使用 C、C++
    “C、C++不安全,新应用开发时就别用了,旧应用应该采取迁移行动”,近日,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的19页PDF报告中强烈呼吁道。其直言,C和C++这几种编程语言既缺乏与内存安全相关的特性,又在关键系统中大量使用,可......
  • Redis数据库安装与使用总结
    Redis语句总结一、基本概念Redis全称:RemoteDictionaryServer(远程字典服务器)的缩写,以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容。使用C语言编写,并以内存作为数据存储介质,所以读写数据的效率极高*redis的官方只提供了linux版本的redis,window系统的redis......