系统地并行化 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 语法?

【问题讨论】:

如果你还在使用它 - 不要使用 FORALLworkshare。请参阅下面的更新答案。 【参考方案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 中相应部分的存在)

请注意,这不如使用&lt;iters 1&gt;*&lt;iters 2&gt;*... 独立迭代并行一个大循环有效,而这是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

这就是你所追求的吗?

【讨论】:

抱歉“系统地”含糊不清。例如,我可以 grepawk do concurrent; XX; end do 代码中的任何地方,并用始终相同的 openmp 语法替换它(例如 sedawk)。不应该是特定的事件(当然是循环变量)。您的回答可能会以这种方式有所帮助,但对于do concurrentend do 之间的各种内容,它是否总是正确的语法? 据我所知,这应该足够了,考虑到对 do concurrent 构造的限制 - 希望有更多知识的人可以在这里加入。我对您尝试做的事情的一个担忧是,当使用 do concurrent 构造时,编译器将检查您在构造中所做的事情是否为 Fortran 标准所允许,但如果您使用 sed 则不会发生这种情况/awk 等。因此,如果您犯了错误,这种简单的翻译可能不合适,并且可能导致难以追踪的意外结果。

以上是关于系统地并行化 fortran 2008 `do concurrent`,可能使用 openmp的主要内容,如果未能解决你的问题,请参考以下文章

无法并行化OpenACC循环

openmp+fortran程序,双重do循环外面都加并行,结果好像并行了,但是threadid都是0,请问到底并行没有?

混合组装和 Fortran 以及并行化 (OpenMP)

如何在由 MPI 并行化的 fortran 中调用子例程?

并行 fortran 程序将在某个时间休眠

请看看则个fortran结合openmp并行程序,为啥老出错?