剖析我们的fortran代码之一,有两个子程序占用了大部分计算时间(22.1%和17.2%)。在每个程序中,约5%的时间花在分配和释放内存上。这些程序看起来像Fortran:动态数组与自动数组避免内存分配
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次,我的基准点,所以我想摆脱分配和释放的。将这些更改为自动数组会将分析器输出更改为。
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
在哪里这些额外mallocs,并释放来自哪里?我怎么设置这个,所以我分配这些数组一次?
Fortran中的堆数组通过隐式'malloc' /'free'调用在每个函数调用上分配和释放。它们在这方面与'ALLOCATABLE'数组没有区别。 –
我不希望这种情况发生在ifort上。我始终使用第二种方法,即使用多次预分配的缓冲区而不释放和重新分配。 – bdforbes
当您事先分配一个配置文件时,配置文件不可能变得更糟......您是否找出原因? – Lupocci