0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

numactl内存绑定中代码段的问题

Linux阅码场 来源:Linux阅码场 作者:宋宝华 2021-05-10 14:20 次阅读

numactl内存绑定中代码段的问题

代码段为什么没有进入指定的numa节点

内核内存管理一个改进方向建议

在一个典型的NUMA架构Linux服务器中,我们常常使用类似numactl -N 1 -m 1 。/a.out类似的命令来绑定一定进程的memory,比如上面的例子,进程的memory被绑定到NUMA1。

但是这个时候,我们用numastat命令去查看进程a.out的内存分布,很可能会发现它有少部分内存不在NUMA1:

f1f6365c-b03c-11eb-bf61-12bb97331649.png

有极少量0.75MB在NUMA0。这是不是说numactl -m 1没有起作用呢?瞎猜没用,眼见为实,我们来调查一下这个在NUMA0的内存属于进程的哪一部分。

f2253d3a-b03c-11eb-bf61-12bb97331649.png

基本上可以看出,有3个地方有位于N0的内存,比如:

开始地址是0x40000的,文件背景为/root/a.out的部分;

开始地址是0x7fb9afc000,文件背景为/lib/aarch64-linux-gnu/libc-2.23.so的部分;

开始地址为0x7fb9c42000,文件背景为/lib/aarch64-linux-gnu/ld-2.23.so的部分。

如果我们进一步探究,会发现上面这三段,都是代码段:

f234b1a2-b03c-11eb-bf61-12bb97331649.png

为什么会这样呢?看起来numactl -m 《node》对代码段不起作用?

代码段为啥没进入指定numa?

原因其实是比较清晰的。上述代码段对应的内存,在Linux内核中,都属于有文件背景的页面,受page cache机制管理。

想象一个场景,如果a.out曾经运行过一次(其实我开机后已经在没有用numactl绑定内存的情况下,运行过一次a.out,上面的数据是第二次运行a.out的时候采集的),然后系统也加载了一些动态库,那么a.out本身的代码段,库的代码段可能进入到了numa节点m,从而在内存命中。接下来,如果我们用numactl -m 《n》 。/a.out去运行a.out并绑定numa节点n,势必要再次需要a.out的代码段以及a.out依赖的动态库的代码段。但是前一次,这些代码段都进入了page cache(位于NUMA node m),所以第2次在numa node n运行的时候,其实是命中了numa node m里面的内存。

假设我们运行4个a.out,这4个a.out分别运行于4个不同的numa,然后a.out依赖a.out的代码段、libx.so代码段,liby.so代码段。那么,完全有可能出现下图的情况,a.out的代码段位于numa0,libcx.so代码段位于numa1,liby.so的代码段位于numa2,这样4份运行中的a.out,都各自有跨NUMA的代码段内存访问,这样在icache替换的时候,都需要跨NUMA访问内存。

f261c278-b03c-11eb-bf61-12bb97331649.png

内核为什么这样做呢?原因在于,page cache的管理机制是以inode为单位的,每个page inode唯一!一个inode(比如a.out对应的inode)的page cache在内存命中的情况下,内核会直接用这部分page cache。这个page cache,不会为每个NUMA单独复制一份。从page cache的管理角度来讲,这没有问题。

我们把前面的a.out kill掉,然后drop一次cache,再看a.out的内存分布,发现在node0的部分减少了(0.75-》0.63)

f26b1508-b03c-11eb-bf61-12bb97331649.png

为什么呢?因为我drop掉部分page cache后(echo 3也不可能drop掉全部的所有的代码段,毕竟这里面很多代码是“活跃”代码),我们再运行a.out并绑定numa1的时候,这次这些没有命中的代码段page cache,会进入到numa1。

如果我们重启系统,开机第一次运行a.out就绑定numa1呢?这个时候,我们会看到a.out的代码段在numa1:

f27806c8-b03c-11eb-bf61-12bb97331649.png

然后我们把a.out kill掉,第二次绑定numa node0运行a.out,会发现这次的a.out的代码段还是在numa node1而不是node0:

