синхронизации языке Fortran OpenMP и


Я пытаюсь распараллелить цикл fortran через OpenMP. Цикл по существу состоит всего из двух команд:

do i=1,LSample
  calcSslice(Vpot(:,:,i), Sslice)
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
end do

Подпрограмма calcSslice считывает Vpot (:,:, i), выполняет некоторые вычисления и сохраняет результаты в матрице Sslice. combine_rp_matrices использует rpold и Sslice для обновления rp. rp действует как бегущая переменная и является желаемым результатом работы программы. Порядок, в котором Sslice-матрицы из разных итераций объединяются с rp, не имеет значения. Моя первая попытка при распараллеливании этот цикл выглядел так:

!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
  calcSslice(Vpot(:,:,i), Sslice)
!$OMP CRITICAL
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO
Это компилируется и выполняется, но приводит к неверным результатам. Используя следующий код, я получаю правильные результаты, но гораздо медленнее выполнения (хотя все еще быстрее, чем сериализованный код):
!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
!$OMP CRITICAL(Crit2)
  calcSslice(Vpot(:,:,i), Sslice)
!$OMP END CRITICAL(Crit2)
!$OMP CRITICAL
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO

Таким образом, очевидно, существует некоторая проблема синхронизации с calcSslice. Однако я не совсем понимаю, где это могло произойти. Vpot только считывается и не записывается в calcSslice, а Sslice-это переменная threadprivate. Любые используемые глобальные переменные в calcSslice также только читаются из. Переменные rpold и rp объявляются в области действия подпрограммы, частью которой является цикл DO, и поэтому не могут быть доступны calcSslice. Переменные, объявленные в calcSslice использовать следующие атрибуты: умысел(в), намерения(выйти), цель, указатель.

Где это может быть неправильно?

EDIT: проблема решена, причиной стала инициализация переменных в calcSslice при объявлении, что подразумевает атрибут save.

1 3

1 ответ:

Я бы предположил, что calcSslice не является threadsafe. Убедитесь, что эта подпрограмма не обращается к глобальным переменным, отличным от только для чтения, и не использует атрибут save (остерегайтесь неявного сохранения, если вы инициализируете переменные во время объявления!). Вы можете использовать threadchecker, подобный тому, который предоставляет Intel, чтобы найти условия гонки в вашем коде. Если у вас нет доступа к такому программному обеспечению, я бы начал с фиктивной процедуры, а затем пополнил бы процедуру инкрементально, чтобы увидеть, где она терпит неудачу.

Еще одна вещь, которая озадачивает меня, - это последние две линии тела петли. Каждый поток создает резервную копию всей матрицы, а затем добавляет свой кусок. Не лучше ли собрать все срезы (например, с помощью предложения reduction), а затем объединить этот большой срез один раз?