使用 openMP 和 openACC 的多线程多 GPU 计算

Multi-threaded multi GPU computation using openMP and openACC

我正在尝试编写将 openmp 线程移植到单个 gpu 的代码。我在 this.Since 上发现的案例研究/代码非常少我不是计算机科学背景。 我的编程技能比较差

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

这里有很多问题。

首先,您不能将 OpenMP(或 OpenACC)并行循环放在一个 do while 上。 do while have indeterminant number to iterations for therefore create a dependency in that exiting the loop depends on the previous iteration of the loop.您需要使用 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,您的代码还可以跨节点,而不是仅限于单个节点。