【问题标题】:Measures to mitigate openmp parallel latency缓解 openmp 并行延迟的措施
【发布时间】:2017-01-27 11:46:39
【问题描述】:

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

我有两个问题。我读过 OpenMP 并行循环 here 的开始和停止存在延迟。我的问题是:

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

Q2) 以下哪种方法的效果会更好?

方法一

 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)

分别指向子程序add (x=x+y) 和multiply (x=x*y)。

3) 清理(解除分配)

评论

首先,显然方法 2 优于方法 1,所以我对方法 2 和方法 3 的比较非常感兴趣。其次,我知道“试试看”是一个有效的答案,但是我想知道在实践(或行业)中是否存在方法 3 的具体示例或方法 3 不如方法 2 的概念原因(例如,由于许多过程调用导致的开销)。最后,如果可以采取某种特殊措施(例如,通过专门指定特定线程)使方法 2 和 3 几乎等效,它们是什么?

感谢您的帮助!

更新

鉴于cmets,我做了以下更正。

  • 修改了操作(谢谢@Gilles)
  • 删除了与 MPI 相关的所有内容,这确实是一个 openmp 问题(谢谢,@Vladimir)
  • 在下面添加了说明(我自己意识到)

感谢@innoSPG 关于缓存内存(和缓存故障)的回答,这非常有用且很有帮助!

澄清

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

另外,如果我说的不对还请指正,但我相信方法2中的两个操作会按照写好的顺序执行,从而得到正确的最终x值。

【问题讨论】:

  • 撇开 sn-ps 中的两个计算都没有意义(好吧,这只是为了表明我们进行了一些计算),事实证明 方法 1method 2 不等价,因为顺序很重要(在这种情况下很重要)。所以你关于“方法 2 优于方法 1”的断言是非常值得怀疑的,因为如果引用是从 方法 1 获得的结果,那么 方法 2 是错误的(除非a=b=0 )。我知道,这不是你的意思,但我完全赞成正确性而不是效率。
  • “MPI 并行化循环” 到底是什么意思?没有这样的事情。

标签: c++ performance fortran mpi openmp


【解决方案1】:

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

让我解释一下:

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

由于过程调用而产生的开销与并行化完全无关。您仍然可以在顺序代码中使用它。它不是并行化延迟的一部分。

现在,我冒着风险回到你不喜欢的选项:试试看。我冒这个险是因为我相信你所展示的只是你的问题的一个例子,你的实际情况更复杂。当您遇到复杂的情况时,您可能会惊讶于方法 1 和 2 之间的结论不再有效。它可能在很大程度上取决于您手头的问题。一个案例的结论不适用于另一个案例。尽管编译器现在很聪明,但它们不会捕获所有内容。在计算机科学中,有一个缓存内存的概念有时不太好理解,但我不会详细介绍。您可能会遇到这样一种情况,即方法 1 的每个单个循环(数据和/或代码)都保存在缓存中,而情况 2 的组合循环不保存在缓存中。简单的说明是方法 2 在内部循环中遇到缓存故障而方法 1 没有的情况。在这种情况下,您会看到方法 1 在大循环边界方面比方法 2 优越得多。

这就是Try and see 成为标准的地方,这也是现实生活中大部分时间发生的情况。

【讨论】:

  • 第三种方法是对的——与前两种方法相比,它很可能会更慢,因为过程指针是在运行时而不是在编译时解析的。因此,编译器不能做任何事情来优化这部分代码——它必须按原样使用它。至于前两种方法之间的比较——这在很大程度上取决于编译器——但对于现代编译器,我希望两者都能同样快速地执行
猜你喜欢
  • 1970-01-01
  • 2018-06-20
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 2018-06-06
  • 2013-12-01
  • 2015-01-12
  • 1970-01-01
相关资源
最近更新 更多