f2bde5d0-b03c-11eb-bf61-12bb97331649.png

原因是它命中了第一次运行a.out已经进入node1的代码段page cache。

初恋为什么如此刻骨铭心,你终究还是错过了那个人,而多少年以后,常常回想起来,你依然泪流满面?因为,它命中了你的page cache。但是终究,一个人,一生可能不会只运行一次a.out。我们终究也要学会放手,把全部的爱,献给你身边与你相濡以沫的那个人。

内存管理的改进方向

2020年8月,我在Linux内核里面提交和合入了per-numa CMA的支持:

dma-contiguous: provide the ability to reserve per-numa CMA

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b7176c261cdbc

这样让每个NUMA里面的外设申请连续内存的时候,可以申请到本NUMA的近地址内存,而不用跑到远端去,从而提高I/O的性能:

f3421ef4-b03c-11eb-bf61-12bb97331649.png

考虑到代码段以及其他page cache的跨NUMA特点,这里我想提一个可能性,就是per-numa Page cache。内核可以支持让关键的代码段,文件背景页面,在每个NUMA单独获得一份page cache:

f35a3e3a-b03c-11eb-bf61-12bb97331649.png

它的缺点是显而易见的,page cache可能会用多份内存。它的优点也是显而易见的,就是代码段不用跨NUMA了。这属于典型的以空间换时间!

这个事情行不行得通呢?技术上是行得通的,实践上,我是不敢做的,因为需要大量的benchmark,加上patch至少得发20,30个版本,前后一两年至少的。别的不说,宋牧春童鞋的省vmemmap内存的patch已经发到了22版:

[PATCH v22 0/9] Free some vmemmap pages of HugeTLB page

https://lore.kernel.org/lkml/20210430031352.45379-1-songmuchun@bytedance.com/

要是干这个page cache的优化,不得至少发个30版?通常这种有利于全世界,而不利于自己的KPI的事情,是没有多少工程师愿意投入的 :-) 细思恐极,这需要极大的耐心、投入和奉献精神。

那么,前期是不是可以从一个小点开始优化呢?我觉得是可能的。

比如a.out本身在numa0运行,kill后再在numa1运行,这个时候,内核感知到a.out独一份,没有share的情况,是不是直接在内核态把page cache直接migrate到numa1呢?我这里还是打个嘴炮就好,把想象空间留给读者。

原文标题:宋宝华:为什么numactl内存绑定对代码段不起作用

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    2962

    浏览量

    73803
  • 代码
    +关注

    关注

    30

    文章

    4719

    浏览量

    68211

