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

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

    关注

    9

    文章

    3173

    浏览量

    76121
  • 代码
    +关注

    关注

    30

    文章

    4942

    浏览量

    73160

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

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    单片机程序的执行

    ,还是差着几个数量级,所以拷贝到DDRRAM中。这时,一个程序的代码和数据是连续存放的,其中代码是只读区域,数据是可读写区域(这是由操作系统的
    发表于 12-04 06:20

    汇编程序的定义介绍

    指令部分)... MOVAX, 4C00H INT21H CODE ENDS ENDSTART 语法解读: 程序开始的两条指令都是用于装载数据寄存器DS的。进入程序后,代码寄存器CS中的值
    发表于 11-21 08:19

    编译器如何指定代码的地址

    我在官方 gcc 的基础上添加了自定义指令,目前可以正确编译出汇编代码,但是我该如何指定汇编结果的地址,让生成的代码符合蜂鸟的地址分配呢?求助大神帮助指导一下,thx~
    发表于 11-10 06:06

    时序约束管脚绑定不成功问题

    {[新手提问]: 关于引脚绑定问题}在绑定vivado引脚中时,选项中没有原理图可绑定的引脚,需要绑定的引脚在l/O Bank88,但是我需要绑定
    发表于 08-21 17:18

    如何将 UID 代码绑定到 M031 LDROM 和 APROM 固件?

    将 UID 代码绑定到 M031 LDROM 和 APROM 固件
    发表于 08-20 06:38

    请问OpenVINO™ 是否支持 Rust 绑定

    无法确定OpenVINO™是否支持 Rust 绑定
    发表于 06-25 07:45

    在OpenVINO™ C++代码中启用 AddressSanitizer 时的内存泄漏怎么解决?

    在 OpenVINO™ C++代码中启用 AddressSanitizer 时遇到内存泄漏: \"#0 0xaaaab8558370 in operator new(unsigned
    发表于 06-23 07:16

    飞凌嵌入式ElfBoard ELF 1板卡-uboot编译链接文件uboot.lds

    。uboot.lds中规定了整个uboot的程序入口点(此入口点可以在Makefile文件中进行了更改,将入口地址定位到了内存中0X87800000位置),链接器以这个入口点为基点,将各个.o文件中代码.text
    发表于 05-22 11:20

    harmony OS NEXT-双向数据绑定MVVM以及$$语法糖介绍

    保持同步的机制,当数据发生变化时,UI自动更新;反之,当用于通过UI代码操作修改数据时,数据模型也会同步更新,这种机制简化了开发,减少了手动DOM或UI组件的代码量,举个简单的例子,比如输入框和变量的绑定,用户输入变量更新,变量
    的头像 发表于 04-29 16:52 1119次阅读

    无法在iMX8上启动gpsd:GPSD绑定怎么解决?

    3.19) gpsd:错误:无法绑定到 IPv4 端口 gpsd,地址已在使用 gpsd:ERROR: 也许 gpsd 已经在运行了! gpsd:错误:无法绑定到 IPv6 端口 gpsd,地址已在
    发表于 04-04 07:58

    快速搞懂C语言程序内存分区!

    到动态分配的数据等内容。(内存分区图示)理解这些内存分区的结构和特性,不仅有助于编写更高效的代码,还能帮助排查和解决如错误、内存泄漏、栈溢
    的头像 发表于 03-14 17:37 1342次阅读
    快速搞懂C语言程序<b class='flag-5'>内存</b>分区!

    电池电量计的通信、配置、数据内存访问以及相关代码示例

    德州仪器(Texas Instruments)发布的关于电池电量计通信的应用报告,主要介绍了电池电量计的通信、配置、数据内存访问以及相关代码示例等内容,为开发者提供了全面的技术指导。电量计通信
    发表于 03-11 15:45 0次下载

    分析C语言代码结构的设计问题

    来分析一个C语言代码结构的设计问题。 这段代码,使用了两次malloc,分别给 p1 和 p2 申请了内存。用完后,内存释放,防止内存泄漏。
    的头像 发表于 02-11 09:31 680次阅读

    labview完成该操作内存不足

    程序运行一时间后显示内存不足 这是为什么?是否是程序结构冗余?
    发表于 01-04 14:26

    养成良好的编程习惯|堆内存初值不一定是0

    ;} 代码很简单,使用 malloc 申请一内存,假设内存空间足够大。 通过 getchar 配合 while 循环,从标准输入获取一个字符串,直到遇到换行符结束。 最后就是把获取
    的头像 发表于 12-18 09:14 574次阅读