缓解openmp并行延迟的措施

时间:2016-09-19 17:40:57

标签: c++ performance fortran mpi openmp

我从Fortran的角度编写了这个问题,但问题并不仅限于Fortran(因此是c ++标签)。

我有两个问题。我已经读过在OpenMP并行循环here的开始和结束时存在延迟。我的问题是:

Q1)有哪些实用措施可以缓解openMP延迟?

Q2)以下哪种方法表现更好?

方法1

 x = 1.0; y = 2.0
 !$OMP PARALLEL DO
 do k=1,Nz; do j=1,Ny; do i=1,Nx
 x(i,j,k) = x(i,j,k)+y(i,j,k)
 enddo; enddo; enddo
 !$OMP END PARALLEL DO

 !$OMP PARALLEL DO
 do k=1,Nz; do j=1,Ny; do i=1,Nx
 x(i,j,k) = x(i,j,k)*y(i,j,k)
 enddo; enddo; enddo
 !$OMP END PARALLEL DO
 ! (x should = 6.0 at this point)

方法2

 x = 1.0; y = 2.0
 !$OMP PARALLEL DO
 do k=1,Nz; do j=1,Ny; do i=1,Nx
 x(i,j,k) = x(i,j,k)+y(i,j,k)
 x(i,j,k) = x(i,j,k)*y(i,j,k)
 enddo; enddo; enddo
 !$OMP END PARALLEL DO
 ! (x should = 6.0 at this point)

方法3

1)创建一个包含过程数组的对象

2)按如下方式调用程序数组

 x = 1.0; y = 2.0
 !$OMP PARALLEL DO
 do k=1,Nz; do j=1,Ny; do i=1,Nx
 do t=1,procedure_array%N
 call procedure_array%single_procedure(t)%P(x(i,j,k),y(i,j,k))
 enddo
 enddo; enddo; enddo
 !$OMP END PARALLEL DO
 ! (x should = 6.0 at this point)

我们假设procedure_array%N = 2

 procedure_array%single_procedure(1)
 procedure_array%single_procedure(2)

分别指向子例程addx=x+y)和multiplyx=x*y)。

3)清理(解除分配)

评论

首先,很明显方法2优于方法1,所以我真的对方法2与方法3的比较感兴趣。其次,我知道“尝试看看”是一个有效的答案,但是我想知道方法3是否在实践(或行业)中使用的具体示例或概念性原因为什么方法3与方法2相比较差(例如由于许多过程调用引起的开销)。最后,如果可以采取某种特殊关注(例如,通过专门指定特定线程)来使方法2和3几乎相同,那么它们是什么?

我感谢任何帮助!

更新

根据评论,我做了以下更正。

  • 修改了操作(谢谢你,@ Gilles)
  • 删除了与MPI相关的所有内容,这真是一个悬而未决的问题(谢谢你,@ Vladimir)
  • 下面补充说明(我自己的意识)

非常感谢@innoSPG关于缓存内存(和缓存故障)的答案,这些内容非常丰富且有用!

澄清

最后,从评论中,我意识到这个问题的重点实际上是关于过程调用,而不是与openmp并行化严格相关。也就是说,我已经离开了openmp语句,因为这是我更复杂的应用程序中发生的事情,我希望尽可能保留它。从@ Chaosit的评论看来,程序调用将需要开销,减慢方法3.有没有办法解决这个问题?

另外,如果我错了,请纠正我,但我相信方法2中的两个操作将按书面顺序执行,从而产生正确的最终x值。

1 个答案:

答案 0 :(得分:4)

我的理解是,您正在寻找的差异(方法2和方法3)不依赖于并行化。

让我解释一下:

方法3可能会因为方法2中不存在的过程调用而产生另一个开销。我说可能是因为我不熟悉过程指针,但是,我的猜测是编译器的优化不会内联如果使用过程指针,则调用过程。

由于过程调用而产生的开销完全独立于并行化。您仍将在顺序代码中使用它。它不是并行化延迟的一部分。

现在,我冒着风险回到你不喜欢的选项:试试看。我冒这个风险是因为我相信你所展示的只是你问题的一个例子,你的实际案例更复杂。当您遇到复杂的情况时,您可能会惊讶于方法1和方法2之间的结论不再有效。它可能在很大程度上取决于您手头的问题。一个案件​​的结论不适用于另一个案件。像现在的编译器一样聪明,他们不会抓住一切。在计算机科学中,有一种高速缓冲存储器的概念有时候还不太清楚,但我不会详细介绍。您可以将方法1的每个单个循环(数据和/或代码)保存在高速缓存存储器中,而情况2的组合循环不保存在高速缓冲存储器中。简单说明是方法2在内循环内经历高速缓存故障而方法1不经历高速缓存故障的情况。在这种情况下,您将看到方法1高于大循环边界的方法2。

这就是Try and see成为标准的地方,这就是现实案例中大部分时间都会发生的事情。