синхронизации языке 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 ответ:
Я бы предположил, что
Еще одна вещь, которая озадачивает меня, - это последние две линии тела петли. Каждый поток создает резервную копию всей матрицы, а затем добавляет свой кусок. Не лучше ли собрать все срезы (например, с помощью предложенияcalcSslice
не является threadsafe. Убедитесь, что эта подпрограмма не обращается к глобальным переменным, отличным от только для чтения, и не использует атрибутsave
(остерегайтесь неявного сохранения, если вы инициализируете переменные во время объявления!). Вы можете использовать threadchecker, подобный тому, который предоставляет Intel, чтобы найти условия гонки в вашем коде. Если у вас нет доступа к такому программному обеспечению, я бы начал с фиктивной процедуры, а затем пополнил бы процедуру инкрементально, чтобы увидеть, где она терпит неудачу.reduction
), а затем объединить этот большой срез один раз?