什么时候应该使用DO CONCURRENT和OpenMP?

时间:2016-07-24 07:21:27

标签: concurrency fortran openmp simd fortran2008

我知道thisthis,但我再次问,因为现在第一个链接已经很老了,第二个链接似乎没有得出确凿的答案。是否已达成共识?

我的问题很简单:

我有一个DO循环,其中包含可能并发运行的元素。我使用哪种方法?

下面是在简单立方晶格上生成粒子的代码。

  • npart 是粒子数
  • npart_edge & npart_face 分别是边缘和面部
  • space 是晶格间距
  • Rx Ry Rz 是位置数组
  • x y z 是决定格子位置的临时变量

请注意,在CONCURRENT情况下,x,y和z必须是数组,但在OpenMP情况下不是这样,因为它们可以定义为PRIVATE。

所以我使用DO CONCURRENT(正如我从上面的链接中所理解的那样,使用SIMD):

DO CONCURRENT (i = 1, npart)
    x(i) = MODULO(i-1, npart_edge)
    Rx(i) = space*x(i)
    y(i) = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y(i)
    z(i) = (i-1) / npart_face
    Rz(i) = space*z(i)
END DO

或者我使用OpenMP?

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(x,y,z)
!$OMP DO
DO i = 1, npart
    x = MODULO(i-1, npart_edge)
    Rx(i) = space*x
    y = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y
    z = (i-1) / npart_face
    Rz(i) = space*z
END DO
!$OMP END DO
!$OMP END PARALLEL

我的测试:

将64粒子放入10号方框中:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  6.870000000000001E-003
Real time =  3.600000000000000E-003

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  6.699999999999979E-005
Real time =  0.000000000000000E+000

将100000个颗粒放在100面的盒子中:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  8.213300000000000E-002
Real time =  1.280000000000000E-002

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  2.385000000000000E-003
Real time =  2.400000000000000E-003

使用DO CONCURRENT构造似乎给了我至少一个数量级更好的性能。这是在i7-4790K上完成的。此外,并发的优势似乎随着大小的增加而减少。

1 个答案:

答案 0 :(得分:3)

DO CONCURRENT本身不进行任何并行化。编译器可以决定使用线程并行化它或使用SIMD指令。对于线程,您经常需要指示它这样做。或者(通常!)它只是将其视为常规DO并使用SIMD,如果它将它们用于常规DO。

OpenMP也不仅仅是线程,编译器可以根据需要使用SIMD instructuons。还有omp simd指令,但这只是建议编译器使用SIMD,可以忽略它。

你应该尝试,测量和看到。没有一个明确的答案。甚至对于给定的编译器来说,所有编译器都没有。

我的做法是使用OpenMP并尝试确保编译器矢量化(SIMD)它能做什么。特别是因为我无论如何都在我的程序中使用OpenMP。 DO CONCURRENT仍然需要证明它确实有用。我还不相信。