关于C / C ++编译器优化我能想到什么?

时间:2013-03-23 08:27:01

标签: c++ visual-c++ compiler-optimization

我想知道当我将遗留代码,库代码或示例代码集成到我自己的代码库中时,如何通过重新散列源代码来避免浪费我的时间并冒着打字错误。

如果我举一个简单的例子,基于图像处理场景,你可能会看到我的意思。

我发现我正在整合这样的代码片段并不罕见:

for (unsigned int y = 0; y < uHeight; y++)
{
    for (unsigned int x = 0; x < uWidth; x++)
    {
        // do something with this pixel ....
        uPixel = pPixels[y * uStride + x];
    }
}

随着时间的推移,我已经习惯于做一些事情,比如从内循环中移除不必要的计算,并可能将后缀增量更改为前缀......

for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned int uRowOffset = y * uStride;
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = pPixels[uRowOffset + x];
    }
}

或者,我可以使用指针算法,按行...

for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned char *pRow = pPixels + (y * uStride);
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = pRow[x];
    }
}

...或按行和列...所以我最终得到类似的东西

unsigned char *pRow = pPixels;
for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned char *pPixel = pRow;
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = *pPixel++;
    }

    // next row
    pRow += uStride;
}

现在,当我从头开始编写时,我会习惯性地应用自己的“优化”,但我知道编译器也会执行以下操作:

  • 将代码从内部循环移动到外部循环
  • 将后缀增量更改为前缀
  • 很多其他我不知道的东西

请记住,每当我以这种方式处理一段正在运行,经过测试的代码时,我不仅花费了一些时间,而且还冒着我会引入手指麻烦或其他任何问题的风险(以上示例已简化)。我知道“过早优化”以及通过设计更好的算法等提高性能的其他方法。但对于上述情况,我正在创建构建块,将用于更大的流水线类型的应用程序,我可以' t预测非功能性需求可能是什么,所以我只希望代码在时间限制内合理快速和紧凑(我的意思是我花时间调整代码)。

所以,我的问题是:我在哪里可以找到“现代”编译器通常支持的编译器优化。我正在使用Visual Studio 2008和2012的混合体,但是有兴趣知道是否存在与备选方案的差异,例如英特尔的C / C ++编译器。任何人都可以提供一些见解和/或指出一个有用的网络链接,书籍或其他参考?

修改
只是为了澄清我的问题

  • 我上面展示的优化是简单的例子,而不是完整的列表。我知道(从性能的角度来看)进行那些特定的更改是没有意义的,因为编译器无论如何都会这样做。
  • 我专门寻找有关我正在使用的编译器提供的优化的信息。

3 个答案:

答案 0 :(得分:16)

我希望您作为示例包含的大多数优化都是浪费时间。一个好的优化编译器应该能够为你完成所有这些。

我可以通过实用建议提出三点建议:

  1. 在处理实际数据的实际应用程序的上下文中分析您的代码。如果你不能,想出一些你认为会与最终系统非常相似的综合测试。
  2. 只将通过性能分析证明的代码优化为瓶颈。
  3. 如果您确信某段代码需要优化,那么不要只假设从循环中分解不变表达式会提高性能。始终进行基准测试,可选择查看生成的装配体以获得进一步的洞察力。
  4. 以上建议适用于任何优化。但是,最后一点与低级优化特别相关。它们有点像黑色艺术,因为涉及很多相关的架构细节:memory hierarchy和带宽,instruction pipeliningbranch predictionSIMD指令的使用等。

    我认为最好依靠对目标架构有深入了解的编译器编写器,而不是试图超越它们。

    您不时会通过分析找到需要手动优化的东西。然而,这些情况相当罕见,这将使你能够在实际上有所作为的事情上花费大量的精力。

    与此同时,专注于编写正确且可维护的代码。

答案 1 :(得分:0)

  

我可以假设有关C / C ++编译器优化的内容吗?

尽可能想象,除了使用优化代码遇到功能或性能问题的情况,然后关闭优化和调试。

现代编译器有各种策略来优化您的代码,尤其是在您执行concurrent programming时,以及使用OMPBoostTBB等库时。

如果您 DO 关心您的代码在机器代码中的确切内容,那么反编译并观察程序集就更好了。

最重要的是你做手动优化,可能是减少不可预测的分支,这是编译器更难完成的事情。

如果您想查找有关优化的信息,那么就已经有了关于SO

的问题

在优化选项中,有关于每种优化的解释:

还有一些优化策略和技术

答案 2 :(得分:0)

我认为重新考虑问题的前提可能更有用,而不是直接回答。

为什么要执行这些优化?从你的问题来看,我认为应该更快地制定一个具体的计划。如果是这种情况,您需要从问题开始:如何使该程序更快?

这个问题有一个非常不同的答案。首先,您需要考虑Amdahl's law。这通常意味着优化程序的一个或两个重要部分才有意义。其他一切都无关紧要。您应该使用分析器来定位程序的这些部分。此时您可能会争辩说您已经知道应该使用分析器。但是,我认识的几乎所有程序员都不会对他们的代码进行分析,即使他们知道他们应该这样做。了解蔬菜和吃蔬菜不一样。 ;-)

找到热点后,解决方案可能会涉及:

  1. 改进算法,使代码工作量减少。
  2. 改进内存访问模式,提高缓存性能。
  3. 同样,您应该使用分析器来查看您的更改是否改善了运行时。

    有关详细信息,您可以使用Google code optimization和类似条款。

    如果你想变得非常认真,你还应该看看Agner Fog's optimization manualsComputer Architecture: A Quantitative Approach。确保获得最新版本。

    您可能还想阅读The Sad Tragedy of Micro-Optimization Theater