要自动完成这个并不容易。 DO CONCURRENT
结构有一个 forall-header ,这意味着它可以接受多个循环、索引变量定义和掩码。基本上,您需要替换:
DO CONCURRENT([<type-spec> :: ]<forall-triplet-spec 1>, <forall-triplet-spec 2>, ...[, <scalar-mask-expression>])
<block>
END DO
with:
[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]
请注意,这不如使用 <iters 1>*<iters 2>*...
进行并行化一大循环有效,而这也是预期 DO CONCURRENT
要做的事情。 此外,请注意,forall-header 允许 type-spec,它允许您在标题中定义循环索引,并且您需要将整个内容包围在 BLOCK ... END BLOCK
结构中以保留语义。 您还需要检查 forall-header 的末尾是否存在 scalar-mask-expr,如果有,则还应在最内部的循环中放置该 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和循环体的内容系统地将其替换为上述转换结构之一。
编辑:目前不建议使用OpenMP workshare
指令。事实证明至少Intel Fortran编译器和GCC会在编译过程中通过用OpenMP single
指令包围FORALL
语句和OpenMP workshare
指令内的构造来进行串行化处理,这并不能提高速度。其他编译器可能会以不同的方式实现它,但如果需要达到可移植的性能,则最好避免使用它。
workshare
中使用FORALL
。请参见下面更新的答案。 - Hristo Iliev