一个物理内存分布导致的问题

事出前些日子有人咨询我:“在某个关闭NUMA的双CPU机器上,通过lat_mem_rd跑分,为什么会出现差不多2倍的跑分差距?” 话说这里的lat_mem_rd是lmbench 的一个组件,它通过模拟排序来测试系统的内存读性能——主要是时延为主。

从一开始,我就认为这是UPI/QPI时延的叠加导致的。在一个双CPU的机器上,即便你关闭了NUMA,事实上两个CPU还是各承担了50%的内存读写。测试工具既然是基于排序的,了解过排序算法的人都应该知道,排序算法不论你采用什么样的排序,内存的读写都是极度不平均的。内存的分布不平均势必导致了两个socket之间的读写也是不平衡的,加上测试过程中测试的进程可能在两个个CPU之间摇摆,当落在近端内存时跑分自然就高一点;远端时自然就低。

大致方向定位以后,开始准备测试。既然如此,那我就通过taskset命令将测试的进程分别绑定到两个socket上,跑个结果出来。

lat_mm_rd 跑分
lat_mem_red 方差

No-fix(不做CPU绑定)的情况的跑分居中,但方差最大;socket 0 和socket的方差都非常小,但socket0的跑分好过socket1差不多一倍。和一开始的估计差不多,内存读写中,大量的内存都落在socke0的内存控制器上,socket1的内存访问都要经由UPI/QPI,导致了时延较大。而不做CPU绑定时,结果相当于混合了socket0和socket1两种情况,跑分自然介于两者之间,方差自然也小不了。

简单的描述了下结果,交了差。结论很清晰,对方也认可了这个解释。也就是大家都认为事情结束了的时候,问题又来了。那边发现换了一套机器之后无论怎么绑定CPU,测试的结果都非常稳定,直接挑战了我之前的解释。

苦于无法在本机重现两种状态,只能硬抓取数据了。期间写一个监视器,直接读取每个内存通道的瞬时读写带宽,输出socket0:socket1的带宽占比。不提。

Host A(方差小)Host B(方差大)
NO fix94%101%
绑定Socket016%93%
绑定Socket1622%110%

Host A的不正常在于:当使用CPU绑定的时候,只有大约1/6的数据访问落在本地,大多数都落在了远端。而方差大的Host B则尽可能的保持两个socket读写均衡——数值都非常接近1:1(100%)。受CPU绑定影响的内存访问Host A只占了1/6,而Host B则是1/2,自然效果更加明显。

顺道抓个时序图出来瞧瞧。

不出所料!这两套机器即便有了相同的CPU频率,相同的内存大小,相同的Linux kernel,但对于测试中反印出来的内存特性是完全不一样的。Host A由于读写不平衡,在测试阶段已经出现了其中一个socket的读瓶颈,测试自然而然的成为了一个非常稳定的极端值,而Host B似乎在内存读写均衡上下了不少功夫做优化,似乎离系统平静还有很远,但在这个测试中这点优化就起了反作用。

内存如何分布在具体物理DIMM插槽上,一直以来都是黑盒。加上了uma的场景,这个黑盒导致了测试结果更加抖动,几乎成了一个抽奖的结果。一开启NUMA的支持,什么方差的问题全都迎刃而解了!

推荐阅读:
继续在NUMA和性能差异的路上
首先列出本站之前相关的几篇帖子
NUMA(Non-Unifor

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据