gpt4 book ai didi

memory-management - 本地可分配数组和自动数组之间的区别

转载 作者:行者123 更新时间:2023-12-04 07:43:40 26 4
gpt4 key购买 nike

我对 alloc_array 之间的区别感兴趣和 automatic_array在以下摘录中:

subroutine mysub(n)
integer, intent(in) :: n
integer :: automatic_array(n)
integer, allocatable :: alloc_array(:)

allocate(alloc_array(n))
...[code]...

我对 足够熟悉基础知识 分配(在高级技术上不多)知道分配允许您更改代码中间的数组大小(如 this question 中所指出的),但我有兴趣考虑您的情况不要 需要改变数组的大小;它们可能会被传递给其他子程序进行操作,但代码和任何子程序中的两个变量的唯一目的是保存维度为 n 的数组的数据。 (可能会更改数据,但不会更改大小)。

(1) 内存使用有什么不同吗? 我不是低级程序的专家,但我对它们的重要性以及它们如何影响更高级别的编程知之甚少(我正在谈论的那种经验:曾经尝试在 fortran 中运行大代码我遇到了一个我不明白的错误,系统管理员告诉我“哦,是的,你可能正在使堆栈饱和;尝试在你的运行脚本中添加这一行”;任何能让我深入了解在实际编码时如何考虑这些事情的东西欢迎以后不必修补它们)。人们告诉我,它可能依赖于许多其他东西,比如编译器或架构,但我从这些回复中解释说,他们并不完全确定这是怎么回事。它是否如此绝对依赖于多种因素,或者编码中是否存在默认/预期行为,然后可能会被可选的编译关键字或系统偏好所覆盖?

(2) 子程序会有不同的接口(interface)需求吗? 同样,不是专家,但在此之前我也遇到过这种情况,因为我声明子程序变量的方式,我最终不得不将子程序放在一个模块中。我被告知这可能会有所不同,具体取决于我是否使用了对可分配变量特别的东西。我正在考虑这样一种情况,即我对变量所做的一切都可以通过可分配对象和自动对象来完成,而不是故意使用任何特定的可分配对象(即使用前分配除外)。

最后,以防万一:我问的原因是因为我们是在一个小组中开发的,我们最近注意到不同的人以不同的方式使用这两个声明,我们需要确定这是否可以留给个人喜好,或者是否有任何原因为什么设置一个明确的标准(以及如何设置该标准)可能是一个好主意。我不需要非常详细的答案,我正在尝试确定这是否是我应该做的研究,以小心我们如何使用它以及应该在哪些方面进行研究。

虽然我很想知道“有趣的技巧”而不是分配可以做到的,但与大小可变性的需求没有直接关系,我将这些留给 future 可能的后续问题,并在这里关注严格的功能差异(意思是:我明确告诉编译器如何处理我的代码)。我提到的两个项目是我可以根据以前的经验提出的,但是任何其他我遗漏并应该考虑的重要项目,请务必提及。

最佳答案

因为 gfortran 或 ifort + Linux(x86_64) 是用于 HPC 的最流行的组合之一,所以我对这些组合的本地可分配数组和自动数组进行了一些性能比较。使用的CPU是Xeon E5-2650 v2@2.60GHz,编译器是gfortran4.8.2和ifort14.0。测试程序如下。

In test.f90:

!------------------------------------------------------------------------
subroutine use_automatic( n )
integer :: n

integer :: a( n ) !! local automatic array (with unknown size at compile-time)
integer :: i

do i = 1, n
a( i ) = i
enddo

call sub( a )
end

!------------------------------------------------------------------------
subroutine use_alloc( n )
integer :: n

integer, allocatable :: a( : ) !! local allocatable array
integer :: i

allocate( a( n ) )

do i = 1, n
a( i ) = i
enddo

call sub( a )

deallocate( a ) !! not necessary for modern Fortran but for clarity
end

!------------------------------------------------------------------------
program main
implicit none
integer :: i, nsizemax, nsize, nloop, foo
common /dummy/ foo

nloop = 10**7
nsizemax = 10

do i = 1, nloop
nsize = mod( i, nsizemax ) + 1

