链接时优化和内联

根据我的经验,有许多代码明确使用内联函数,这需要权衡:

  1. 代码变得不那么简洁,而且可维护性稍差。
  2. 有时,内联可以大大提高运行时性能。
  3. 内联是在一个固定的时间点决定的,可能没有对其用途的非常好的预知,或者没有考虑所有(未来)周围环境。

问题是:链接时优化(例如,在GCC中)是否呈现手动内联,例如,在C99中声明一个“内联”函数并提供一个实现,已经过时了? 我们是否真的不需要考虑自己内联大多数function? 那些能从内联中受益的函数呢,例如deg_to_rad(x)?

澄清:我不是在考虑同一个翻译单元中的函数,而是考虑逻辑上应该存在于不同翻译单元中的函数。

更新:我经常看到反对“内联”,并建议过时。 然而,就个人而言,我确实经常看到明确的内联函数:作为类体中定义的函数。

即使使用LTO,编译器仍然必须使用启发式方法来确定是否为每个调用内联函数(注意它不是根据函数决定,而是每次调用)。 启发式考虑了诸如 – 它是循环,循环展开,函数有多大,全局调用的频率等因素。编译器肯定永远无法准确地确定代码被调用的频率,以及代码扩展是否可能在编译时烧掉特定CPU的指令/跟踪/循环/微代码高速缓存。

配置文件引导优化应该是解决这个问题的一个步骤,但是如果你曾经尝试过它,你很可能已经注意到你可以获得0-2%的性能摆动,它可以在无论方向! :-)这仍然是一项正在进行中的工作。

如果性能是你的最终目标,并且你真的知道自己在做什么,并且真正对你的代码进行彻底的分析,那么真正需要的是一种告诉编译器内联或不内联每个调用的方法, 而不是每个function提示。 在实践中,我通过使用编译器特定的“force_no_inline”类型提示来管理这个我不想内联的情况,以及一个单独的“force_inline”副本(或在极少数情况下这个失败的宏)我希望它内联的函数。 如果有人知道如何以更清晰的方式使用编译器特定的提示(对于任何C / C ++编译器),请告诉我。

要专门解决您的观点:

1.代码变得不那么简洁,而且可维护性稍差。

通常,不 – 它只是一个控制内联方式的关键字提示。 但是,如果你像我在上一段中描述的那样跳过篮球,那么是的。

2.有时,内联可以大大提高运行时性能。

将编译器留给自己的设备时 – 是的,它肯定可以,但大多数情况下都没有。 编译器具有良好的启发式,虽然不总是最佳的内联决策,但仍然很好。 特别是对于关键字,编译器可能完全忽略关键字,或者使用关键字作为弱提示 – 通常它们看起来不利于内联代码,这些代码会标记其启发式(例如将16k函数内联到展开的循环16x中)。

3.内联是在一个固定的时间点决定的,可能没有对其用途的非常好的预知,或者没有考虑所有(未来)周围环境。

是的,它使用静态分析。 动态分析可以来自您的洞察力, 可以手动控制每个呼叫的内联,或理论上来自PGO(仍然很糟糕)。

问题是:链接时优化(例如,在GCC中)是否呈现手动内联,例如,在C99中声明一个“内联”函数并提供一个实现,已经过时了?

本文似乎回答“是”:

想一想:什么把function变成了内联的好选择? 除了大小因素之外,优化器还需要知道调用此函数的频率,调用它的位置,程序中有多少其他函数是内联的可行候选者 – 不管信不信 – 函数是否曾经调用。 优化(即内联)甚至一次不调用的函数是浪费时间和资源。 但是优化器怎么知道函数永远不会被调用? 好吧,它不能。 除非它扫描了整个程序。 这就是[链接时优化]变得至关重要的地方。

如果链接时间优化与编译时优化一样快,那么它将消除对编译器提示的需要。 不幸的是,它通常不比编译时优化快,因此它是整体构建速度与该构建的整体优化质量之间的权衡。

此外,在标题中定义函数时仍需要使用内联。 否则,如果在多个转换单元中使用这些函数的多个定义,则会出现链接器错误。

  1. 我不认为内联关键字会影响可维护性,只是简单的简洁。 (意见)
  2. 有时内联可以降低运行时性能: http : //www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3
  3. 编译器对于内联非常聪明,我听说Visual Studio几乎完全忽略它们并决定内联。

does link-time optimization render manual inlining, obsolete? 完全没有,在链接时间之前使内联关键字过时的优化器开始了。

第33项 – 斯科特迈尔斯 – 第2版 – 有效的C ++让人想起。

你必须记住关键字static wrt inline! 现在有一个黄蜂窝!