OpenACC循环私有条款和竞争条件

时间:2019-03-25 15:17:27

标签: fortran gpu openacc pgi

我正在尝试将工人专用阵列与OpenACC配合使用,但是我一直得到错误的结果。我猜发生了某种竞争状况问题,但我找不到位置。

我正在使用PGI编译器(18.10,OpenPower)并使用:

进行编译
pgf90 -gopt -O3 -Minfo=all -Mcuda=ptxinfo -acc -ta=tesla:cc35 main.F90

这是我要实现的目标的一个最小示例:

#define lx 7000
#define ly 500

program test
  implicit none
  integer :: tmp(ly,1), a(lx,ly), b(lx,ly)
  integer :: x,y,i

  do x=1,lx
     do y=1,ly
        a(x,y) = x+y
     end do
  end do

  !$acc parallel num_gangs(1)                                                                                                                                                                                                                 
  !$acc loop worker private(tmp)                                                                                                                                                                                                              
  do x=1,lx
     !$acc loop vector                                                                                                                                                                                                                        
     do y=1,ly
        tmp(y,1) = -a(x,y)
     end do
     !$acc loop vector
     do y=1,ly
        b(x,y) = -tmp(y,1)
     end do
  end do
  !$acc end parallel                                                                                                                                                                                                                          

  print *, "check"
  do x=1,lx
     do y=1,ly
        if(b(x,y) /= x+y) print *, x, y, b(x,y), x+y
     end do
  end do
  print*, "end"
end program

我原本希望得到b == a,但事实并非如此。

请注意,我定义了tmp(ly,1),因为将tmp(ly)定义为一维数组时可以得到预期的结果。即使它与一维阵列兼容,我也不确定它是否完全遵守OpenACC标准。

我在这里想念东西吗?

编辑:最后一个循环检查a == b,并输出错误的值。预期的输出(我在禁用OpenACC的情况下得到)是:

  check
  end

启用OpenACC后,我得到的是这样的结果(运行之间的变化):

check
            1            1            5            2
            1            2            6            3
            1            3            7            4
[...]
  end

2 个答案:

答案 0 :(得分:1)

看起来像一个编译器问题,其中“ tmp”由工作程序共享,而不是每个工作程序都获得私有副本。反过来,这会在您的代码中导致竞争状态。

我已向PGI(TPR#27025)提交了问题报告,并将其发送给我们的工程师进行进一步调查。

解决方法是在外循环上使用“ gang”而不是“ worker”,或者您要注意,将“ tmp”作为一维数组。

答案 1 :(得分:0)

这两个acc loop

 !$acc loop vector                                                                                                                                                                                                                        
 do y=1,ly
    tmp(y,1) = -a(x,y)
 end do
 !$acc loop vector
 do y=1,ly
    b(x,y) = -tmp(y,1)
 end do

将同时在gpu上执行。也就是说,它们是并行执行的。为了确保tmp在第二个循环中被使用之前在第一个循环中被正确校正,它们必须位于不同的acc parallel结构上。

正确的代码如下:

  do x=1,lx
      !$acc parallel loop                                                                                                                                                                                                                     
      do y=1,ly
          tmp(y,1) = -a(x,y)
      end do
      !$acc parallel loop                                                                                                                                                                                                                     
      do y=1,ly
          b(x,y) = -tmp(y,1)
      end do
  end do