fortran循环索引问题以优化代码

时间:2019-03-06 08:18:37

标签: matrix optimization indexing fortran column-major-order

首先我的英语不好。对不起。

据我所知。 Fortran地址是专栏主要的。 我的旧Fortran代码没有长期优化。 我尝试更改Fortran90代码索引以提高速度。

代码几乎是3维矩阵。 (i,j,k) 几乎“ Do循环”是关于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) 我认为(k,i,j)是fortran(专业列)中的最佳选择。

但结果不是。

所有3种情况[(i,j,k),(k,i,j),(i,k,j)]几乎都花时间。 (1961年代,1955年代,1692年代)。

我的程序代码很长,迭代足以比较(32000)

下面是我的编译选项。

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

我不明白上面的结果。 请帮助我。

感谢阅读。

另外,下面是我的程序之一。 矩阵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

1 个答案:

答案 0 :(得分:2)

我不必担心循环顺序。 ifort -O3优化是一个积极的循环优化器。重新排列3-D阵列的影响很小甚至没有影响。

就您而言,(k,i,j)是最好的顺序。一般来说,这是最好的。但是k只有2个元素,而我有1024个。假设您使用的是单精度实数(4个字节),则3-D数组的此2-D段适合8K ram。一旦循环开始,您的数据可能就完全位于CPU缓存中,因此索引排序将是无关紧要的。您需要大得多的数据维度,才能使效果生效。

就您的性能差异而言,这可能是编译器优化遇到的困难。