我描述了阻塞矩阵乘法随着块大小的增加,分支指令的数量减少了。 如在Image1中,盒装组具有450万个分支指令,但在其他组中,它是大约1700万个分支指令,这是因为只有循环次序已经改变。据我所知,分支指令依赖于代码中或其机器代码中使用的任何分支指令(条件或无条件),但我无法弄清楚循环重新排序如何改变分支的数量。尽管循环重新排序阻塞技术也会影响分支指令的数量。
OS是linux x86_64 Ram 4G l1缓存32k 64Byte线路大小L2缓存2048k 64Byte线路大小4路关联。 papi_library的个人资料kij算法
For (k=0;k<n;k++)
For(i=0;i<n;i++){
r=A[i][k];
For (j=0;j<n;j++)
C[i][j]+=r*B[k][j]
}
ikj算法
For (i=0;i<n;i++)
For(k=0;k<n;k++){
r=A[i][k];
For (j=0;j<n;j++)
C[i][j]+=r*B[k][j]
}
我的阻止代码不在手边,而是使用1级阻止。
图像1(图表按比例缩放,可能所有组看起来都相同,但值为真)
问题:
1-为什么循环重新排序或阻止可以减少或增加分支指令的数量?
感谢
答案 0 :(得分:1)
循环重新排序是代码块重新排序优化之一,它改变了程序中基本块的顺序,以减少条件分支并改进locality of reference。
简单地描述分支缩减,假设您有这样的代码:
void foo(bool is_enabled) {
for (int i = 0; i < 10000; ++i) {
if (is_enabled) {
data[i].enable();
} else {
data[i].disable();
}
}
}
鉴于没有必要一直检查is_enabled
,编译器可能决定做的是:
void foo(bool is_enabled) {
if (is_enabled) {
for (int i = 0; i < 10000; ++i) {
data[i].enable();
}
} else {
for (int i = 0; i < 10000; ++i) {
data[i].disable();
}
}
}
...因此将分支数量减少9999(只检查一次is_enabled
而不是10000)。
在你的代码片段中,由于更加硬件友好的内存访问模式,这更像是一个参考优化的地方,可以很好地与内存预取器和CPU缓存一起使用。
答案 1 :(得分:0)
我不认为循环重新排序会影响为示例代码生成的分支指令的数量,因为它在循环内没有条件测试,并且所有循环都是相同的长度。
如果在编译时已知块大小,则每个块的编译器可能为unrolling the loop。
您应该查看编译器的汇编输出。