使用可分配数组的性能损失

lea*_*dro 5 arrays fortran

我有一个 Fortran90 程序 (Packmol),直到它是通过静态内存分配实现的。

我将代码更改为使用动态分配,以便在开始时分配所有数组。在某些示例中,我的性能损失了 400%。

然后,我验证了即使数组的大小与我使用静态分配时的大小相同,问题仍然存在。也就是说,如果我将分配更改为 类似 That 的内容,则足以导致性能损失。当然,当所有需要动态分配的数组都这样做时,大约有 30 个。 double precision :: x(1000) double precision, allocatable :: x(:) allocate(x(1000))

有没有办法以更有效的方式分配数组以减少性能损失?或者有人有不同的建议?

非常感谢。

编辑:不知何故,问题得到了解决。动态版本现在只比静态版本慢一点,这是预期的。我真的不知道是什么导致了之前的重大放缓。

Ant*_*ama 3

造成这种性能损失的原因可能有很多:

1) 静态数组始终在 BSS 上分配(请参阅静态变量存储在哪里(在 C/C++ 中)?),而“已分配”数组可以在堆或堆栈上分配。堆栈上的分配比堆上的分配快得多。一个好的编译器可以生成在堆栈上分配尽可能多的内存的代码。

2) 您可能在循环中有分配/解除分配语句。每次内存分配都会花费​​一些时间。一个好的编译器可以避免在每次分配时物理地分配一些内存,而是重新使用已释放的空间。

3)编译器在编译时就知道静态数组的维度,因此它会做一些额外的优化。

4)如果有多维数组,则无法在编译时计算元素的地址。例如, 的地址A(5,6,7)是,5 + 6*n1 + 7*n1*n2是:的维度。对于静态数组,编译器可以优化这部分。此外,如果维度是 2 的幂,编译器将生成位移位,而不是执行整数乘法,速度快 3 倍。n1n2AA(n1,n2,n3)n1,n2,...

3)是最有可能的。您可以为在编译时知道合理上限的数组保留一些静态数组,这些数组相对较小(大约<1000个元素),并且也在经常调用且执行少量工作的例程内。

根据经验,只有小型数组可以静态分配:大多数 1D 数组、一些小型 2D 数组和微小的 3D 数组。将所有其余的转换为动态分配,因为它们可能无法放入堆栈中。

如果您有一些频繁的分配/解除分配,因为您在循环中调用子例程,如下所示:

 do i=1,10000000
    call work(a,b)
 end do

 subroutine work(a,b)
  ...
  allocate (c)
  ...
  deallocate (c)
 end
Run Code Online (Sandbox Code Playgroud)

如果c始终具有相同的维度,您可以将其作为子例程的参数,或者作为全局变量,在调用 work 之前仅分配一个:

 use module_where_c_is_defined

 allocate (c)
 do i=1,10000000
    call work(a,b)
 end do
 deallocate(c)

 subroutine work(a,b)
  use module_where_c_is_defined
  if (.not.allocated(c)) then
    stop 'c is not allocated'
  endif
  ...
 end
Run Code Online (Sandbox Code Playgroud)