Распараллеливание fortran 2008 "do concurrent" систематически, возможно, с openmp
Фортран 2008 do concurrent
construct-это цикл do, который сообщает компилятору, что никакие итерации не влияют на другие. Таким образом, его можно безопасно распараллелить.
действующий пример:
program main
implicit none
integer :: i
integer, dimension(10) :: array
do concurrent( i= 1: 10)
array(i) = i
end do
end program main
где итерации могут быть выполнены в любом порядке. Вы можете прочитать больше об этом здесь.
насколько мне известно, gfortran не автоматически распараллеливает эти do concurrent
петли, в то время как я помню письмо gfortran-diffusion-list об этом (здесь). Это справедливо превратить их в классические do
петли.
у меня вопрос: вы знаете, как систематически распараллелить do concurrent
петли? Например с систематически синтаксис openmp?
2 ответов
это не так просто сделать это автоматически. The DO CONCURRENT
конструкция имеет forall-header что означает, что он может принимать несколько циклов, определение переменных индекса и маски. В принципе, вам нужно заменить:
DO CONCURRENT([<type-spec> :: ]<forall-triplet-spec 1>, <forall-triplet-spec 2>, ...[, <scalar-mask-expression>])
<block>
END DO
С:
[BLOCK
<type-spec> :: <indexes>]
!$omp parallel do
DO <forall-triplet-spec 1>
DO <forall-triplet-spec 2>
...
[IF (<scalar-mask-expression>) THEN]
<block>
[END IF]
...
END DO
END DO
!$omp end parallel do
[END BLOCK]
(вещи в квадратных скобках являются необязательными, исходя из наличия соответствующих частей в forall-header)
обратите внимание, что это будет не так эффективно, как parallelising один большой цикл с <iters 1>*<iters 2>*...
независимых итераций, что DO CONCURRENT
как ожидается, сделать. Обратите внимание также, что forall-header разрешает type-spec это позволяет определить индексы цикла внутри заголовка, и вам нужно будет окружить все это в BLOCK ... END BLOCK
строительство, чтобы сохранить семантику. Вам также нужно будет проверить, если скалярная маска-expr существует в конце forall-header и если это так, вы также должны положите это IF ... END IF
внутри внутреннего цикла.
если у вас есть только назначения массива внутри тела DO CONCURRENT
вы могли бы также преобразовать его в FORALL
и с помощью workshare
директива OpenMP. Это было бы намного проще, чем вышесказанное.
DO CONCURRENT <forall-header>
<block>
END DO
станет:
!$omp parallel workshare
FORALL <forall-header>
<block>
END FORALL
!$omp end parallel workshare
учитывая все вышесказанное, единственное систематически способ, о котором я могу думать, это систематически пройти через исходный код, поиск для DO CONCURRENT
и систематически замена его одной из вышеупомянутых преобразованных конструкций на основе содержимого forall-header и тело цикла.
Edit: использование OpenMP workshare
директива в настоящее время не рекомендуется. Оказывается, что по крайней мере компилятор Intel Fortran и сериализация GCC FORALL
операторы и конструкции внутри OpenMP workshare
директивы, окружая их OpenMP single
директива во время компиляция, которая не приносит никакого ускорения. Другие компиляторы могут реализовать его по-другому, но лучше избегать его использования, если требуется портативная производительность.
Я не уверен, что вы имеете в виду "способ систематического распараллеливания параллельных циклов". Однако, чтобы просто распараллелить обычный do
цикл с OpenMP вы можете просто использовать что-то вроде:
!$omp parallel private (i)
!$omp do
do i = 1,10
array(i) = i
end do
!$omp end do
!$omp end parallel
это то, что вы после?