原文标题:宋宝华:为什么numactl内存绑定对代码段不起作用

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    机智云智家APP的设备扫描与绑定限制

    在使用机智云的智家APP时,用户可能会遇到无法扫描和绑定设备的问题。这一现象的根本原因在于智家APP的使用限制和付费策略。Q智家APP的功能概述是什么?智家APP是机智云平台为用户提供的公
    的头像 发表于 09-22 08:02 178次阅读
    机智云智家APP的设备扫描与<b class='flag-5'>绑定</b>限制

    超低功耗LCD笔式液晶显示驱动芯片VKL092Q简介

    ;DICE/DIE裸片(绑定COB);COG(绑定玻璃) 省电模式 VK1622 2.4V~5.2V 32seg*8com 偏置电压1/4 LQFP44/LQFP48/LQFP52/LQFP64
    发表于 07-15 15:51

    想通过perf工具来检查2不同代码内存占用率,但一直没找到,怎么办?

    想通过perf工具来检查2不同代码内存占用率,但一直没找到,怎么办?
    发表于 05-17 13:33

    鸿蒙开发接口Ability框架:【@ohos.application.formBindingData (卡片数据绑定类)】

    卡片数据绑定模块提供卡片数据绑定的能力。包括FormBindingData对象的创建、相关信息的描述。
    的头像 发表于 05-06 17:25 432次阅读
    鸿蒙开发接口Ability框架:【@ohos.application.formBindingData (卡片数据<b class='flag-5'>绑定</b>类)】

    udp_bind这个绑定的端口怎么解除?

    请教下,udp_bind 这个绑定的端口,刚开始是可以的,但是重新绑定时返回错误,有什么方法可以在 重新绑定前解除之前的绑定
    发表于 04-22 07:41

    C语言内存泄漏问题原理

    内存泄漏问题只有在使用堆内存的时候才会出现,栈内存不存在内存泄漏问题,因为栈内存会自动分配和释放。C语言
    发表于 03-19 11:38 441次阅读
    C语言<b class='flag-5'>内存</b>泄漏问题原理

    拆解mmap内存映射的本质!

    mmap 内存映射里所谓的内存其实指的是虚拟内存,在调用 mmap 进行匿名映射的时候(比如进行堆内存的分配),是将进程虚拟内存空间中的某一
    的头像 发表于 01-24 14:30 1344次阅读
    拆解mmap<b class='flag-5'>内存</b>映射的本质!

    服务器宝塔面板怎么绑定多个ip?

    服务器宝塔面板怎么绑定多个ip?在宝塔面板中绑定多个IP地址可以通过以下步骤完成: 1、登录宝塔面板 使用你的浏览器访问宝塔面板的网址,并使用管理员账号和密码登录。 2、进入站点管理 在宝塔面板左侧
    的头像 发表于 01-12 17:29 1534次阅读

    求教下source insight 的使用问题,关于#if #endif中的代码变暗的

    source insight 4.0在实际使用时,#if 0#endif会使中间的代码变暗,但假如我的#if 0是通过宏定义的,如图的IOT_PTINTF_TEST为0,代码就不会
    发表于 12-08 11:06

    如何绑定ip地址与mac物理地址呢?

    如何绑定ip地址与mac物理地址呢? 绑定IP地址与MAC物理地址是一种网络管理和安全措施,可以帮助确保网络设备的身份验证和安全性。在这篇文章中,我们将详细介绍如何进行IP地址与MAC物理地址的绑定
    的头像 发表于 12-07 09:33 6365次阅读

    devc怎么注释掉一代码

    在DevC中,要注释掉一代码,你可以使用注释符号来标记这段代码。注释符号的作用是告诉编译器不要编译这些代码,而是将其视为注释,这样可以方便开发人员在
    的头像 发表于 11-22 10:23 2272次阅读

    Linux内核驱动与单个PCI设备的绑定和解绑定

    在Linux内核2.6.13-rc3以前,驱动和设备之间的绑定和解绑只能通过insmod(modprobe)和rmmod来实现,但是这种实现方法有一个弊端,就是一旦绑定或者解绑定都是针对驱动与其
    的头像 发表于 11-17 17:11 1503次阅读
    Linux内核驱动与单个PCI设备的<b class='flag-5'>绑定</b>和解<b class='flag-5'>绑定</b>

    glibc的内存分配回收策略

    从上到下依次为stack栈(向下增长)、mmap(匿名文件映射区)、Heap堆(向上增长)、bss数据、数据、只读代码。 其中,Heap区是程序的动态
    的头像 发表于 11-13 11:16 613次阅读
    glibc的<b class='flag-5'>内存</b>分配回收策略

    内存池的使用场景

    为什么要用内存池 为什么要用内存池?首先,在7 * 24h的服务器中如果不使用内存池,而使用malloc和free,那么就非常容易产生内存碎片,早晚都会申请
    的头像 发表于 11-10 17:19 648次阅读
    <b class='flag-5'>内存</b>池的使用场景

    内存泄漏会产生哪些后果

    在申请的内存没有进行释放。 { void *p1 = malloc ( 10 ); void *p2 = malloc ( 20 ); free (p1);} 上面的代码,申请了两块内存
    的头像 发表于 11-10 15:06 750次阅读
    <b class='flag-5'>内存</b>泄漏会产生哪些后果