为什么Blocking技术减少了分支指令?

时间:2013-10-14 14:49:43

标签: c++ performance

我描述了阻塞矩阵乘法随着块大小的增加,分支指令的数量减少了。  如在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(图表按比例缩放,可能所有组看起来都相同,但值为真)

enter image description here

问题:

1-为什么循环重新排序或阻止可以减少或增加分支指令的数量?

感谢

2 个答案:

答案 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

您应该查看编译器的汇编输出。