Я пытаюсь распараллелить петлю fortran через OpenMP. Цикл, по существу состоит только из двух команд:fortran openmp synchronization
do i=1,LSample
calcSslice(Vpot(:,:,i), Sslice)
rpold = rp
combine_rp_matrices (rpold, Sslice, rp)
end do
calcSslice подпрограмма считывает Vpot (:,:, я), выполняет некоторые вычисления и сохраняет результаты в матрице Sslice. comb_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, используют следующие атрибуты: aim (in), target (out), target, pointer.
Где это происходит не так?
EDIT: проблема решена, причиной была инициализация переменных в calcSslice
во время объявления, что подразумевает атрибут save
.
Благодарим вас за ответ. Есть некоторые указатели, которые инициализируются как null() во время объявления. Я не знал, что это означает атрибут save. Я изменю это и посмотрю, поможет ли это. –
'Combine_rp_matrices' использует' Sslice' для обновления 'rp'. Мне пришлось бы собирать 'Sslice'-переменные, которые в 4 раза больше, чем' rp' матрицы. Матрицы очень большие и не подходят для стека, поэтому я фактически использовал массив переменных '' NThreads'Sslice' вместо того, чтобы объявить его закрытым. Для небольших матриц проблема, которую я описал, сохраняется даже при использовании частного 'Sslice', поэтому я не упоминал об этом в своем вопросе.' NThreads' намного меньше, чем 'LSample', массив' LSample' 'Sslice 's будет использовать слишком много памяти. –