一个测试性能不稳定的问题

经常会通过一些通用的测试工具测试一些服务器的性能,个人非常喜欢SPEC的一系列产品,特别是SPECcpu。SPECcpu原理上通过接近30种不同特性的组件的执行时间对服务器的计算吞吐能力进行一个客观的评价。当然,由于计算机的硬件配置不同,不同的程序跑分各有千秋,但有一点也是SPECcpu能够成为业界标准之一的原因是跑分结果的稳定。这么说不夸张:如果其中的一个测试组件两次跑分差距超过5%,请仔细检查环境有没有变化。

偏偏最近就是被是这个“非常稳定”的SPECcpu测试成绩折腾了很久。

事出同事发现某个SPECcpu2017测试组件bwaves(事实上它是浮点性能测试的第一个组件)的测试成绩有着非常明显的测试偏差,误差范围超过7% (取stdev/average即变异系数,下同)。仅针对bwaves且多套类似配置的主机上均无法复现。该主机为双skylake Xeon,搭配8根16G DDR4-2666内存,算是比较常见的服务器搭配。由于测试数据太多,只能让同事单独隔离那台主机翻来复去的跑bwaves试图找出规律。大约2周左右,居然找出完整最小重现规律来了:“当设定bwaves跑在仅跑在socket1(空闲出socket0)且以主机OS重启为节点;前两次测试bwaves的跑分会大幅低于平均值,第三四两次的结果会高于均值,之后测试成绩逐步抖动收敛到均值……”

摸不着头脑,不可理喻!讲道理作为一个软件工程师居然能相信会有这么妖的重现方式,居然不是“清缓存、重启、重装”的三板斧!自己远程登上KVM重装系统、重装应用程序,手工执行个几次,居然还真是100%复现。脱敏(与同机同配置16次结果均值的比,下同)之后的跑分数据如下,误差范围±7.94%:


round_1round_2round_3round_4round_5
bwaves rate92%92%111%107%98%

8%的性能差距被形容起来好比说买了一盒一打装的鸡蛋拿回来结果发现少了一个😛,当然,相比其他“表现正常”的同配置主机,该主机的bwaves跑分实际只有55.63%,属于严重缩水。

花了大量的时间检查过各种可能的设置错误之后均无果而终,于是决定从bwaves的特性入手看看bwaves到底对什么样的系统配置敏感。得到的结果是内存带宽,于是采集了改主机在运行bwaves时的内存带宽变化情况,但得到内存带宽的变化真的很小,不足以证明为什么会有“低低高高中”的规律。

问题在于特别是在第二轮和第三轮之间到底发生了什么。

该主机有8×16=128G内存,OS同样显示了该主机128G内存。由于NUMA开启,每个socket只能使用64G内存。我们为此主机设置的bwaves的测试需要实际占用10~12G内存空间。于是我调整了一下bwaves的测试脚本让它使用更多的内存空间。结果数据就成了“低高中中”。我已经了解问题的所在,要求同事检查下内存插槽,顿时恍然大悟。

Skylake xeon

Skylake这一代XEON CPU每个socket上有两个独立的内存控制器分管两块不同的内存空间,如上图所示内存控制器即上图中黄色的imc。每个skylake imc支持3通道,每通道2根内存,两个socket总计支持6个通道合12根内存。

和磁盘raid阵列类似,interleave的缘故通道越多性能越好。

但测试中的服务器由于成本考量,只安装了8根内存条合每个socket只安装4根。
问题来了,如果你在6根内存槽中选择4根的话你会怎么选?相信大多数人的选择是前四个,后面两个留空。这样的做法恰恰是错误的!对于skylake这类每个socket上即成了多个内存控制器的CPU来说,这样的话恰好让一个imc是3通道加持,另一个imc仅有1通道(3+1)。两个imc之间内存带宽不均衡性能自然不均衡。另外该主机的主板走线使得2+2对称插法非常不顺手,于是偷懒似乎成了理所当然。

重新移动了内存条之后(2+2),性能稳定,偏差范围±0.23%,平均分也匹配预期。


round_1round_2round_3round_4round_5
bwaves rate99.88%99.88%100.46%99.88%99.88%

如果你一直看到这里你可能会觉得我好像还是没有解释为什么会有“低低高高中”的规律。

  1. 在系统刚刚启动好之后,一般socket1上不会有过任务请求过大量内存空间,也就是说内存调度器在socket1上有大量可分配的连续空闲内存。socket0相对噪声更多,内存碎片化较socket1多。
  2. 不正确的内存插法导致了同一个socket上部分(1/4)内存地址的性能较预期值差。而整体的不平衡内存访问导致整体的性能无法提升。
  3. 当前两次分配bwaves内存时,恰好分配的内存地址大多都是在单通道imc上。Linux kernel的内存页回收机制并不积极的回收内存页(这里不展开讲Linux的内存页管理 buddy system和内存碎片的关系)。
  4. 第三次开始分配的地址空间已经转移到3通道imc上,性能会好很多。高于2+2的内存配置,表现出来的就是较高的性能。
  5. 所有连续内存页分配结束后kernel只能分配相对连续,宏观上导致后期的测试数据逐步趋于两者的平均值。

我第二次测试的结果加大了程序内存大小,自然也加速了这个过程,不过真正触发这个妖异的现象我承认也是有运气的成分在内。而且运气更好的是,通过逆向分析测试数据,我找到了一个通过较低权限软件方式简易识别内存DIMM插法的可行性并实现成功。

考虑到类似的双skylake xeon服务器某家知名大厂居然有脑残的10根内存产品,要知道10无法整除4!于是特地去检查10内存主机的测试数据。怎么说呢?毕竟嘛2:3根1:3比起来还是更接近于1:1,只能说有类似情况的趋势,但没足够的理由认定这是问题,只能随他去了。

总结:

  • 在细节上面较真是没错的。确实会用螺丝刀的人就能学会装电脑,可谁知里面细节上其实大有讲究。
  • 别为了省个几百块钱给几万块钱的东西埋下炸弹。
  • 另,老外更习惯12进制的偏见是做实了。
推荐阅读:
首先,提个问题:64bit x
接到一个黑盒的case:一套双
去年的DCDC,我主要介绍了基

发表评论

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

请补全下列算式: *

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