自动做到这一点并不容易。该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中相应部分的存在)
请注意,这不如将一个大循环与<iters 1>*<iters 2>*...
独立迭代并行化那样有效,而这DO CONCURRENT
是预期的。另请注意,forall-header允许一种类型规范,该规范允许在标头内定义循环索引,并且您需要将整个事物包围在BLOCK ... END BLOCK
构造中以保留语义。您还需要检查scalar-mask-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
鉴于以上所有情况,我能想到的唯一系统方法是系统地检查您的源代码,根据forall-header和循环体的内容,搜索DO CONCURRENT
并系统地用上述转换后的结构之一替换它。
编辑:workshare
目前不鼓励使用 OpenMP指令。事实证明,至少英特尔 Fortran 编译器和 GCC通过在编译期间用 OpenMP 指令包围它们来序列化 OpenMP 指令中的FORALL
语句和构造,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现可移植性能,最好避免使用它。workshare
single