为什么我没有通过使其缓存友好来加速我的程序?

时间:2016-04-19 06:16:29

标签: caching parallel-processing fortran hpc

我使用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

性能差异稳定,可能证明优化。然而,当我将它改编为我的真实项目时,我失败了。

再次感谢您,我对堆栈溢出很新,感谢您的帮助

1 个答案:

答案 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
正如你所发现的那样,

给出了最好的表现。