Распараллеливание 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

это то, что вы после?