2015-11-17 33 views
0

這裏是矩陣向量乘法的Fortran子程序。這可能是老式的和低效的多種方式,但現在我只是想獲得它OpenACC的指令來工作,我試圖找出減少是如何工作的:OpenACC中的減少

subroutine matrmult(matrix,invec,outvec,n) 

integer:: n 
real*8, intent(in):: matrix(n,n), invec(n) 
real*8, intent(out) :: outvec(n) 
real*8 :: tmpmat(n,n) 
real*8 :: tmpscl 

integer :: i,j,k 

!$acc declare create(matrix, invec, outvec, tmpmat) 

outvec = 0.d0 

!$acc update device(matrix, invec, tmpmat, outvec) 

!$acc parallel 

!$acc loop gang 
do j=1,n 
!$acc loop vector 
    do i=1,n 
    tmpmat(i,j) = matrix(i,j)*invec(j) 
    enddo 
enddo 

!$acc loop vector reduction(+:tmpsclr) 
do j=1,n 
    tmpsclr = 0.d0 
    do i=1,n 
    tmpsclr = tmpsclr+tmpmat(j,i) 
    enddo 
    outvec(j) = tmpsclr 
enddo 

!$acc end parallel 

!$acc update host(outvec) 

end subroutine 

這代碼實際上給出正確的結果但是,當我試圖在最後循環幫會/矢量組合,就像這樣:

!$acc loop gang reduction(+:tmpsclr) 
do j=1,n 
    tmpsclr = 0.d0 
!$acc loop vector 
    do i=1,n 
    tmpsclr = tmpsclr+tmpmat(j,i) 
    enddo 
    outvec(j) = tmpsclr 
enddo 

結果回來都錯了。對於outvec的大多數(但不是全部)元素,總看起來不完整。無論我在哪裏放置reduction條款,無論是在幫派還是向量中,都是如此。改變位置會改變結果,但從不會給出正確的結果。

我在一個簡單的測試中得到的結果如下所示。 matrix是10x10和全1,而invec是1,2,3,... 10。所以outvec的元素應該只是invec,55中元素的總和。如果我運行代碼的gang/vector版本,outvec的每個元素都是1,而不是55.如果我用向量進行縮減,好吧,然後我得到正確的答案,55.並且這繼續工作,直到我得到90個元素。當我達到91時,outvec的每個元素應該等於4186.但是隻有最後一個元素是,而其餘所有元素都等於4095(1到90之和)。隨着元素數量越來越大,值的變化以及與正確答案的差異越來越大。

我顯然不明白減法是如何工作的。誰能解釋一下?

+0

@Vladimir˚F請參閱我的編輯。謝謝。 –

回答

1

還原子句需要在發生還原的循環上,即向量循環。我還建議在這裏使用「kernels」指令,因爲「parallel」將爲兩個循環創建一個內核啓動,而「kernels」將創建兩個內核,每個循環一個。

例如:

subroutine foo(n,matrix,invec,outvec) 
integer n 
real*8, intent(in) :: matrix(n,n) 
real*8, intent(in) :: invec(n) 
real*8, intent(out) :: outvec(n) 
real*8 :: tmpmat(n,n) 
real*8 :: tmpscl 

integer :: i,j,k 

!$acc declare create(matrix, invec, outvec, tmpmat) 

outvec = 0.d0 

!$acc update device(matrix, invec, tmpmat, outvec) 

!$acc kernels 

!$acc loop gang 
do j=1,n 
!$acc loop vector 
    do i=1,n 
    tmpmat(i,j) = matrix(i,j)*invec(j) 
    enddo 
enddo 

!$acc loop gang 
do j=1,n 
    tmpsclr = 0.d0 
!$acc loop vector reduction(+:tmpsclr) 
    do i=1,n 
    tmpsclr = tmpsclr+tmpmat(j,i) 
    enddo 
    outvec(j) = tmpsclr 
enddo 

!$acc end kernels 

!$acc update host(outvec) 

end subroutine foo 
% pgf90 -c -acc -Minfo=accel test2.f90 
foo: 
    11, Generating create(matrix(:,:),invec(:),outvec(:)) 
    15, Generating update device(outvec(:),tmpmat(:,:),invec(:),matrix(:,:)) 
    20, Loop is parallelizable 
    22, Loop is parallelizable 
     Accelerator kernel generated 
     Generating Tesla code 
     20, !$acc loop gang, vector(4) ! blockidx%y threadidx%y 
     22, !$acc loop gang, vector(32) ! blockidx%x threadidx%x 
    28, Loop is parallelizable 
     Accelerator kernel generated 
     Generating Tesla code 
     28, !$acc loop gang ! blockidx%x 
     31, !$acc loop vector(128) ! threadidx%x 
      Sum reduction generated for tmpsclr 
    31, Loop is parallelizable 
    39, Generating update host(outvec(:)) 

希望這有助於 墊