3

有一个程序的 mpi 版本,它使用 COMMON 块来存储通过代码到处使用的数组。不幸的是,没有办法以 COMMON 块大小声明数组,只有运行时才知道该数组的大小。因此,作为一种解决方法,我决定将这些数组移到接受 ALLOCATABLE 数组的模块中。也就是说,COMMON 块中的所有数组都消失了,而是使用了 ALLOCATE。所以,这是我在程序中唯一改变的地方。不幸的是,该程序的性能很糟糕(与 COMMON 块的实现相比)。对于 mpi-settings,每个计算节点上都有一个 mpi-process,每个 mpi-process 都有一个线程。我发现了类似的这里提出的问题但不认为(不明白:))如何将其应用于我的案例(每个进程都有一个线程)。我很感激任何帮助。

这是一个简单的例子,它说明了我在说什么(下面是一个伪代码):

“源文件”:

SUBROUTINE ZEROSET()
   INCLUDE 'FILE_1.INC'
   INCLUDE 'FILE_2.INC'
   INCLUDE 'FILE_3.INC'
   ....
   INCLUDE 'FILE_N.INC'

   ARRAY_1 = 0.0
   ARRAY_2 = 0.0
   ARRAY_3 = 0.0
   ARRAY_4 = 0.0
   ...
   ARRAY_N = 0.0
END SUBROUTINE

如您所见, ZEROSET() 没有并行或 MPI 的东西。FILE_1.INC, FILE_2, ... , FILE_N.INC 是在 COMMON 块中定义 ARRAY_1, ARRAY_2 ... ARRAY_N 的文件。类似的东西

REAL ARRAY_1
COMMON /ARRAY_1/ ARRAY_1(NX, NY, NZ)

其中 NX、NY、NZ 是在 PARAMETER 指令的帮助下定义明确的参数。当我使用模块时,我只是销毁了所有 COMMON 块,所以 FILE_I.INC 看起来像

REAL, ALLOCATABLE:: ARRAY_I(:,:,:)

然后将上面的“INCLUDE 'FILE_I.INC'”语句更改为“USE FILE_I”。实际上,当执行并行程序时,一个特定的进程不需要整个(NX,NY,NZ)域,所以我计算参数然后分配 ARRAY_I(仅 ONCE!)。

子程序 ZEROSET() 使用 COMMON 块执行 0.18 秒,使用模块执行 0.36 秒(当数组的维度在运行时计算时)。因此,性能恶化了两倍。

我希望现在一切都清楚了。我非常感谢你的帮助。

4

3 回答 3

3

在模块中使用可分配数组通常会损害性能,因为编译器在编译时不知道大小。使用此代码的许多编译器将获得更好的性能:

   subroutine X
   use Y  ! Has allocatable array A(N,N) in it
   call Z(A,N)
   end subroutine

   subroutine Z(A,N)
   Integer N
   real A(N,N)
   do stuff here
   end

然后这段代码:

   subroutine X
   use Y  ! Has allocatable array A(N,N) in it
   do stuff here
   end subroutine

编译器将知道数组是 NxN 并且 do 循环超过 N 并且能够利用这一事实(大多数代码在数组上以这种方式工作)。此外,在“do stuff here”中的任何子例程调用之后,编译器将不得不假设数组“A”可能已经改变了大小或移动了内存中的位置并重新检查。这会扼杀优化。

这应该可以让您恢复大部分性能。

公共块也位于内存中的特定位置,这也允许优化。

于 2011-09-09T15:55:50.510 回答
0

当谈到使用数组的 fortran 性能时,我可以想到这些原因:

  1. 堆栈 VS 堆上的数组,但我怀疑这会对性能产生巨大影响。
  2. 将数组传递给子例程,因为这样做的最佳方法取决于数组,请参阅此页面以有效地使用数组
于 2011-09-09T19:08:04.163 回答
0

其实我猜,你的问题是,结合堆栈与堆内存,确实是基于编译器优化的。根据您使用的编译器,它可能会执行一些更有效的内存消隐,并且对于固定的内存块,它甚至不需要检查它在子例程中的范围和位置。因此,在固定大小的数组中,几乎不会涉及任何开销。这个例程是不是经常被调用,或者你为什么关心这些 0.18 s?如果确实相关,最好的选择是完全摆脱 0 设置,而是例如分离第一个迭代循环并将其用于初始化,这样您就不必引入额外的内存访问,只需使用 0 进行初始化。但是它会重复一些代码......

于 2011-09-10T18:48:40.560 回答