系统地并行化fortran 2008`并发`,可能与openmp

max*_*max 8 parallel-processing fortran openmp

fortran 2008 do concurrent构造是一个do循环,它告诉编译器没有迭代会影响任何其他迭代.因此可以安全地并行化.

一个有效的例子:

program main
  implicit none
  integer :: i
  integer, dimension(10) :: array
  do concurrent( i= 1: 10)
    array(i) = i
  end do
end program main
Run Code Online (Sandbox Code Playgroud)

迭代可以按任何顺序完成.你可以在这里阅读更多相关信息.

据我所知,gfortran不会自动并行化这些do concurrent循环,而我记得有关gfortran扩散列表的邮件(这里).它只是将它们转换为经典do循环.

我的问题:你知道一种系统地并行化do concurrent循环的方法吗?例如,使用系统的 openmp语法?

Hri*_*iev 12

自动完成并不容易.该DO CONCURRENT构造有一个forall-header,这意味着它可以接受多个循环,索引变量定义和掩码.基本上,你需要更换:

DO CONCURRENT([<type-spec> :: ]<forall-triplet-spec 1>, <forall-triplet-spec 2>, ...[, <scalar-mask-expression>])
  <block>
END DO
Run Code Online (Sandbox Code Playgroud)

有:

[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]
Run Code Online (Sandbox Code Playgroud)

(方括号中的东西是可选的,基于forall-header中相应部分的存在)

请注意,这不如使用<iters 1>*<iters 2>*...独立迭代并行化一个大循环那样有效,这DO CONCURRENT是预期的.另请注意,forall-header允许使用类型规范,允许在头文件中定义循环索引,并且您需要在BLOCK ... END BLOCK构造中包围整个内容以保留语义.您还需要检查forall-header -expr是否存在于forall-header的末尾,如果存在,您还应该将其IF ... END IF放在最里面的循环中.

如果您只在主体内部进行数组赋值,那么DO CONCURRENT您也可以将其转换为FORALL并使用workshareOpenMP指令.它会比上面容易得多.

DO CONCURRENT <forall-header>
  <block>
END DO
Run Code Online (Sandbox Code Playgroud)

会成为:

!$omp parallel workshare
FORALL <forall-header>
  <block>
END FORALL
!$omp end parallel workshare
Run Code Online (Sandbox Code Playgroud)

鉴于以上所有,我能想到的唯一系统方法是系统地浏览您的源代码,根据forall-header和循环体的内容,使用上述转换结构中的一个来搜索DO CONCURRENT系统地替换它.

编辑:workshare目前不鼓励使用OpenMP 指令.事实证明,至少英特尔Fortran编译器和GCC序列化FORALL语句和OpenMP workshare指令内部的构造通过single在编译期间用OpenMP 指令包围它们而不会带来任何加速.其他编译器可能会以不同的方式实现它,但如果要实现便携式性能,最好避免使用它.