4

派生データ型のメモリ使用量に関して奇妙な動作を観察しました。次のfortran90コードは、この問題を示しています。

  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

データを多次元配列(egmax * niter * ncell * namom * nsmom倍精度数)に格納したい。私は2つの異なる方法でそれを行いました:

  1. 多次元標準配列「simple_array(egmax、niter、...、)」
  2. 私が提供したコードの一部で定義されている、ネストされた派生データ構造「fancy_array」。

を使用してコードをコンパイルしました

    ifort -g -o  test.exe file.f90

valgrindで実行し、simple_arrayとfancy_arrayのメモリ消費量を比較しました。simple_arrayは予想どおり約300Mbを使用しますが、fancy_arrayは同じ数の実数を格納しているにもかかわらず3Gb(10倍)を使用します。したがって、300Mbしか消費しないはずです。

より単純なテストケースを実行します。ここで、派生型は1レベルの深さしかありません。

     type level_1
        real(kind=d_t),allocatable :: subarray(:)
     end type
     type array
        type(level_1),allocatable :: lev_1(:)
     end type         

私が期待している量のメモリを正確に消費します。10倍のメモリを消費しません。誰かが同様の行動を観察したことがありますか、またはこれが発生する理由について何か手がかりがありますか?説明されている動作の理由に関する私の唯一の考えは、fancy_arrayが非連続メモリを割り当て、Fortranがそれを追跡する必要があるため、メモリ消費量が増加することです。ご意見や同様のご意見をいただければ幸いです。

ご協力いただきありがとうございます。

セバスチャン

4

1 に答える 1

6

(割り当て可能なコンポーネントは Fortran 2003 の機能です。)

割り当て可能な配列オブジェクトの Fortran プロセッサ (インテル Fortran を含む) 実装の一般的な手段は、記述子を使用することです。これは、メモリ内の配列データの位置や、配列の各次元の境界とストライドなどの情報を含むデータ構造です。 、とりわけ

x64 プラットフォーム上のインテル Fortran の場合、その記述子は 1 次元の割り当て可能配列に対して 72 バイトを使用します。派生型の場合、そのような配列は約 4,200 万ありますlev_3。存在するすべてのコンポーネントに 1 つと、割り当て可能な親コンポーネントの数がはるかに少なくなります。72 バイト x 4200 万で約 3 GB になります。基になるメモリ アロケータに関連するオーバーヘッドがさらに発生する場合があります。

同じプラットフォームで、ランク 5 配列の記述子は 168 バイトを使用し、メモリ割り当ては 1 つだけです。

2 つのアプローチのデータ ストレージ要件はほぼ同じです。

2 つのアプローチによって提供される機能が大きく異なることに注意してください (したがって、オーバーヘッドの違いがあります)。派生型の場合、 lev_3コンポーネントの割り当て状態、境界、および範囲を変更できます。単一の配列の場合、その柔軟性はどこにもありません-割り当てられた場合、その配列は長方形でなければなりません。

(Fortran 90 では、宣言内のコンポーネントの次元は定数式である必要があります (コンパイル時に修正されます)。記述子は使用されず、2 つのアプローチのメモリ要件は収束します。)

于 2013-01-27T20:27:43.373 に答える