1

我有一个使用 Fortran 95 和 gfortran 编译器的代码。我也在使用 OpenMP,我必须处理非常大的数组。在我的代码中,我还必须使用 OpenBLAS 的求解器 DGTSV 求解线性方程组。我想并行化这个求解器以及使用应该能够做到的openblas。但我在语法上有问题。使用附加的伪代码,所有 4 个 CPU 几乎 100% 使用,但我不确定每个内核是否单独求解线性方程,或者是否将其拆分为多个部分并并行计算。整个东西是使用编译的gfortran -fopenmp -lblas a.f95 -o a.out

所以我的伪代码看起来像

program a
implicit none
integer, parameter  ::  N   =       200
real*8, dimension(numx) ::  D   =       0.0
real*8, dimension(numx-1):: DL  =       0.0
real*8, dimension(numx-1):: DU  =       0.0
real*8, dimension(numx) ::  b   =       0.0
integer         ::  info    =       0
integer :: numthread=4
...
!$OMP PARALLEL NUM_THREADS(numthread)
...
!$OMP DO
...
!$OMP END DO
CALL DGTSV(N,1,DL,D,DU,b,N,info)
!$OMP DO
...
!$OMP END DO
...
!$OMP END PARALLEL
end program a

我必须做什么才能使求解器并行化,以便每个内核计算求解器的各个部分?

4

1 回答 1

1

在 OpenMP 并行区域内,所有线程都执行相同的代码(如在 MPI 中),并且仅当线程到达循环/部分/任务时才拆分工作。

在您的示例中,循环 ( OMP DO) 内的工作分布在可用线程之间。循环完成后,隐式屏障同步所有线程,然后它们并行执行 function DGTSV。在子程序返回后,循环再次被拆分。

@HristoIliev 建议使用一个OMP SINGLE子句。这限制了内部的一段代码只能由一个线程执行,并强制所有其他线程等待它(除非您指定nowait)。

另一方面,嵌套并行被称为在另一个并行区域内声明一个并行区域的情况。当您在并行区域内执行对 OpenMP 并行化库的调用时,这也适用。

默认情况下,OpenMP 不会增加嵌套并行区域的并行度,而是只有进入并行区域的线程才能执行它。可以使用环境变量将这种行为更改OMP_NESTEDtrue.

OMP SINGLE解决方案比将并行区域一分为二要好得多,因为资源被重用于下一个循环:

$!OMP PARALLEL
  $!OMP DO
  DO ...
  END DO

  $!OMP SINGLE
  CALL DGTSV(...)

  $!OMP DO
  DO ...
  END DO
$!OMP END PARALLEL

为了说明的用法,OMP_NESTED我将向您展示我从一个使用 FFTW(一种快速傅里叶变换实现)配置为使用 OpenMP 的应用程序中获得的一些结果。执行在 16 核双插槽 Intel Xeon E5 @2.46GHz 节点中执行。

下图显示了在整个应用程序中花费的时间,其中并行区域在 CPU > 1 时出现,在 CPU = 1 时出现序列化区域,在 CPU = 0 时出现同步区域。

该应用程序是令人尴尬的并行,因此在这种特殊情况下使用嵌套是不值得的(FFTW 不能很好地扩展)。

这就是OMP_NESTED=false执行。观察并行量如何受到外部并行区域 (ftdock) 中所用线程数量的限制。

未嵌套的 OpenMP 版本

这就是OMP_NESTED=true执行。在这种情况下,可以进一步增加并行度,而不是在外部并行区域上花费的线程数量。在这种情况下,最大可能的并行度为 16,当 8 个外部线程创建一个对等体来执行内部并行区域时,或者它们是 4 个,每个线程创建 3 个附加线程(8x2 = 4x4 = 16)。

嵌套 OpenMP 版本

于 2016-10-06T15:29:57.523 回答