Закрытое предложение цикла OpenACC и условие гонки

#fortran #gpu #openacc #pgi

#fortran #графический процессор #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
  

Ответ №1:

Похоже на проблему компилятора, когда «tmp» совместно используется рабочими вместо того, чтобы каждый рабочий получал личную копию. Это, в свою очередь, вызывает состояние гонки в вашем коде.

Я отправил отчет о проблеме в PGI (TPR # 27025) и отправил его нашим инженерам для дальнейшего расследования.

Обходной путь заключается в использовании «gang» вместо «worker» во внешнем цикле или, как вы заметили, сделать «tmp» в виде массива одного измерения.

Обновление: TPR # 27025 был исправлен в выпуске PGI 19.7.

Комментарии:

1. Где я могу следить за ходом выполнения того отчета о проблеме, который вы отправили?

2. У нас нет общедоступного средства отслеживания ошибок. Для получения статуса вы можете отправить электронное письмо в службу поддержки клиентов PGI по адресу trs@ pgroup, com.

Ответ №2:

Эти два 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
  

одновременно будет выполняться на графическом процессоре. То есть они выполняются параллельно. Чтобы гарантировать, что 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