【发布时间】: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 中的两个计算都没有意义(好吧,这只是为了表明我们进行了一些计算),事实证明 方法 1 和 method 2 不等价,因为顺序很重要(在这种情况下很重要)。所以你关于“方法 2 优于方法 1”的断言是非常值得怀疑的,因为如果引用是从 方法 1 获得的结果,那么 方法 2 是错误的(除非
a=b=0)。我知道,这不是你的意思,但我完全赞成正确性而不是效率。 -
“MPI 并行化循环” 到底是什么意思?没有这样的事情。
标签: c++ performance fortran mpi openmp