0

まず、英語が苦手です。ごめんなさい。

私の知る限りでは。Fortran アドレスは列優先です。私の古い Fortran コードは長い間最適化されていません。速度を向上させるために、Fortran90 コード インデックスを変更しようとしています。

コードはほぼ 3 次元の行列です。(i, j, k) であり、ほぼ Do-loop は i と j についてです。i と j のサイズは約 2000 ~ 3000 で、k はちょうど 2 です。これは x,y を意味します。

私の古いコードのインデックス順は (i, k, j) です

例えば

Do j = 1 : 1500
    Do i = 1 : 1024
        AA(i, 1, j) = ... ;
        AA(i, 2, j) = ... ;
    end do
end do

私のコードにはこれらがたくさんあります。

そこで、インデックスの順序を変更しました。たとえば、(i, j, k), (k, i, j), (i, k, j) fortran (列優先) では (k, i, j) が最良の選択だと思います。

しかし、結果はそうではありません。

3 つのケース [ (i, j, k), (k, i, j), (i, k, j) ] はすべてほぼ時間を費やしています。(1961 年代、1955 年代、1692 年代)。

私のプログラムコードはとても長く、比較するには反復で十分です ( 32000 )

以下は私のコンパイルオプションです。

ifort -O3 -xHost -ipo -qopenmp -fp-model strict -mcmodel=medium

上記の結果がわかりません。私を助けてください。

読んでくれてありがとう。

さらに、以下は私のプログラムの1つです。行列 L_X(i, :, j) は私のターゲットです, : は 1 と 2

!$OMP Parallel DO private(j,i,ii,Tan,NormT)

do j=1,LinkPlusBndry
  if (Kmax(j)>2) then
     i=1; Tan=L_X(i+1,:,j)-L_X(i,:,j); NormT=sqrt(Tan(1)**2+Tan(2)**2)
     if (NormT < min_dist) then
        L_X(2:Kmax(j)-1,:,j)=L_X(3:Kmax(j),:,j)
        Kmax(j)=Kmax(j)-1
     elseif (NormT > max_dist) then
        do i=Kmax(j)+1,3,-1; L_X(i,:,j)=L_X(i-1,:,j); end do
        L_X(2,:,j)=(L_X(1,:,j)+L_X(3,:,j))/2.0_dp
        Kmax(j)=Kmax(j)+1
     end if
     do i=2,M-1
       if (i > (Kmax(j)-2) ) exit
       Tan=L_X(i+1,:,j)-L_X(i,:,j); NormT=sqrt(Tan(1)**2+Tan(2)**2)
       if (NormT < min_dist) then
         L_X(i,:,j)=(L_X(i,:,j)+L_X(i+1,:,j))/2.0_dp
         L_X(i+1:Kmax(j)-1,:,j)=L_X(i+2:Kmax(j),:,j)
         Kmax(j)=Kmax(j)-1
       elseif (NormT > max_dist) then
         do ii=Kmax(j)+1,i+2,-1; L_X(ii,:,j)= L_X(ii-1,:,j); end do
         L_X(i+1,:,j)=(L_X(i,:,j)+L_X(i+2,:,j))/2.0_dp
         Kmax(j)=Kmax(j)+1
       end if
     end do
     i=Kmax(j)-1;
     if (i>1) then
       Tan=L_X(i+1,:,j)-L_X(i,:,j); NormT=sqrt(Tan(1)**2+Tan(2)**2)
       if (NormT < min_dist) then
         L_X(Kmax(j)-1,:,j)=L_X(Kmax(j),:,j)
         Kmax(j)=Kmax(j)-1
       elseif (NormT > max_dist) then
         L_X(Kmax(j)+1,:,j)= L_X(Kmax(j),:,j)
         L_X(Kmax(j),:,j)=(L_X(Kmax(j)-1,:,j)+L_X(Kmax(j)+1,:,j))/2.0_dp
          Kmax(j)=Kmax(j)+1
       end if
     end if
  elseif (Kmax(j)==2) then
     i=1; Tan=L_X(i+1,:,j)-L_X(i,:,j); NormT=sqrt(Tan(1)**2+Tan(2)**2)
     if (NormT > max_dist) then
        do i=Kmax(j)+1,3,-1; L_X(i,:,j)=L_X(i-1,:,j); end do
        L_X(2,:,j)=(L_X(1,:,j)+L_X(3,:,j))/2.0_dp
        Kmax(j)=Kmax(j)+1
     end if
  end if
  do i=Kmax(j)+1,M; L_X(i,:,j)=L_X(Kmax(j),:,j); end do
end do

!$OMP End Parallel DO
4

1 に答える 1

2

ループの順序についてはあまり心配しません。ifort -O3 最適化は、積極的なループ オプティマイザーです。3 次元配列を並べ替えても、ほとんどまたはまったく影響がない可能性があります。

あなたが考える限り、(k、i、j) が最良の順序です。一般的には、これが最適です。しかし、k には 2 つの要素しかなく、i には 1024 の要素があります。単精度実数 (4 バイト) を使用していると仮定すると、3D 配列のこの 2D セグメントは 8K RAM に収まります。ループが開始されると、データは完全に CPU キャッシュ上にある可能性が高いため、インデックスの順序は関係ありません。考慮している効果を有効にするには、はるかに大きなデータ次元が必要です。

パフォーマンスの違いに関する限り、それはおそらくコンパイラの最適化の苦労です。

于 2019-03-06T20:35:08.153 に答える