Некоторые вопросы по программе acc

Один код MPI, я пытаюсь распараллелить его простой цикл с помощью openacc, и результат не ожидается. Здесь у цикла есть вызов, и я добавляю в подпрограмму «acc regular seq». Если я вручную сделаю этот вызов встроенным и удалю подпрограмму, результат будет правильным. Правильно ли я использую стандартную директиву OpenACC? или другое неправильное?

  • Среда выполнения

Версия MPI: openmpi4.0.5
HPC SDK 20.11
Версия CUDA: 10.2

!The main program
program test
  use simple
  use mpi
  implicit none
  integer :: i,id,size,ierr,k,n1
  call MPI_INIT(ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD,id,ierr)
  call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierr)

  allocate(type1(m))
  do i=1,m
    allocate(type1(i)%member(n))
    type1(i)%member=-1
    type1(i)%member(i)=i
  enddo
  
  !$acc update device(m,n)
  do k=1,m
    n1=0
    allocate(dev_mol(k:2*k))
    dev_mol=type1(k)%member(k:2*k)
    !$acc update device(dev_mol(k:2*k))
    !$acc parallel copy(n1) firstprivate(k)
    !$acc loop independent
    do i=k,2*k
      call test1(k,n1,i)
    enddo
    !$acc end parallel
    !$acc update self(dev_mol(k:2*k))
    type1(k)%member(k:2*k)=dev_mol
    write(*,"('k=',I3,' n1=',I2)") k,n1
    deallocate(dev_mol)
  enddo
  
  do i=1,m
    write(*,"('i=',I2,' member=',I3)") i,type1(i)%member(i)
    deallocate(type1(i)%member)
  enddo
  deallocate(type1)
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
  call MPI_Finalize(ierr)
end


!Here is the module
module simple
  implicit none
  integer :: m=5,n=2**15
  integer,parameter :: p1=15
  integer,allocatable :: dev_mol(:)
  type type_related
    integer,allocatable :: member(:)
  end type
  type(type_related),allocatable :: type1(:)
  
  !$acc declare create(m,n,dev_mol)
  !$acc declare copyin(p1)
  contains
    subroutine test1(k,n1,i)
      implicit none
      integer :: k,n1,i
      !$acc routine seq
      if(dev_mol(i)>0) then
        !write(*,*) 'gpu',k,n1,i
        n1=dev_mol(i)
        dev_mol(i)=p1
      else
        if(i==k)write(*,*) 'err',i,dev_mol(i)
      endif
    end
end
  • MPI

команда компиляции : mpif90 test.f90 -o test
выполнить команду : mpirun -n 1 ./test
результат следующим образом:

k=  1 n1= 1
k=  2 n1= 2
k=  3 n1= 3
k=  4 n1= 4
k=  5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15
  • MPI + OpenACC

команда компиляции : mpif90 test.f90 -o test -ta = tesla: cuda10.2 -Minfo = Accel
команда запуска : mpirun -n 1 ./test
результат ошибки следующий:

k=  1 n1= 0
k=  2 n1= 0
k=  3 n1= 0
k=  4 n1= 0
k=  5 n1= 0
i= 1 member= 1
i= 2 member= 2
i= 3 member= 3
i= 4 member= 4
i= 5 member= 5

person Xin Ding    schedule 06.04.2021    source источник
comment
Вам вообще нужен MPI для доказательства проблемы?   -  person Gilles Gouaillardet    schedule 06.04.2021
comment
Добро пожаловать, пожалуйста, пройдите тур. Пожалуйста, используйте тег fortran для всех вопросов по Fortran, Fortran 90 - это всего лишь одна очень старая версия стандарта. Я также предлагаю попробовать воспроизвести проблему в еще более простой программе без MPI. Какой компилятор вы используете?   -  person Vladimir F    schedule 06.04.2021
comment
@Vladimir F Спасибо за ответ. Я использую компилятор NVFORTRAN 20.11. Только что я удалил весь код MPI и воспроизвел проблему без MPI. Нужно ли мне загружать новый код?   -  person Xin Ding    schedule 06.04.2021
comment
Да, пожалуйста, обновите код. Мы хотим смотреть именно на то, на что смотрите   -  person Ian Bush    schedule 06.04.2021


Ответы (1)


Проблема в том, что i передается по ссылке (по умолчанию с Фортраном). Самое простое решение - передать его по значению:

  contains
    subroutine test1(k,n1,i)
      implicit none
      integer, value :: i
      integer :: n1, k

Теперь есть небольшая ошибка компилятора, поскольку i - это индексная переменная цикла, поэтому переменную следует неявно приватизировать. Однако, поскольку он передается по ссылке, это приводит к тому, что он становится общим. Мы исправим это в будущей версии компилятора. Хотя по возможности рекомендуется передавать скаляры по значению.

Пример запуска с обновлением:

% mpif90 test2.f90 -acc -Minfo=accel -V21.2 ; mpirun -np 1 a.out
test1:
     16, Generating acc routine seq
         Generating Tesla code
test:
     48, Generating update device(m,n)
     53, Generating update device(dev_mol(k:k*2))
     54, Generating copy(n1) [if not already present]
         Generating Tesla code
         56, !$acc loop gang, vector(128) ! blockidx%x threadidx%x
     60, Generating update self(dev_mol(k:k*2))
k=  1 n1= 1
k=  2 n1= 2
k=  3 n1= 3
k=  4 n1= 4
k=  5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15
person Mat Colgrove    schedule 06.04.2021
comment
Отлично. Большое спасибо. - person Xin Ding; 07.04.2021
comment
К вашему сведению, в SDK NVHPC 21.3 исправлена ​​проблема неявной приватизации переменной индекса цикла, передаваемой по ссылке, поэтому исходная версия будет работать должным образом. Однако я по-прежнему рекомендую передавать скаляры по значению, когда это возможно. - person Mat Colgrove; 09.04.2021