系统地并行化 fortran 2008 `do concurrent`,可能使用 openmp
Posted
技术标签:
【中文标题】系统地并行化 fortran 2008 `do concurrent`,可能使用 openmp【英文标题】:Parallelizing fortran 2008 `do concurrent` systematically, possibly with openmp 【发布时间】:2012-07-18 21:12:34 【问题描述】: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
迭代可以以任何顺序进行。你可以阅读更多关于它的信息here。
据我所知,gfortran 不会自动并行化这些 do concurrent
循环,而我记得有一封关于这样做的 gfortran-diffusion-list 邮件 (here)。它只是将它们转换为经典的do
循环。
我的问题:您知道一种系统地并行化do concurrent
循环的方法吗?例如使用 systematic openmp 语法?
【问题讨论】:
如果你还在使用它 - 不要使用FORALL
和 workshare
。请参阅下面的更新答案。
【参考方案1】:
自动做到这一点并不容易。 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 允许 type-spec 允许在标题内定义循环索引,并且您需要将整个事物包围在 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
鉴于以上所有情况,我能想到的唯一系统方法是系统地检查您的源代码,搜索DO CONCURRENT
和系统地 根据 forall-header 和循环体的内容,将其替换为上述转换后的结构之一。
编辑: 目前不鼓励使用 OpenMP workshare
指令。事实证明,至少英特尔 Fortran 编译器和 GCC 在编译期间通过用 OpenMP single
指令将它们包围在 OpenMP workshare
指令内部序列化 FORALL
语句和构造,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现可移植性能,最好避免使用它。
【讨论】:
感谢您的更新。关于这种不鼓励的行为,你有什么资料可以阅读吗? 使用 GCC,您可以查看 source code。一些结构是并行的,例如数组赋值,但FORALL
不在其中。使用其他编译器,您可以查看程序集输出。
我还应该补充一点,编译器供应商实际上正在解决您试图解决的完全相同的问题:)【参考方案2】:
我不确定您的意思是“一种系统地并行化并发循环的方法”。但是,要简单地将普通的 do
循环与 OpenMP 并行化,您可以使用类似的东西:
!$omp parallel private (i)
!$omp do
do i = 1,10
array(i) = i
end do
!$omp end do
!$omp end parallel
这就是你所追求的吗?
【讨论】:
抱歉“系统地”含糊不清。例如,我可以 grep 或 awkdo concurrent
; XX; end do
代码中的任何地方,并用始终相同的 openmp 语法替换它(例如 sed 或 awk)。不应该是特定的事件(当然是循环变量)。您的回答可能会以这种方式有所帮助,但对于do concurrent
和end do
之间的各种内容,它是否总是正确的语法?
据我所知,这应该足够了,考虑到对 do concurrent
构造的限制 - 希望有更多知识的人可以在这里加入。我对您尝试做的事情的一个担忧是,当使用 do concurrent
构造时,编译器将检查您在构造中所做的事情是否为 Fortran 标准所允许,但如果您使用 sed 则不会发生这种情况/awk 等。因此,如果您犯了错误,这种简单的翻译可能不合适,并且可能导致难以追踪的意外结果。以上是关于系统地并行化 fortran 2008 `do concurrent`,可能使用 openmp的主要内容,如果未能解决你的问题,请参考以下文章
openmp+fortran程序,双重do循环外面都加并行,结果好像并行了,但是threadid都是0,请问到底并行没有?