うまくいけば、私はこのことを説明することができました。私は、Fortranでの作業と実際にCFDのトピックに私のコードを書いて、下記の(ちょうど簡単のために、ちょうど例えば)私の場合の短い説明をしているんだ:2D配列A(i、j)の最適な構成を選択する方法
- 私は1次元配列Aを使用する必要があります(I 、j)と1D配列B(i)
- 私は2回ループする必要があります。これは、最初のループは50,000回、2回目は5回(変更できません)です。
- 上記のポイント番号2は10,000回ループする必要があります。
2つのバージョン(私はそれらをProg_AとProg_Bと呼んでいます)でコードを書きます。
PROGRAM PROG_A
REAL*8, DIMENSION(50000,5):: A
REAL*8, DIMENSION(50000)::B
REAL*8:: TIME1,TIME2
!Just for initial value
DO I=1, 50000
A(I,1)=1.0
A(I,2)=2.0
A(I,3)=3.0
A(I,4)=4.0
A(I,5)=5.0
B(I)=I
END DO
!Computing computer's running time (start)
CALL CPU_TIME(TIME1)
DO K=1, 100000
DO I=1, 50000 !Array should be computed first for 50,000 elements (can't be changed)
DO J=1, 5
A(I,J)=A(I,J)+SQRT(B(I))
END DO
END DO
END DO
!Computing computer's running time (finish)
CALL CPU_TIME(TIME2)
PRINT *, 'Elapsed real time = ', TIME2-TIME1, 'second(s)'
END PROGRAM PROG_A
第二つある:以下に示すように
最初のものである
PROGRAM PROG_B
REAL*8, DIMENSION(5,50000):: A
REAL*8, DIMENSION(50000)::B
REAL*8:: TIME1,TIME2
!Just for initial value
DO J=1, 50000
A(1,J)=1.0
A(2,J)=2.0
A(3,J)=3.0
A(4,J)=4.0
A(5,J)=5.0
B(J)=J
END DO
!Computing computer's running time (start)
CALL CPU_TIME(TIME1)
DO K=1, 100000
DO J=1, 50000 !Array should be computed first for 50,000 elements (can't be changed)
DO I=1, 5
A(I,J)=A(I,J)+SQRT(B(J))
END DO
END DO
END DO
!Computing computer's running time (finish)
CALL CPU_TIME(TIME2)
PRINT *, 'Elapsed real time = ', TIME2-TIME1, 'second(s)'
END PROGRAM PROG_B
別の私は2次元配列Aを用いる最初のもの(50000ためのものである見ることができるように、 5)、2番目には2DアレイA(5,50000)を使用しました。
私が知っているところでは、Fortranは「列メジャー」に基づいているため、2番目のケースは最初のものより高速です(2番目のケースでは、配列の最も内側のループを実行していますこの場合i = 1、...、5)。
しかし、gfortran(-O3最適化)でコンパイルした後、私は、2番目のものが最初のものよりずっと遅いことも発見しました。ここでの結果は次のとおりです。
- 最初のケース:経過時間= 70.496秒
は、誰もが、なぜ私に説明してもらえ:時間= 29.187秒
PS:両方のケースの結果は確かに同じです。
多くの場合、コンパイラはループの順序を切り替えることができます。 –
私は最初の例でコンパイラがあなたの最も内側のループを展開し、その結果得られる長いストライド1ループの効率的なベクトル化されたコードを生成すると思います。 – haraldkl
@VladimirF:ありがとうございました。コンパイラが非効率なループを検出できるはずですか?私にお知らせください。 –