OpenACC加速使用OpenMP

时间:2019-05-27 05:47:04

标签: fortran openmp gpgpu openacc

我有一个代码部分,可以将其并行化到我想要的位置,并且可以与OpenMP正确运行,但是不能与OpenACC并行运行。它是求解器的一部分,如果使用OpenACC则根本不会收敛。

有没有一种方法可以编写它,使其行为像OpenMP代码一样正确?我也尝试了没有“ collapse(2)”的问题,同样的问题,它不会收敛。 由于使用了graf多种颜色,提取了并行度,因此可以安全地并行化循环,如OpenMP代码所示。
如果我使用"!$acc parallel loop seq",它将只能在OpenACC上正常运行。否则,它将在经过不同的迭代次数后失败,因此似乎必须消除竞争条件。

OPENMP:

    !$omp parallel default(none) &
    !$omp&shared(NColor,indexL,itemL,indexU,itemU,AL,AU,D,ALU,perm,&
    !$omp&       NContact,indexCL,itemCL,indexCU,itemCU,CAL,CAU,&
    !$omp&       ZP,icToBlockIndex,blockIndexToColorIndex) &
!$omp&private(SW1,SW2,SW3,X1,X2,X3,ic,i,iold,isL,ieL,isU,ieU,j,k,blockIndex)

            do ic=1,NColor

              !$omp do schedule (static, 1)
              do blockIndex = icToBlockIndex(ic-1)+1, icToBlockIndex(ic)
                do i = blockIndexToColorIndex(blockIndex-1)+1, &
                    blockIndexToColorIndex(blockIndex)
                  ! do i = startPos(threadNum, ic), endPos(threadNum, ic)
                  iold = perm(i)
                  SW1= ZP(3*iold-2)
                  SW2= ZP(3*iold-1)
                  SW3= ZP(3*iold  )
                  isL= indexL(i-1)+1
                  ieL= indexL(i)
                  do j= isL, ieL
                    !k= perm(itemL(j))
                    k= itemL(j)
                    X1= ZP(3*k-2)
                    X2= ZP(3*k-1)
                    X3= ZP(3*k  )
                    SW1= SW1 - AL(9*j-8)*X1 - AL(9*j-7)*X2 - AL(9*j-6)*X3
                    SW2= SW2 - AL(9*j-5)*X1 - AL(9*j-4)*X2 - AL(9*j-3)*X3
                    SW3= SW3 - AL(9*j-2)*X1 - AL(9*j-1)*X2 - AL(9*j  )*X3
                  enddo ! j

                  if (NContact.ne.0) then
                    isL= indexCL(i-1)+1
                    ieL= indexCL(i)
                    do j= isL, ieL
                      !k= perm(itemCL(j))
                      k= itemCL(j)
                      X1= ZP(3*k-2)
                      X2= ZP(3*k-1)
                      X3= ZP(3*k  )
                      SW1= SW1 - CAL(9*j-8)*X1 - CAL(9*j-7)*X2 - CAL(9*j-6)*X3
                      SW2= SW2 - CAL(9*j-5)*X1 - CAL(9*j-4)*X2 - CAL(9*j-3)*X3
                      SW3= SW3 - CAL(9*j-2)*X1 - CAL(9*j-1)*X2 - CAL(9*j  )*X3
                    enddo ! j
                  endif

                  X1= SW1
                  X2= SW2
                  X3= SW3
                  X2= X2 - ALU(9*i-5)*X1
                  X3= X3 - ALU(9*i-2)*X1 - ALU(9*i-1)*X2
                  X3= ALU(9*i  )*  X3
                  X2= ALU(9*i-4)*( X2 - ALU(9*i-3)*X3 )
                  X1= ALU(9*i-8)*( X1 - ALU(9*i-6)*X3 - ALU(9*i-7)*X2)
                  ZP(3*iold-2)= X1
                  ZP(3*iold-1)= X2
                  ZP(3*iold  )= X3
                enddo ! i
              enddo ! blockIndex
            !$omp end do
            enddo ! ic
           !$omp end parallel

OPENACC:

