我使用intel的ifort来编译我的程序
有很多嵌套循环,如下面的
do i=1,imax
do j=1,jmax
if (a(i,j).ne.1) cycle
.....
.....
.....
enddo
enddo
以及像
这样的循环do j=1,jmax
do i=1,imax
if (a(i,j).ne.1) cycle
.....
.....
.....
enddo
enddo
我注意到Fortran按列主要顺序存储数组,因此我将j循环放在i循环之外。
让我感到困惑的是,表现似乎有所下降。
相比之下,我试图将i循环外部的j循环用于其他循环。但是仍有性能损失,但是很少
program p
integer ::i, j, k, s
real ::a(1000,1000)
do i=1,1000
do j=1,1000
call random_number(a(i,j))
enddo
enddo
do k=1,10000
do j=1,1000
do i=1,1000
if (a(i,j) .ge. 111) s = s+a(i,j)
enddo
enddo
enddo
print *,s
end
ifort -fPIC -no-prec-div -O3 -xCORE-AVX2 a.f90 -o a 时间./a 10921820
real 0m2.221s
user 0m2.221s
sys 0m0.001s
program p
integer ::i, j, k, s
real ::a(1000,1000)
do i=1,1000
do j=1,1000
call random_number(a(i,j))
enddo
enddo
do k=1,10000
do i=1,1000
do j=1,1000
if (a(i,j) .ge. 111) s = s+a(i,j)
enddo
enddo
enddo
print *,s
end
ifort -fPIC -no-prec-div -O3 -xCORE-AVX2 a.f90 -o a
time ./a
10923324
real 0m4.459s
user 0m4.457s
sys 0m0.003s
性能差异稳定,可能证明优化。然而,当我将它改编为我的真实项目时,我失败了。
再次感谢您,我对堆栈溢出很新,感谢您的帮助
答案 0 :(得分:1)
正如您所提到的,Fortran是专栏专业。这意味着该列是主索引,并且矩阵的所有列在内存中一个接一个地存储。可能你假设,列主要意味着循环遍历列索引意味着遍历内存中连续元素的矩阵,但事实并非如此。矩阵
| a11, a12, a13 |
| a21, a22, a23 |
| a31, a32, a33 |
以列主要顺序存储为
a11, a21, a31, a12, a22, a32, a13, a23, a33
--column 1--- --column 2--- --column 3---
这意味着当你在Fortran中创建一个二维循环时,表示行索引的第一个索引应该始终是最里面的,以获得最佳性能,因为那样你按照我的内存顺序遍历矩阵上面写道。因此
do j=1,1000
do i=1,1000
if (a(i,j) .ge. 111) s = s + a(i,j)
enddo
enddo
正如你所发现的那样,给出了最好的表现。