Difference in memory usage when using standard arrays and derived types in fortran 90
I have observed strange behavior regarding the memory usage of derived data types. The following fortran90 code demonstrates the problem.
module prec
implicit none
integer, parameter :: d_t = selected_real_kind(15,307)
end module
module typdef
use prec
implicit none
type level_2
real(kind=d_t), allocatable :: lev_3(:)
end type
type level_1
type(level_2),allocatable :: lev_2(:,:)
end type
type array
type(level_1),allocatable :: lev_1(:,:)
end type
end module
program mem_test
use prec
use typdef
implicit none
integer :: n,i,j,k,l,m,egmax,niter,ncells,namom,nsmom
real(kind=d_t),allocatable :: simple_array(:,:,:,:,:)
type(array) :: fancy_array
real(kind=d_t) :: it
egmax=7
niter=2
ncells=3000000
namom=1
nsmom=1
!
!
!
allocate( simple_array(egmax,niter,ncells,namom,nsmom) )
!
!
!
allocate( fancy_array%lev_1(egmax,niter))
do i=1,niter
do j=1,egmax
allocate( fancy_array%lev_1(j,i)%lev_2(ncells,namom) )
end do
end do
do i=1,niter
do j=1,egmax
do k=1,namom
do l=1,ncells
allocate( fancy_array%lev_1(j,i)%lev_2(l,k)%lev_3(nsmom) )
end do
end do
end do
end do
!
do n=1,100000
it=0.0_d_T
do i=1,100000
it=it+1.0_d_t
end do
end do
!
!
deallocate(simple_array)
deallocate(fancy_array%lev_1)
end program
I want to store data in a multidimensional array (e.g. max * niter * ncell * namom * nsmom double precision numbers). I did it in two different ways:
- Multidimensional standard array "simple_array (egmax, niter, ...,)"
- A nested derived data structure "fancy_array" as defined in the piece of code I provided.
I have compiled the code using
ifort -g -o test.exe file.f90
I ran it in valgrind and compared the memory consumption of simple_array and fancy_array. simple_array uses roughly 300Mb as expected, while fancy_array uses 3Gb (10x more) even if it stores the same number of real numbers. Therefore, it should also only consume 300MB.
Running a simpler test case where the derived type has only one level of depth, like
type level_1
real(kind=d_t),allocatable :: subarray(:)
end type
type array
type(level_1),allocatable :: lev_1(:)
end type
consumes exactly the amount of memory I expect. It does not consume 10 times more memory. Has anyone observed similar behavior or had any idea why this would happen? My only idea because of the described behavior is that fancy_array allocates non-contiguous memory and fortran somehow needs to keep track of it, hence increasing memory consumption. Any introductory or similar observations would be appreciated.
Thank you for your help.
Sebastian
source to share
(Allocatable is a Fortran 2003 feature.)
A typical way Fortran processors (including Intel Fortran) implement allocatable arrays is to use a descriptor, a data structure that contains information such as the location of the array's data in memory, and the bounds and spacing of each dimension of the array, among other things .
For Intel Fortran on the x64 platform, the descriptor is 72 bytes for a one-dimensional allocation array. In the case of your derived type, you have about 42 million such arrays - one for each component lev_3
you create, plus a significantly smaller number for the parent distributed components. 72 bytes by 42 million gives about 3 GB. There may be additional overhead associated with the main memory allocator.
On the same platform, a descriptor for a rank five array takes 168 bytes and there is only one memory allocation
The storage requirements for the two approaches will be approximately the same.
Note that the possibilities offered by these two approaches are significantly different (hence the difference in overhead) - in the case of a derived type, you can change the distribution status, boundaries, and degree of each component lev_3
. You don't have that flexibility in the case of a single array - if the allocated array needs to be rectangular.
(In Fortran 90, your component parameters in their declarations must be constant expressions (fixed at compile time). No descriptors will be used, and the memory requirements of the two approaches will converge.)
source to share