do ic=1,NColor

 !$acc parallel loop collapse(2)
  do blockIndex = icToBlockIndex(ic-1)+1, icToBlockIndex(ic)
    do i = blockIndexToColorIndex(blockIndex-1)+1, &
        blockIndexToColorIndex(blockIndex)
      ! do i = startPos(threadNum, ic), endPos(threadNum, ic)
      iold = perm(i)
      SW1= ZP(3*iold-2)
      SW2= ZP(3*iold-1)
      SW3= ZP(3*iold  )
      isL= indexL(i-1)+1
      ieL= indexL(i)

      !$acc loop vector
      do j= isL, ieL
        !k= perm(itemL(j))
        k= itemL(j)
        X1= ZP(3*k-2)
        X2= ZP(3*k-1)
        X3= ZP(3*k  )
        SW1= SW1 - AL(9*j-8)*X1 - AL(9*j-7)*X2 - AL(9*j-6)*X3
        SW2= SW2 - AL(9*j-5)*X1 - AL(9*j-4)*X2 - AL(9*j-3)*X3
        SW3= SW3 - AL(9*j-2)*X1 - AL(9*j-1)*X2 - AL(9*j  )*X3
      enddo ! j

      if (NContact.ne.0) then
        isL= indexCL(i-1)+1
        ieL= indexCL(i)

       !$acc loop vector
        do j= isL, ieL
          !k= perm(itemCL(j))
          k= itemCL(j)
          X1= ZP(3*k-2)
          X2= ZP(3*k-1)
          X3= ZP(3*k  )
          SW1= SW1 - CAL(9*j-8)*X1 - CAL(9*j-7)*X2 - CAL(9*j-6)*X3
          SW2= SW2 - CAL(9*j-5)*X1 - CAL(9*j-4)*X2 - CAL(9*j-3)*X3
          SW3= SW3 - CAL(9*j-2)*X1 - CAL(9*j-1)*X2 - CAL(9*j  )*X3
        enddo ! j
      endif

      X1= SW1
      X2= SW2
      X3= SW3
      X2= X2 - ALU(9*i-5)*X1
      X3= X3 - ALU(9*i-2)*X1 - ALU(9*i-1)*X2
      X3= ALU(9*i  )*  X3
      X2= ALU(9*i-4)*( X2 - ALU(9*i-3)*X3 )
      X1= ALU(9*i-8)*( X1 - ALU(9*i-6)*X3 - ALU(9*i-7)*X2)
      ZP(3*iold-2)= X1
      ZP(3*iold-1)= X2
      ZP(3*iold  )= X3
    enddo ! i
  enddo ! blockIndex

 !$acc end parallel loop
enddo ! ic

预期结果与OpenMP加速代码具有相同的行为,即它确实会收敛并且不会在迭代过程中过早停止。

1 个答案:

答案 0 :(得分:0)

请注意,这与我在PGI用户论坛上对您的问题的回答相同:https://www.pgroup.com/userforum/viewtopic.php?f=12&t=6572

由于该示例不完整,因此很难确切说明为什么会发生这种情况,但是我会尽力提供所提供的信息。

1)编译器反馈消息告诉您什么?请在编译中添加标志“ -Minfo = accel”以启用消息。

2)鉴于“ i”循环的边界是使用“ blockIndex”循环的索引从查找数组中获取的,因此两个外部循环均无法合拢。与崩溃子句关联的所有循环的行程计数必须在所有循环中都是可计算的且不变的。

3)ZP确实具有潜在的竞争条件,具体取决于“ perm”数组中使用的“ iold”值。如果可以保证不存在重叠,那应该没问题,但是在不知道“ perm”值的情况下,我无法告诉。请注意,如果存在重叠,则OpenMP中会发生相同的问题,但是考虑到CPU上的OpenMP使用的线程比GPU少得多,因此可能不会遇到竞争条件。

4)我在代码中没有看到任何数据管理。假设您不使用更高版本的数据指令,则编译器将需要隐式添加它们。但是鉴于大多数数组都使用计算索引,所以不知道要复制多少数组。在这种情况下,反馈消息应向您发出警告。同样出于性能原因,您将希望在“ ic”循环之前添加一个数据区域来管理阵列的设备副本,这样就不会在每次遇到并行循环时都复制阵列。