call use_automatic( nsize )
! call use_alloc( nsize )
enddo

print *, "foo = ", foo !! to check if sub() is really called
end

In sub.f90:

!------------------------------------------------------------------------
subroutine sub( a )
integer a( * )
integer foo
common /dummy/ foo

foo = a( 1 )
ends

在上面的程序中,我尝试通过将 sub() 放在不同的文件中并使接口(interface)隐式来避免消除 a(:) 本身(即无操作)的编译器优化。首先,我使用 gfortran 作为编译程序
gfortran -O3 test.f90 sub.f90

并在保持 nloop = 10^7 的同时测试了不同的 nsizemax 值。结果如下表(时间以秒为单位,由time命令测量数次)。
nsizemax    use_automatic()    use_alloc()
10 0.30 0.31 # average result
50 0.48 0.47
500 1.0 0.90
5000 4.3 4.2
100000 75.6 75.7

因此,当使用 -O3 时,两次调用的总体时间似乎几乎相同(但请参阅编辑了解不同的选项)。接下来,我用 ifort 编译为
[O3]  ifort -O3 test.f90 sub.f90
or
[O3h] ifort -O3 -heap-arrays test.f90 sub.f90

在前一种情况下,自动数组存储在堆栈中,而当附加 -heap-arrays 时,数组存储在堆中。得到的结果是
         use_automatic()    use_alloc()
[O3] [O3h] [O3] [O3h]
10 0.064 0.39 0.48 0.48
50 0.094 0.56 0.65 0.66
500 0.45 1.03 1.12 1.12
5000 3.8 4.4 4.4 4.4
100000 74.5 75.3 76.5 75.5

所以对于 ifort 来说,在主要使用相对较小的数组时,使用自动数组似乎是有益的。另一方面, gfortran -O3 显示没有区别,因为两个数组的处理方式相同(有关详细信息,请参阅编辑)。

附加比较:

下面是适用于 Linux 的 Oracle Fortran 编译器 12.4(与 f90 -O3 一起使用)的结果。总体趋势似乎相似;对于较小的 n,自动数组更快,表明堆栈的内部使用。
nsizemax    use_automatic()    use_alloc()
10 0.16 0.45
50 0.17 0.62
500 0.37 0.97
5000 2.04 2.67
100000 65.6 65.7

编辑

感谢 Vladimir 的评论,事实证明 gfortran -O3 将自动数组(在编译时大小未知)放在堆上。这解释了为什么 use_automatic() 和 use_alloc() 在上面没有任何区别。所以我在下面的不同选项之间做了另一个比较:
[O3]  gfortran -O3
[O5] gfortran -O5
[O3s] gfortran -O3 -fstack-arrays
[Of] gfortran -Ofast # this includes -fstack-arrays

在这里, -fstack-arrays意味着编译器将所有大小未知的本地数组放入堆栈。请注意,默认情况下使用 -Ofast 启用此标志。 .得到的结果是
nsizemax    use_automatic()               use_alloc()
[Of] [O3s] [O5] [O3] [Of] [O3s] [O5] [O3]
10 0.087 0.087 0.29 0.29 0.29 0.29 0.29 0.29
50 0.15 0.15 0.43 0.43 0.45 0.44 0.44 0.45
500 0.57 0.56 0.84 0.84 0.92 0.92 0.92 0.92
5000 3.9 3.9 4.1 4.1 4.2 4.2 4.2 4.2
100000 75.1 75.0 75.6 75.6 75.6 75.3 75.7 76.0

其中显示了十次测量的平均值。此表说明如果 -fstack-arrays包括在内,小 n 的执行时间变短。这一趋势与上述 ifort 获得的结果一致。

不过需要指出的是,上述比较可能对应于突出它们之间差异的“最佳情况”场景,因此在实践中时间差异可能会小得多。例如,我通过使用其他一些程序(涉及小型和大型数组)比较了上述选项的时序,结果受堆栈选项的影响不大。当然,结果应该取决于机器架构和编译器。所以你的里程可能会有所不同。

关于memory-management - 本地可分配数组和自动数组之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31433121/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com