Я не могу заставить! $ Acc параллельно работать (а вот ядра acc работают)

Я пытался использовать OpenACC с простым кодом, но, думаю, я не совсем понимаю, как писать вложенные циклы OpenACC или что делает private. Процедура, которую я пытаюсь распараллелить, такова:

SUBROUTINE zcs(zc,kmin,kmax,ju2,jl2)                                                                                                                                                            
INTEGER, INTENT(IN) :: kmin,kmax,ju2,jl2                                                                                                                                                      
DOUBLE PRECISION, DIMENSION(-jl2:jl2,-jl2:jl2,-ju2:ju2,-ju2:ju2,kmin:kmax,kmin:kmax,-kmax:kmax) :: zc                                                                                         

INTEGER :: k,kp,k2,km,kp2,q,q2,mu2,ml2,p2,mup2,pp2,mlp2,ps2,pt2                                                                                                                               
DOUBLE PRECISION :: z0,z1,z2,z3,z4,z5,z6,z7                                                                                                                                                   


! Start loop over K, K' and Q                                                                                                                                                                 
!$acc kernels                                                                                                                                                                                 
do k=kmin,kmax                                                                                                                                                                                
   do kp=kmin,kmax                                                                                                                                                                            
      k2=2*k                                                                                                                                                                                  
      km = MIN(k,kp)                                                                                                                                                                          
      kp2=2*kp                                                                                                                                                                                
      z0=3.d0*dble(ju2+1)*dsqrt(dble(k2+1))*dsqrt(dble(kp2+1))                                                                                                                                
      do q=-km,km                                                                                                                                                                             
         q2=2*q                                                                                                                                                                               

         ! Calculate quantity C and its sum over magnetic quantum numbers                                                                                                                     
         do mu2=-ju2,ju2,2                                                                                                                                                                    
            do ml2=-jl2,jl2,2                                                                                                                                                                 
               p2=mu2-ml2                                                                                                                                                                     
               if(abs(p2).gt.2) cycle                                                                                                                                                         
               z1=w3js(ju2,jl2,2,mu2,-ml2,-p2)                                                                                                                                                
               do mup2=-ju2,ju2,2                                                                                                                                                             
                  if(mu2-mup2.ne.q2) cycle                                                                                                                                                    
                  pp2=mup2-ml2                                                                                                                                                                
                  if(abs(pp2).gt.2) cycle                                                                                                                                                     
                  z2=w3js(ju2,jl2,2,mup2,-ml2,-pp2)                                                                                                                                           
                  do mlp2=-jl2,jl2,2                                                                                                                                                          
                     ps2=mu2-mlp2                                                                                                                                                             
                     if(abs(ps2).gt.2) cycle                                                                                                                                                  
                     pt2=mup2-mlp2                                                                                                                                                            
                     if(abs(pt2).gt.2) cycle                                                                                                                                                  
                     z3=w3js(ju2,jl2,2,mu2,-mlp2,-ps2)                                                                                                                                        
                     z4=w3js(ju2,jl2,2,mup2,-mlp2,-pt2)                                                                                                                                       
                     z5=w3js(2,2,k2,-p2,pp2,q2)                                                                                                                                               
                     z6=w3js(2,2,kp2,-ps2,pt2,q2)                                                                                                                                             
                     z7=1.d0                                                                                                                                                                  
                     if(mod(2*ju2-ml2-mlp2,4).ne.0) z7=-1.d0                                                                                                                                  
                     zc(ml2,mlp2,mu2,mup2,k,kp,q)=z0*z1*z2*z3*z4*z5*z6*z7                                                                                                                     
                  enddo                                                                                                                                                                       
               enddo                                                                                                                                                                          
            enddo                                                                                                                                                                             
         enddo                                                                                                                                                                                

      end do                                                                                                                                                                                  
   end do                                                                                                                                                                                     
end do                                                                                                                                                                                        

!$acc end kernels                                                                                                                                                                             
END SUBROUTINE zcs  

Как бы то ни было, код работает нормально, и если я сравниваю матрицу zc после вызова этой подпрограммы, и версия, отличная от OpenACC, и версия OpenACC дадут одинаковый ответ. Но если я попытаюсь сделать это с помощью параллельной директивы, похоже, возникнет состояние гонки, и я не могу понять, где оно находится. Соответствующие изменения:

!$acc parallel                                                                                                                                                                                
!$acc loop private(k,kp,k2,km,kp2,z0,q,q2)                                                                                                                                                    
do k=kmin,kmax                                                                                                                                                                                
   do kp=kmin,kmax                                                                                                                                                                            
      k2=2*k                                                                                                                                                                                  
      km = MIN(k,kp)                                                                                                                                                                          
      kp2=2*kp                                                                                                                                                                                
      z0=3.d0*dble(ju2+1)*dsqrt(dble(k2+1))*dsqrt(dble(kp2+1))                                                                                                                                
      do q=-km,km                                                                                                                                                                             
         q2=2*q                                                                                                                                                                               

         ! Calculate quantity C and its sum over magnetic quantum numbers                                                                                                                     
         !$acc loop private(mu2,ml2,p2,z1,mup2,pp2,z2,mlp2,ps2,pt2,z3,z4,z5,z6,z7)                                                                                                            
         do mu2=-ju2,ju2,2                                                                                            


 [...]

!$acc end parallel  

Насколько я понимаю, я объявил соответствующие переменные как частные, но полагаю, я не совсем понимаю, как вкладывать несколько циклов и / или что на самом деле делает частный. Есть предложения, которые помогут мне правильно понять, что происходит?

Большое спасибо, AdV


person Angel de Vicente    schedule 16.04.2018    source источник


Ответы (1)


Основная проблема здесь в том, что вы передаете переменные границ цикла «ju2» и «jl2» со ссылкой на процедуру «w3js». Это означает, что счетчик отключения цикла может измениться во время выполнения цикла и, таким образом, предотвратить распараллеливание. Вы можете попробовать сделать эти переменные закрытыми, но проще всего добавить атрибут «VALUE» в аргументы w3js, чтобы они передавались по значению.

Обратите внимание, что это работает в случае «ядер», поскольку компилятор распараллеливает только внешние циклы. В «параллельном» случае вы пытаетесь распараллелить эти «несчетные» внутренние циклы.

person Mat Colgrove    schedule 16.04.2018