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

+3


source to share


1 answer


(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.)

+6


source







All Articles