【发布时间】:2012-06-28 03:57:59
【问题描述】:
分析我们的一个 fortran 代码,有两个子程序占用了大部分计算时间(22.1% 和 17.2%)。在每个例程中,大约 5% 的时间用于分配和释放内存。这些例程看起来像
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
IMPLICIT NONE
...
REAL, ALLOCATABLE, DIMENSION(:,:) :: work
...
ALLOCATE (work(size1,size2))
...
DEALLOCATE (work)
END SUBROUTINE bar
...
END MODULE foo
在我的基准测试中,这些子例程被调用了大约 4000-5000 次,所以我想摆脱 ALLOCATE 和 DEALLOCATE。将这些更改为自动数组将更改为探查器输出。
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
IMPLICIT NONE
...
REAL, DIMENSION(size1,size2) :: work
...
END SUBROUTINE bar
...
END MODULE foo
将生成的配置文件更改为
Running Time Symbol Name
20955.0ms 17.0% __totzsp_mod_MOD_totzsps
7.0ms 0.0% malloc
5.0ms 0.0% free
2.0ms 0.0% user_trap
16192.0ms 13.2% __tomnsp_mod_MOD_tomnsps
20.0ms 0.0% free
3.0ms 0.0% malloc
1.0ms 0.0% szone_size_try_large
我看起来 gfortran 将这些分配到堆栈而不是堆上,但我担心当这些数组变得太大时会发生什么。
我采用的第二种方法是将这些数组分配和释放一次。
work_array.f
MODULE work_array
IMPLICIT NONE
REAL(rprec), ALLOCATABLE, DIMENSION(:,:) :: work
END MODULE work_array
我在代码的不同部分分配一次。现在我的子程序看起来像
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
USE work_array
IMPLICIT NONE
...
END SUBROUTINE bar
...
END MODULE foo
但是,当我现在运行代码时,配置文件变得更糟。
Running Time Symbol Name
30584.0ms 21.6% __totzsp_mod_MOD_totzsps
3494.0ms 2.4% free
3143.0ms 2.2% malloc
27.0ms 0.0% DYLD-STUB$$malloc_zone_malloc
19.0ms 0.0% szone_free_definite_size
6.0ms 0.0% malloc_zone_malloc
24325.0ms 17.1% __tomnsp_mod_MOD_tomnsps
2937.0ms 2.0% free
2456.0ms 1.7% malloc
23.0ms 0.0% DYLD-STUB$$malloc_zone_malloc
3.0ms 0.0% szone_free_definite_size
这些额外的 malloc 和 free 来自哪里?如何设置它以便我分配这些数组一次?
【问题讨论】:
-
Fortran 中的堆数组通过隐式
malloc/free调用在每个函数调用中分配和释放。在这方面它们与ALLOCATABLE数组没有什么不同。 -
我不希望 ifort 会发生这种情况。我一直使用您的第二种方法,即有一个预先分配的缓冲区,我多次使用它而无需解除分配和重新分配。
-
如果您事先分配一个配置文件,配置文件不可能变得更糟...您找出原因了吗?
标签: fortran