矩阵乘法在4插槽NUMA系统上的效率很差



我正在开发密集矩阵乘法代码(https://github.com/zboson/gemm)来学习并行编程。我使用OpenMP线程。我的系统有四个插槽,每个插槽都有Xeon E5-1620处理器。每个处理器有10个核心/20个超线程。所以总共是40个核/80个超线程。当我在一个线程上运行我的代码时,我得到了大约70%的峰值flops (19.2 GFLOPS中的13个)。然而,当我使用40个线程运行我的代码时,我只得到峰值flops的30%左右(682.56 GFLOPS中的185个)。在一个单独的系统(Sandy Bridge)上,只有一个插槽和4个内核,我得到了大约65%的效率,四个线程。

我使用系统调用将线程绑定到每个物理核心。我试过禁用这个并使用export OMP_PROC_BIND=trueexport GOMP_CPU_AFFINITY="0 4 8 12 16 20 24 28 32 36 1 5 9 13 17 21 25 29 33 37 2 6 10 14 18 22 26 30 34 38 3 7 11 15 19 23 27 31 35 39",但这些没有区别。我仍然得到大约30%的效率(尽管我可以得到更低的效率与其他糟糕的绑定设置)。

我还能做些什么来提高我的效率?我理解使用第一次触摸策略,因此内存页面由第一个触摸它们的线程分配。当我写出矩阵乘积的时候也许我应该为每个套接字做一个单独的输出然后最后合并每个套接字的结果?

我正在使用GCC 4.8.0和Linux 64位内核2.6.32

编辑:我使用以下绑定矩阵大小= 2048x2048
export GOMP_CPU_AFFINITY="0 4 8 12 16 20 24 28 32 36 1 5 9 13 17 21 25 29 33 37 2 6 10 14 18 22 26 30 34 38 3 7 11 15 19 23 27 31 35 39"

应该有线程0-9 ->节点0,10-19节点1,20-29节点2,30-39节点3。

使用这个绑定,我得到:

 nthread    efficiency    node
 1          77%           0
 2          76%           0
 4          74%           0
 6          62%           0
 8          64%           0
10          52%           0
14          50%           0+1
16          30%           0+1

有理由怀疑效率下降也是由于太多的跨套接字通信。但是设置线程亲和性不足以避免这些通信,它应该在算法层面上解决,例如,以最小化跨numa-node交互的方式划分工作。最好的方法是以一种无关缓存的方式来实现它,例如,不是通过行或列来并行,而是通过二维块来并行。

例如,您可以将tbb:: parallel_forblocked_range2d一起使用,以便更有效地使用缓存。

更高的并行度导致的效率下降也可能表明没有足够的工作来证明同步带来的开销。

最新更新