【发布时间】:2015-12-18 11:53:55
【问题描述】:
我已经编写了一个科学代码,并且像往常一样,这归结为计算代数特征值方程中的系数:计算这些系数需要对多维数组进行积分,这会迅速大幅增加内存使用量。一旦计算出矩阵系数,就可以释放原始的预积分多维数组,并由智能求解器接管,因此内存使用不再是大问题。如您所见,存在瓶颈,在我的 64 位、4 核、8 线程、8GB 内存笔记本电脑上,程序由于内存不足而崩溃。
因此,我正在实施一个系统,通过限制 MPI 进程在计算某些特征值矩阵元素时可以执行的任务的大小来控制内存使用情况。完成后,他们将寻找剩余的工作,以便矩阵仍然被填充,但以更顺序和更少并行的方式。
因此,我检查了我可以分配多少内存,这就是混乱开始的地方:我分配大小为 8 字节的双精度对象(使用 sizeof(1) 检查)并查看分配状态。
虽然我有 8 GB 的可用内存来运行只有 1 个进程的测试,但我可以分配一个最大为 (40000,40000) 的数组,它对应于大约 13GB 的内存!因此,我的第一个问题是:这怎么可能?有这么多虚拟内存吗?
其次,我意识到我也可以为多个进程做同样的事情:最多 16 个进程可以同时分配这些海量数组!
这不可能吧?
有人知道为什么会这样吗?以及我是否做错了什么?
编辑:
这是产生上述奇迹的代码,至少在我的机器上是这样。但是,当我将数组的元素设置为某个值时,它确实会按应有的方式运行并崩溃——或者至少开始缓慢地运行 very,我猜这是因为虚拟内存速度慢用过吗?
program test_miracle
use ISO_FORTRAN_ENV
use MPI
implicit none
! global variables
integer, parameter :: dp = REAL64 ! double precision
integer, parameter :: max_str_ln = 120 ! maximum length of filenames
integer :: ierr ! error variable
integer :: n_procs ! MPI nr. of procs
! start MPI
call MPI_init(ierr) ! initialize MPI
call MPI_Comm_size(MPI_Comm_world,n_procs,ierr) ! nr. MPI processes
write(*,*) 'RUNNING MPI WITH', n_procs, 'processes'
! call asking for 6 GB
call test_max_memory(6000._dp)
call MPI_Barrier(MPI_Comm_world,ierr)
! call asking for 13 GB
call test_max_memory(13000._dp)
call MPI_Barrier(MPI_Comm_world,ierr)
! call asking for 14 GB
call test_max_memory(14000._dp)
call MPI_Barrier(MPI_Comm_world,ierr)
! stop MPI
call MPI_finalize(ierr)
contains
! test whether maximum memory feasible
subroutine test_max_memory(max_mem_per_proc)
! input/output
real(dp), intent(in) :: max_mem_per_proc ! maximum memory per process
! local variables
character(len=max_str_ln) :: err_msg ! error message
integer :: n_max ! maximum size of array
real(dp), allocatable :: max_mem_arr(:,:) ! array with maximum size
integer :: ierr ! error variable
write(*,*) ' > Testing whether maximum memory per process of ',&
&max_mem_per_proc/1000, 'GB is possible'
n_max = ceiling(sqrt(max_mem_per_proc/(sizeof(1._dp)*1.E-6)))
write(*,*) ' * Allocating doubles array of size', n_max
allocate(max_mem_arr(n_max,n_max),STAT=ierr)
err_msg = ' * cannot allocate this much memory. Try setting &
&"max_mem_per_proc" lower'
if (ierr.ne.0) then
write(*,*) err_msg
stop
end if
!max_mem_arr = 0._dp ! UNCOMMENT TO MAKE MIRACLE DISSAPEAR
deallocate(max_mem_arr)
write(*,*) ' * Maximum memory allocatable'
end subroutine test_max_memory
end program test_miracle
保存在test.f90,随后编译运行
mpif90 test.f90 -o test && mpirun -np 2 ./test
【问题讨论】:
-
你能发布一个重现这个奇迹的最小工作代码吗?
-
尝试将所有内存设置为零 - 即数组 = 0.0。那会发生什么?我怀疑这是stackoverflow.com/questions/864416/are-some-allocators-lazy 的一种表现形式,这对于 HPC 来说是众所周知的痛苦......
-
@IanBush 我很确定这正是问题所在。事实上,我今天早些时候遇到了这个确切的问题。 OP,如果您一分配内存,就尝试将其设置为 0.0,它肯定会崩溃。