在OpenACC中有效使用记忆

时间:2015-09-04 17:31:48

标签: memory constants gpu shared-memory openacc

我正在研究OpenACC计算流体动力学代码,通过将整体计算分解为一堆小型操作来增加循环内计算的粒度。我的最终目标是通过将原始复杂任务拆分为GPU上更简单的一系列任务来减少每个威胁的寄存器数量。

例如,我有许多公式可以计算计算域的特定节点:

!$acc parallel loop ...
do i=1,n
  D1 = s(i+1,1) - s(i-1,1)
  D2 = s(i+1,2) - s(i-1,2)
  ...
  R = D1 + D2 + ...
enddo

如您所见,我可以将计算扩展到块的线程,最后将结果(通过缩减)总结为R.因此,我定义了一个内部并行循环,如下所示:

!$acc parallel loop 
do i=1,n
  !$acc parallel loop ...
  do j=1,m  
    D[j] = s(i+1,j) - s(i-1,j)
  end
  !$acc parallel loop reduction(+:R)
  do j=1,m
    R = R + D[j]  
  enddo
enddo

但是,我需要将D定义为所有线程的共享内存,但我实际上并不知道OpenACC的最佳方法是什么? (我使用过!$ acc cache但性能更差)。此外,我需要将一些未更改的数据发送到常量内存,我再也不知道如何。

是否有任何有效的方法将此想法应用于OpenACC?我非常感谢你的帮助。

非常感谢, Behzad

2 个答案:

答案 0 :(得分:0)

我认为你正在寻找的是声明D阵列是帮派私有的。如果你在C,我说你可以在i循环中声明它。由于您在Fortran中,请尝试执行以下操作:

!$acc parallel loop private(D)
do i=1,n
  !$acc loop ...
  do j=1,m  
    D[j] = s(i+1,j) - s(i-1,j)
  end
  !$acc loop reduction(+:R)
  do j=1,m
    R = R + D[j]  
  enddo
enddo

一旦它成为帮派的私人,你可能会发现cache指令更有效。

我正在查看今天早些时候类似的代码,您可能还想尝试将D的大小扩展为nxm,然后在i之间拆分j循环}循环。现在,编译器需要在两个j循环之间插入同步,而且需要将i循环剥离为向量,因此您可能会失去M / vector_length并行性。如果将其分成两个双嵌套循环,则可以将ij循环折叠在一起并获得更多并行性。这看起来像这样。

!$acc parallel loop private(D)
do i=1,n collapse(2)
  do j=1,m  
    D(j,i) = s(i+1,j) - s(i-1,j)
  end
enddo
!$acc parallel loop private(D)
do i=1,n collapse(2) reduction(+:R)
  do j=1,m
    R = R + D(j,i)  
  enddo
enddo

权衡是D需要更多存储空间,CPU上的缓存性能会受到影响。虽然看看是否值得进行权衡,但值得尝试。

答案 1 :(得分:0)

之前的序列号版本如下:

do j=1,n
  do i=1,m
    a_x = s(i+1,j,1) - s(i-1,j,1)                   
    b_x = s(i+1,j,2) - s(i-1,j,2)                   
    c_x = s(i+1,j,3) - s(i-1,j,3)                  
    a_y = s(i,j+1,1) - s(i,j-1,1)                  
    b_y = s(i,j+1,2) - s(i,j-1,2)                  
    c_y = s(i,j+1,3) - s(i,j-1,3) 
    ...
    R1 = b_x + c_y
    R2 = a_x + a_y
    R3 = c_x + b_y
  enddo
enddo   

新方法是将计算分为x和y方向,如下所示(串行版本):

do j=1,n
  do i=1,m
    do k=1,2
      do m=1,3
        D(m) = s(i+dir(k,1),j+dir(k,2),m) - s(i-dir(k,1),j-dir(k,2),m)
      enddo             
      ...
      R_1(k) = a(k+1)
      R_2(k) = a(1)
      R_3(k) = a(3)
    enddo
    do k=1,2
      R1 = R1 + R_1(k)
      R2 = R2 + R_2(k)
      R3 = R3 + R_3(k)
    enddo
  enddo
enddo   

其中dir(2,2)= {(1,0),(0,1)}确定每个方向(k)的2D指数偏移。

现在我正尝试通过OpenACC将此代码导入GPU。