我正在开发密集矩阵乘法代码(https://github.com/zboson/gemm)以了解并行编程。我使用OpenMP进行线程化。我的系统有四个插座,每个插座都配有Xeon E5-1620处理器。每个处理器有10个内核/ 20个超线程。所以总数是40核/ 80超线程。当我在一个线程上运行我的代码时,我获得了大约70%的峰值触发器(19.2 GFLOPS中的13个)。但是,当我使用40个线程运行我的代码时,我只得到大约30%的峰值触发器(682.56 GFLOPS中的185个)。在一个单独的系统(Sandy Bridge)上,只有一个插座和4个内核,四个线程的效率提高了65%。
我将线程绑定到每个物理核心using system calls。我尝试过禁用此功能,而是使用export OMP_PROC_BIND=true
或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"
,但这些没有区别。我仍然可以获得大约30%的效率(尽管我可以通过其他不良绑定设置降低效率)。
我还能做些什么来提高效率?我理解使用first touch policy因此内存页面由触及它们的第一个线程分配。当我写出矩阵产品时,我可能会为每个套接字单独输出,然后合并每个套接字的结果吗?
我使用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
答案 0 :(得分:1)
怀疑由于过多的交叉套接字通信导致效率下降是合理的。但是设置线程亲和性不足以避免这些通信,它应该在算法级别上解决,例如,以最小化跨节点交互的方式划分工作。最好的方法是在cache-oblivious way中实现它,例如并行不是按行或列,而是按2d图块。
例如,您可以将tbb :: parallel_for
与blocked_range2d
一起使用,以便更有效地使用缓存。
更高级别的并行性导致效率下降也可能表明没有足够的工作来证明同步开销是合理的。