来源

群里 H 老师报告 node7 上跑某著名 CFD 商业软件比其它节点慢一倍以上,问我有没有类似经历。

测试

我来测试一下我的 NFR 程序。结果发现确实 node7 上比其它节点慢,如下图

node7 节点上 NFR 比其它节点慢 24%
node7 节点上 NFR 比其它节点慢 24%

node7 上 NFR 跑完需要 76 秒, node4 上跑完需要 61.5 秒。 所以 node7 慢的表现是某著名 CFD 商业软件慢一倍以上,我的 NFR 慢 24%。

但是单核跑 NFR 在 node7 和 node4 上没有性能差异。

解决

Linux 上性能分析参考 Brendan D. Gregg 大神的网站。 了解到使用 perf 给出性能统计报告,也就是上面的图。perf 使用参考 Brendan D. Gregg 大神的网页。 perf 可以直接统计 MPI 并行程序的性能。

首先使用perf stat -d mpirun -n 40 prog input.file发现 node7 上 NFR 的 page-faults 是 node4 上的 3 倍。

先了解 page-faults 是什么。 参考page fault带来的性能问题。 几个要点

  • Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源。
  • 虚拟的内存地址和物理的内存地址之间保持一种映射关系,这种关系由 MMU 进行管理。
  • 需要访问的内存不在虚拟地址空间,也不在物理内存中,需要从慢速设备载入,称为 major page fault
  • 需要访问的内存不在虚拟地址空间,但是在物理内存中,只需要MMU建立物理内存和虚拟地址空间的映射关系即可,minor page fault
  • 进程需要访问的内存地址不在它的虚拟地址空间范围内,属于越界访问,内核会报segment fault错误

MMU
MMU

所以进一步来看下到底是 major 还是 minor 类型。

指定 perf 的具体分析类型:perf stat -d -e major-faults,minor-faults,mem-loads,mem-stores mpirun -n 40 prog input.file, 得到最上面对比图中 minor-faults 在 node7 上是 node4 的 3 倍。 所以 node7 上串行运行 NFR 没有性能差异,并行 40 核运行出现 3 倍的 minor-faults。 这个可能与现代 CPU-Memory 架构有关,即 NUMA 架构。

参考NUMA架构的CPU – 你真的用好了么?。要点如下

  • 之前所有CPU Core都是通过共享一个北桥来读取内存,随着核数如何的发展,北桥在响应时间上的性能瓶颈越来越明显
  • NUMA 中,虽然内存直接与 CPU 紧邻,但是由于内存被平均分配在了各个裸晶 (die) 1上。只有当 CPU 访问自身直接相连的内存对应的物理地址时,才会有较短的响应时间(后称 Local access )。而如果需要访问其他 CPU 紧密相连的内存数据时,就需要通过 inter-connect 通道访问,响应时间就相比之前变慢了(后称 Remote access )。所以 NUMA(Non-Uniform Memory Access)就此得名。
  • Linux 识别到 NUMA 架构后,默认的内存分配方案就是:优先尝试在请求线程当前所处的 CPU 的本地内存上分配空间。如果本地内存不足,优先淘汰本地内存中无用的 page(Inactive,Unmapped)
  • 此文主要讨论 NUMA 中 CPU 对远端内存访问慢的特点导致 MySQL 性能变差。

NUMA
NUMA

从此文中得到启发,进一步检查 node7 上 NUMA 状态。node7 上居然没有numa_miss,如下

$ numastat
                           node0           node1
numa_hit               697457403       665306702
numa_miss                      2       378900577
numa_foreign           378900577               2
interleave_hit            315713          420961
local_node             697270591       666054700
other_node                186814       378152579

而 node4 上就有 numa_miss

$ numastat
                           node0           node1
numa_hit             36121273007      7797037099
numa_miss                7027051      1552203057
numa_foreign          1552203057         7027051
interleave_hit            266562          281401
local_node           36120608738      7797778236
other_node               7691320      1551461920

进一步检查 NUMA 设定: numactl --hardware

NUMA hardware info
NUMA hardware info

可以看到 node7 上 NUMA 的 free 很少,只有 435MB,正常的 node4 有 60GB。 可以推测是 node7 上极少的 free NUMA 导致了 3 倍的 minor page faults。 NUMA free 少应该是被缓存占了,相关术语是 page cache。 所以应该清理 page cache。 上面文章中给出的一个解决 NUMA 问题的方案是

echo 3 > /proc/sys/vm/drop_caches

在 node7 上使用 root 执行上述命令后,node7 性能恢复正常。

node7 节点上 NFR 性能正常
node7 节点上 NFR 性能正常

如果想令系统自动清理缓存,参考Linux下清理内存和Cache方法 /proc/sys/vm/drop_caches,不过我并没有测试。 留待以后尝试。


  1. A die, in the context of integrated circuits, is a small block of semiconducting material on which a given functional circuit is fabricated. ↩︎