構造体の配列: Sample 1: 構造体のメンバーのコピー(FORTRAN)

高速化プログラミング   
トップ  >  メモリジャンプと高速化  >  構造体の配列  >  Sample 1: 構造体のメンバーのコピー(FORTRAN)

構造体の配列: Sample 1: 構造体のメンバーのコピー(FORTRAN)

言語の変更:   C版

■ 概要

ここでは構造体のあるメンバーの配列を別の配列にコピーするサンプルを示します。

Code 1は配列の構造体のサンプルです。配列a, b, c, d, e, f, g, hをメンバーとするVectorという構造体を定義します。Vector型のvecを宣言してからそれぞれのメンバーの配列を長さnでメモリの確保をします。メイン計算ではメンバーの配列aを別の配列rにコピーをします。

Code 2は構造体の配列のサンプルです。a, b, c, d, e, f, g, hをメンバーとするVectorという構造体を定義します。Vector型の配列vecを長さnでメモリの確保をします。Code 1と同様にメイン計算ではメンバーの配列aを別の配列rにコピーをします。

配列の長さnとして2,000,000から40,000,000まで20個の値を用いて、Code 1Code 2のメイン計算にかかる時間を測定して出力します。

■ ソースコード


  ◆ Code 1   ◆ Code 2
 
c Program to copy a member of a structure to another array
      program double_array_sample1_ex1
      implicit none
c
      type Vector
      real*8, allocatable :: a(:), b(:), c(:), d(:), e(:), f(:),
     &   g(:), h(:)
      end type Vector
c
      type(Vector) :: vec
      real*8, allocatable :: r(:)
      integer i, k, n
      integer*8 time0, time1, dtime
      real*8 time
c
      write(*,*)"Array size    Elapsed time [sec]"
      do k=1,20
c Array size
        n = k * 2000000

c Allocation
        allocate(vec%a(n), vec%b(n), vec%c(n), vec%d(n),
     &     vec%e(n), vec%f(n), vec%g(n), vec%h(n), r(n))

c Initialization
        do i=1,n
          vec%a(i) = 1d0
          vec%b(i) = 1d0
          vec%c(i) = 1d0
          vec%d(i) = 1d0
          vec%e(i) = 1d0
          vec%f(i) = 1d0
          vec%g(i) = 1d0
          vec%h(i) = 1d0
        end do

c Start time
        call system_clock(time0)

c Main calculation: copy the member a to r
        do i=1,n
          r(i) = vec%a(i)
        end do

c Finish time
        call system_clock(time1, dtime)

c Output time
        time = 1d0*(time1-time0)/dtime
        write(*,"(i11,f16.7)")n, time

c Deallocation
        deallocate(vec%a, vec%b, vec%c, vec%d, vec%e,
     &     vec%f, vec%g, vec%h, r)
      end do

      end program

    
 
c Program to copy a member of a structure to another array
      program double_array_sample1_ex2
      implicit none
c
      type Vector
      real*8 a, b, c, d, e, f,
     &   g, h
      end type Vector
c
      type(Vector), allocatable :: vec(:)
      real*8, allocatable :: r(:)
      integer i, k, n
      integer*8 time0, time1, dtime
      real*8 time
c
      write(*,*)"Array size    Elapsed time [sec]"
      do k=1,20
c Array size
        n = k * 2000000

c Allocation
        allocate(vec(n), r(n))


c Initialization
        do i=1,n
          vec(i)%a = 1d0
          vec(i)%b = 1d0
          vec(i)%c = 1d0
          vec(i)%d = 1d0
          vec(i)%e = 1d0
          vec(i)%f = 1d0
          vec(i)%g = 1d0
          vec(i)%h = 1d0
        end do

c Start time
        call system_clock(time0)

c Main calculation: copy the member a to r
        do i=1,n
          r(i) = vec(i)%a
        end do

c Finish time
        call system_clock(time1, dtime)

c Output time
        time = 1d0*(time1-time0)/dtime
        write(*,"(i11,f16.7)")n, time

c Deallocation
        deallocate(vec, r)

      end do

      end program

    

■ 計算時間の測定結果

Code 1Code 2を実行したときの計算時間をそれぞれ青線と赤線で図1に示します。そして両者の比を緑線で示します。

測定時間
図1 測定時間

■ 考察

Code 1の配列の構造体では配列のメンバーが連続的に配置されているので、構造体のメンバー、配列aにアクセスするときはメモリのジャンプは起こりません(図2を参照)。一方、Code 2の構造体の配列では構造体の同じメンバーは不連続に配列されているので、このサンプルでは図3のようにメモリのジャンプが起こります。

Code 1のときのメモリアクセス
図2 Code 1のときのメモリアクセス
Code 2のときのメモリアクセス
図3 Code 2のときのメモリアクセス

図1の実測ではCode 1Code 2より計算時間が2~3倍速いです。2次元配列のときよりは倍率が低いですが、構造体のメンバーの個数(サイズ)によっては倍率がもっと上がる可能性があります。



はじめに

演算数を減らす

メモリジャンプを減らす

高性能のアルゴリズム

その他



4 8 2 5 4 3