使用 openMP 和 openACC 的多线程多 GPU 计算
Posted
技术标签:
【中文标题】使用 openMP 和 openACC 的多线程多 GPU 计算【英文标题】:Multi-threaded multi GPU computation using openMP and openACC 【发布时间】:2021-12-17 07:56:18 【问题描述】:我正在尝试编写将 openmp 线程移植到单个 gpu 的代码。我发现的案例研究/代码非常少。因为我不是计算机科学背景。 我在编程方面的技能较少。
This is how the basic idea look's like
这是迄今为止开发的代码。
CALL OMP_SET_NUM_THREADS(2)
!$omp parallel num_threads(acc_get_num_devices(acc_device_nvidia))
do while ( num.gt.iteration)
id = omp_get_thread_num()
call acc_set_device_num(id+1, acc_device_nvidia)
!!$acc kernels
!error=0.0_rk
!!$omp do
!$acc kernels
!!$omp do
do j=2,nj-1
!!$acc kernels
do i=2,ni-1
T(i,j)=0.25*(T_o(i+1,j)+T_o(i-1,j)+ T_o(i,j+1)+T_o(i,j-1) )
enddo
!!$acc end kernels
enddo
!!$omp end do
!$acc end kernels
!!$acc update host(T,T_o)
error=0.0_rk
do j=2,nj-1
do i=2,ni-1
error = max( abs(T(i,j) - T_o(i,j)), error)
T_o(i,j) = T(i,j)
enddo
enddo
!!$acc end kernels
!!$acc update host(T,T_o,error)
iteration = iteration+1
print*,iteration , error
!print*,id
enddo
!$omp end parallel
【问题讨论】:
【参考方案1】:这里有很多问题。
首先,您不能在 do while 上放置 OpenMP(或 OpenACC)并行循环。 while 是否有不确定的迭代次数,因此会创建一个依赖关系,即退出循环取决于循环的前一次迭代。您需要使用 DO 循环,其中迭代次数在进入循环时是已知的。
其次,即使将其转换为 DO 循环,如果并行运行,也会出现竞争条件。每个 OpenMP 线程都会将值分配给 T 和 T_o 数组的相同元素。加上 T_o 的结果被用作下一次迭代的输入,创建一个依赖。换句话说,如果你试图并行化外部迭代循环,你会得到错误的答案。
对于 OpenACC 代码,我建议在迭代循环周围添加一个数据区域,即 "!$acc data copy(T,T_o)" 在迭代循环之前和循环之后 "!$acc end data" ,以便数据仅在设备上创建一次。正如您现在所拥有的那样,每次通过迭代循环都会隐式创建和复制数据,从而导致不必要的数据移动。还在最大误差减少循环周围添加一个内核区域,以便将其卸载。
一般来说,我更喜欢使用 MPI+OpenCC 进行多 GPU 编程而不是 OpenMP。使用 MPI,域分解是固有的,然后您就有了 MPI 等级到设备的一对一映射。并不是说 OpenMP 不能工作,而是您通常需要手动分解域。此外,尝试管理多个设备内存并使它们保持同步可能会很棘手。加上 MPI,您的代码还可以跨节点而不是仅限于单个节点。
【讨论】:
是的,MPI+OpenACC 是一个不错的选择,但我们部门的其他人已经尝试过,即 MPI+OpenACC 与域分解,但在多个节点上的通信开销非常高。这就是为什么我尝试使用使用单节点和多 GPU 的 OpenMP+OpenACC 进行编码的原因。问题再次是我找不到任何相关代码,它利用 OpenMP+OpenACC 进行科学计算。以上是关于使用 openMP 和 openACC 的多线程多 GPU 计算的主要内容,如果未能解决你的问题,请参考以下文章