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

时间:2016-03-09 20:19:12

标签: arrays fortran

我有一个Fortran90程序(Packmol),直到用静态内存分配实现。

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

然后,我验证了即使数组的大小与我使用静态分配时的大小相同,问题仍然存在。也就是说,如果我更改分配 double precision :: x(1000) 喜欢的东西 double precision :: x(1000) 这足以导致性能下降。当然,当需要动态分配的所有数组(大约30个)完成时。

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

非常感谢。

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

1 个答案:

答案 0 :(得分:2)

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

1)静态数组始终在BSS上分配(参见Where are static variables stored (in C/C++)?),而“已分配”数组可以在堆上或堆栈上分配。堆栈上的分配比堆上快得多。一个好的编译器可以生成在堆栈上尽可能多地分配的代码。

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

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

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

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

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

如果你有一些频繁的分配/解除分配,因为你在这样的循环中调用子程序:

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

 subroutine work(a,b)
  ...
  allocate (c)
  ...
  deallocate (c)
 end

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

 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