为啥我无法通过使其对缓存友好来加速我的程序?
Posted
技术标签:
【中文标题】为啥我无法通过使其对缓存友好来加速我的程序?【英文标题】:Why did I failed to speed up my program by making it cache-friendly?为什么我无法通过使其对缓存友好来加速我的程序? 【发布时间】:2016-04-19 06:16:28 【问题描述】:我使用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
性能差异是稳定的,这可能证明了优化。但是,当我将它改编为我的实际项目时,我失败了。
再次感谢您,我是堆栈溢出的新手,感谢您的帮助
【问题讨论】:
很难说没有看到任何代码。最好是创建一个最小的工作示例...... 谢谢你。我刚刚完成了那个最小的工作示例(类似的循环结构,相同的编译选项)。事实证明,性能应该一直都有提升,而我的程序却没有。 这不是一个最小的例子,一个最小的例子必须是complete和verifiable。 ***.com/help/mcve 谢谢,我更新了我的问题。我应该提供更多细节吗? 我不明白你的问题,结果完全符合预期。k,j,i
订单应该更快。顺便说一句,a(i,j)
怎么会变成>= 111
?答案怎么可能不是 0?我认为这只是因为您没有在开头设置s=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
如您所见,提供最佳性能。
【讨论】:
我一直觉得这些行和列非常混乱。我实际上通过记住 Fortran 应该是“主要列”而不是相反来记住哪个索引应该是行和列。但是,我也确实相信这些列是连续的,你为什么说它们不是? 根据矩阵表示法,第一个索引是行,第二个索引是列。在此示例中,a(1,1)
和 a(2,1)
表示我放置的示例矩阵中的元素 a11
和 a21
。这两个元素在内存中是连续的,因为列(以矩阵表示法)是主要坐标。您可以颠倒推理并说您希望列在内存中是连续的,并且您使用另一种矩阵表示法,其中第一个索引是列,第二个索引是行。
我听不懂您的话,但仅通过查看您的矩阵图片及其下方的元素,我发现您的示例中的列是连续的...
顺便说一句,我们在 Les Houches 见过吗?
我遵循这个约定:en.wikipedia.org/wiki/Matrix_(mathematics)。行是矩阵中的一条水平线,由第一个索引表示,一列是垂直线,由第二个索引表示。列作为一个整体确实是连续的......术语仍然令人困惑。我想我们确实在那里见过:)以上是关于为啥我无法通过使其对缓存友好来加速我的程序?的主要内容,如果未能解决你的问题,请参考以下文章