構造体の配列: Sample 2: 構造体のメンバーの和の計算(FORTRAN)

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

構造体の配列: Sample 2: 構造体のメンバーの和の計算(FORTRAN)

言語の変更:   C版

■ 概要

ここでは構造体の全部のメンバーの和を別の配列にコピーするサンプルを示します。内容的にはSample 1と似ていますが、違いは配列rに代入するのはあるひとつのメンバーではなくて、全部のメンバーの和です。つまりSample 1ではひつとのメンバーだけにアクセスしますが、このサンプルでは全メンバーにアクセスします。

■ ソースコード


  ◆ Code 1   ◆ Code 2
 
c Program to take the sum of the members of a structure
c 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: find the sum of all members of vec
        do i=1,n
          r(i) = vec%a(i) + vec%b(i) + vec%c(i) + vec%d(i)
     &       + vec%e(i) + vec%f(i) + vec%g(i) + vec%h(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 take the sum of the members of a structure
c 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: find the sum of all members of vec
        do i=1,n
          r(i) = vec(i)%a + vec(i)%b + vec(i)%c + vec(i)%d
     &       + vec(i)%e + vec(i)%f + vec(i)%g + vec(i)%h
        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の配列の構造体では配列のメンバーが連続的に配置されているので、構造体の全部のメンバーを順番ににアクセスするとメモリのジャンプが起こります(図2を参照)。一方、Code 2の構造体の配列では構造体の同じメンバーは不連続に配列されているので、このサンプルでは図3のようにメモリのジャンプが起こりません。

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

図1の実測ではCode 2Code 1より計算時間が1.2倍ぐらい速いです。メモリのジャンプの面ではSample 1と似ていますが、Sample 2の倍率の方が低いです。これは、Sample 2のときの演算数がSample 1より多いためでしょう。



はじめに

演算数を減らす

メモリジャンプを減らす

高性能のアルゴリズム

その他



4 8 2 6 4 5