英特尔C ++编译器了解执行的优化

时间:2011-02-04 00:17:00

标签: c++ optimization compiler-construction intel

我有一个简单的代码段:

for( int i = 0; i < n; ++i)
{
  if( data[i] > c && data[i] < r )
  {
    --data[i];
  }
}

它是大型功能和项目的一部分。这实际上是对不同循环的重写,这被证明是耗时的(长循环),但我对两件事感到惊讶:

当data [i]临时存储时,这样:

for( int i = 0; i < n; ++i)
{
  const int tmp = data[i];
  if( tmp > c && tmp < r )
  {
    --data[i];
  }
}

变慢了。我没有声称这应该更快,但我不明白为什么它应该这么慢,编译器应该能够弄清楚是否应该使用tmp。

但更重要的是,当我将代码段移动到一个单独的函数时,它变得慢了四倍。我想了解发生了什么,所以我查看了opt报告,在这两种情况下,循环都是矢量化的,似乎也做了相同的优化。

所以我的问题是什么可以在一个不被称为百万次的函数上产生这样的差异,但它本身是耗时的?在opt报告中要查找什么?

我可以通过保持内联来避免它,但是为什么要烦我。

更新:

我应该强调的是,我的主要关注点是,当移动到一个单独的功能时,为什么它会变慢。使用tmp变量给出的代码示例只是我在此过程中遇到的一个奇怪示例。

3 个答案:

答案 0 :(得分:4)

你可能注册缺乏,编译器必须加载和存储。我很确定本机x86汇编指令可以使内存地址运行 - 即,编译器可以保持这些寄存器空闲。但是通过将其设置为本地,您可以 更改行为。别名和编译器可能无法证明更快的版本具有相同的语义,特别是如果这里有多种形式的多线程,允许它更改代码。

在新段中,函数可能因为函数调用不仅会破坏管道,而且还会导致指令缓存性能不佳(参数push / pop /等的额外代码)。

课程:让编译器进行优化,它比你聪明。我并不是说这是一种侮辱,它也比我更聪明。但实际上,尤其是英特尔编译器,这些人知道他们在定位自己的平台时正在做什么。

编辑:更重要的是,您需要认识到编译器的目标是优化未优化的代码。它们的目标不是识别半优化代码。具体来说,编译器将为每个优化设置一组触发器,如果​​您碰巧以未被命中的方式编写代码,则可以避免执行的优化,即使代码在语义上是相同的。

您还需要考虑实施成本。并非每个理想的内联函数都可以内联 - 只是因为内联逻辑过于复杂而无法让编译器处理。我知道VC ++很少会内联循环,即使内联产生了好处。您可能在英特尔编译器中看到这一点 - 编译器编写者只是认为不值得花时间实现。

我在处理VC ++中的循环时遇到过这种情况 - 编译器会以略微不同的格式为两个循环生成不同的程序集,即使它们都实现了相同的结果。当然,他们的标准库使用了理想的格式。您可能使用std::for_each和一个功能对象来观察加速。

答案 1 :(得分:1)

你是对的,编译器应该能够将其识别为未使用的代码并将其删除/不编译。这并不意味着它确实识别并删除它。

您最好的选择是查看生成的装配并检查确切的结果。请记住,仅仅因为聪明的编译器能够弄清楚如何进行优化,并不意味着它可以。

如果您确实检查并发现代码未被删除,您可能需要向intel编译器团队报告。听起来他们可能有一个错误。

答案 2 :(得分:-2)

我很惊讶这个

for( int i = 0; i < n; ++i)
{
  const int tmp = data[i]; //?? declaration inside a loop
  if( tmp > c && tmp < r )
  {
    --data[i];
  }
}

完全编译。可能会混淆编译器。尝试

for( int tmp, i = 0; i < n; ++i)
{
  tmp = data[i];
  if( tmp > c && tmp < r )
  {
    --data[i];
  }
}

代替。通常使用size_t(uint)来循环。 Signed int与unsigned的编码不同,因此可能存在不必要的bitshift。所以我试试

int tmp; // well if you must have your temporary, I don't see why you want it,
         // it costs you 1 register although that should not matter much here.
for( size_t i = 0; i < n; ++i)
{
  tmp = data[i];
  if( tmp > c && tmp < r )
  {
    --data[i];
  }
}

发布结果。