链接时间优化与。项目内联;每种方法的局限性

时间:2011-07-14 21:44:23

标签: c++ optimization compiler-optimization

通常人们在c ++上设计适当的软件架构时也需要有很好的性能,进入过早优化的危险游戏,而不是在架构层面进行优化(这是一种非常好的鼓励形式的过早优化)他们在代码级别做出妥协,比如完全避免虚拟方法和接口,低级别的黑客攻击等等。

有些人通过一种通常称为应用程序内联统一构建的做法来避免这种情况,这种做法基本上会生成一个或两个非常大的.cpp,包含所有头文件和.cpp从整个项目中包括,然后将其编译为单个翻译单元。在内联虚拟方法(虚拟化)时,这种方法非常可靠,因为编译器确实拥有进行所需优化的所有功能

问题这种方法对于更优雅和现代的方法(如链接时优化)有什么缺点?

4 个答案:

答案 0 :(得分:4)

该方法的技术名称接近次要流行语状态 unity build

参见例如:

The benefits / disadvantages of unity builds?

这里的缺点最好:

http://leewinder.co.uk/blog/?p=394

简短版本或多或少是语言选择:您可以使用常规C ++或Unified-build-C ++编写。实际编写任何代码的“正确”方式在两者之间会有所不同。

答案 1 :(得分:1)

  • 对于大型项目,将“所有文件合二为一”的技术可能会增加构建时间,尽管这只对开发人员有意义。对于多个较小的文件,一次代码更改通常会导致编译的代码更少,因此它应该是更快的增量构建。如果对头文件或许多文件所依赖的其他组件更频繁地进行更改,那么单个文件方法可以节省构建时间,因为更改后多个依赖项不需要处理头文件。
  • 有惊人数量的编译器无法处理非常大的源文件,即使是那些广泛使用并且受欢迎程度与其质量不成比例的编译器。这样的编译器往往会随机扼流,报告错误的语法正确代码,或生成错误的指令。
  • 具有多个开发人员和旧版本控制工具的项目可能无法协调对有限数量模块的更改。

答案 2 :(得分:1)

一个明显的缺点是静态或局部符号之间可能发生冲突:

// File a.cpp
namespace
{
    void f() { make_peace(); }
}

void action() { f(); }

// file b.cpp
void f() { launch_missiles(); }

void action2() { f(); }

如果在b.cpp之前包含a.cpp,则会发生不良事件。

另一个缺点是编译器(MSVC?)可能无法很好地处理大文件。

此外,每次更改代码的一小部分时,都需要进行完整编译。

总之,我永远不会这样做。对于SSD *或更强大的构建机器来说,这不值得花钱。并且链接时间代码生成通常足够好。

我看到的罕见好处是增强了虚拟功能分析和更好的别名分析,但我真的不认为这是值得的。您可以使用restrict或其变体作为后者,而前者很少会对您的程序性能产生实际影响。

*如果编译时间真的困扰您,请尝试在构建计算机上用SSD替换硬盘。魔法。

答案 3 :(得分:1)

考虑一下。您的程序中有一些部分,称之为A,没有任何优化需要时间T,但是通过优化需要T / 2.

现在你的程序还有其他部分,所以让我们考虑A的优化对整个程序的影响。

如果最初花在A上的时间是无(0%)那么A的优化效果是什么?零。

如果最初在A中花费的时间全部(100%)那么A的优化效果是什么? T / 2

如果最初花在A上的时间是一半(50%)那么A的优化效果是T / 4.

因此优化一段代码的好处与最初在该代码中花费的时间成正比。


因此,如果想要内联,避免使用虚函数等以获得显着的好处,那么它必须是什么样的代码?

它必须是代码,在优化之前,它包含程序计数器(独占时间)很长一段时间。


在重要的应用程序中,包含多层函数/方法调用,其中调用树几乎总是下降到new,或I / O,或字符串库,或数据结构库或数据库库,在应用程序的源代码之外,作为应用程序的一部分编译的代码中,总时间的百分比是独占时间?

经常(并非总是)从很少到很少。 内联或其他编译器/链接器优化的潜在好处与此成正比。