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

时间:2012-07-18 21:12:35

标签: 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

可以按任何顺序完成迭代。您可以阅读更多相关信息here

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

我的问题:您是否知道系统地并行化do concurrent循环的方法?例如,使用系统 openmp语法?

2 个答案:

答案 0 :(得分:12)

自动执行并不容易。 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中包围整个内容构造以保留语义。您还需要检查 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指令。事实证明,至少英特尔Fortran编译器和GCC序列化FORALL语句并在OpenMP workshare指令内构造,在编译期间用OpenMP single指令包围它们,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现便携性能,最好避免使用它。

答案 1 :(得分:1)

我不确定你的意思是“系统地并行化并发循环的方法”。但是,要简单地将一个普通的do循环与OpenMP并行化,您可以使用类似的东西:

!$omp parallel private (i)
!$omp do
do i = 1,10
    array(i) = i
end do
!$omp end do
!$omp end parallel

这就是你想要的吗?