为啥 OpenMP 'simd' 比 'parallel for simd' 有更好的性能?

Posted

技术标签:

【中文标题】为啥 OpenMP \'simd\' 比 \'parallel for simd\' 有更好的性能?【英文标题】:Why OpenMP 'simd' has better performance than 'parallel for simd'?为什么 OpenMP 'simd' 比 'parallel for simd' 有更好的性能? 【发布时间】:2015-03-15 09:01:59 【问题描述】:

我正在使用英特尔编译器 OpenMP 4.0 开发英特尔 E5(6 核,12 线程)

为什么这段代码 SIMD-ed 比并行 SIMD-ed 更快?

for (int suppv = 0; suppv < sSize; suppv++) 
  Value *gptr = &grid[gind];
  const Value * cptr = &C[cind];

  #pragma omp simd // vs. #pragma omp parallel for simd
  for (int suppu = 0; suppu < sSize; suppu++)
    gptr[suppu] += d * cptr[suppu];

  gind += gSize;
  cind += sSize;

线程越多,速度就越慢。


编辑 1: * grid是一个4096*4096的矩阵,数据结构:vector&lt;complex&lt;double&gt;&gt; * C 是一个2112*129*129 矩阵,数据结构:vector&lt;complex&lt;double&gt;&gt; * gSize = 4096 * sSize = 129.

编译器标志:icpc -march=native -std=c++11 -qopt-report-phase=vec -qopt-report=3 -O2 -openmp

计时器:使用 POSIX times() API 的返回值差异。 (它确实使用挂钟进行并发,我做了检查)

E5 线程 1 SIMD 占用:291.520000 (s)

E5 线程 2 for-SIMD 占用:1039.220000 (s) E5 线程 12 for-SIMD 占用:1684.270000 (s)

【问题讨论】:

慢多少?你是怎么测量的?你检查过装配吗?您是否尝试让线程数与内核数相同? sSize 有多大?作为gridC 连续,为什么有两个循环(啊,只对C 的前缀进行操作,奇怪)。还有什么平行的吗?你在一个小程序中演示这个吗?你的编译器标志是什么,记录的实际时间是多少? 【参考方案1】:

如果sSize = 129,就像您在编辑中所做的那样,那么并行化循环的开销不会得到回报。如果您向我们展示顺序实现(无 SIMD)和纯并行实现(即使用#pragma omp parallel for 但没有 SIMD)的数量,这将更容易确认。

可能发生的情况是,即使是纯并行版本也比顺序版本慢。当您为最外层循环的每次迭代启动/创建一个并行区域时,不仅减少了循环大小。

至于 SIMD 版本,这个问题本质上是为此量身定制的:您有一个高度可向量化的内核,它太小而无法在线程之间分配。

【讨论】:

宾果游戏。如果每个人都要做很多的工作,启动工作线程任务是很有用的。并行化 129 个 add/muls 距离一个好主意还有几个数量级。

以上是关于为啥 OpenMP 'simd' 比 'parallel for simd' 有更好的性能?的主要内容,如果未能解决你的问题,请参考以下文章

为啥向量长度 SIMD 代码比普通 C 慢

带有 Altivec 的 SIMD:为啥将两个向量相乘比相加两个向量更快?

OpenMP 为内联函数声明 SIMD

知道 OpenMP 4.0 会产生啥 SIMD 指令吗?

嵌套循环的 OpenMP SIMD 矢量化

使用 Rcpp 和 OpenMP 在 R 中多线程和 SIMD 矢量化 Mandelbrot