fortran Do循环索引问题以优化代码
fortran Do loop index issue for optimize code
首先我的英语不好。对不起。
据我所知。 Fortran 地址是主要的列。
我的旧 Fortran 代码很长时间没有优化。
我尝试更改我的 Fortran90 代码索引以获得更快的速度。
一个代码几乎就是3维矩阵。 (我, 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)
我认为 (k, i, j) 是 fortran (column major) 中的最佳选择。
但结果不是。
所有 3 种情况 [ (i, j, k), (k, i, j), (i, k, j) ] 都花费了差不多的时间。
(1961 年代、1955 年代、1692 年代)。
我的程序代码这么长,Iteration足够比较(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
我不会太担心循环顺序。 ifort -O3 优化是一种积极的循环优化器。重新排序 3-D 阵列可能几乎没有影响。
就你认为 (k,i,j) 是最好的顺序。一般来说,这将是最好的。但是 k 只有 2 个元素,而 i 有 1024 个。假设您使用的是单精度实数(4 字节),您的 3-D 数组的这个 2-D 段适合 8K ram。一旦循环开始,您的数据很可能完全位于 CPU 缓存中,因此索引排序无关紧要。您需要更大的数据维度才能使您考虑的效果生效。
就您的性能差异而言,这可能是编译器优化的问题。
首先我的英语不好。对不起。
据我所知。 Fortran 地址是主要的列。 我的旧 Fortran 代码很长时间没有优化。 我尝试更改我的 Fortran90 代码索引以获得更快的速度。
一个代码几乎就是3维矩阵。 (我, 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) 我认为 (k, i, j) 是 fortran (column major) 中的最佳选择。
但结果不是。
所有 3 种情况 [ (i, j, k), (k, i, j), (i, k, j) ] 都花费了差不多的时间。 (1961 年代、1955 年代、1692 年代)。
我的程序代码这么长,Iteration足够比较(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
我不会太担心循环顺序。 ifort -O3 优化是一种积极的循环优化器。重新排序 3-D 阵列可能几乎没有影响。
就你认为 (k,i,j) 是最好的顺序。一般来说,这将是最好的。但是 k 只有 2 个元素,而 i 有 1024 个。假设您使用的是单精度实数(4 字节),您的 3-D 数组的这个 2-D 段适合 8K ram。一旦循环开始,您的数据很可能完全位于 CPU 缓存中,因此索引排序无关紧要。您需要更大的数据维度才能使您考虑的效果生效。
就您的性能差异而言,这可能是编译器优化的问题。