如何强制gcc内联函数?

77

__attribute__((always_inline))是否可以强制gcc内联函数?


41
GCC使用代码大小作为启发式方法来确定是否进行内联。我有一个网络/序列化库,由于代码大小的原因,默认情况下不会内联函数。我进行了内联,并且在基准测试中提高了30%的性能。内联的一个原因是,如果您在编译时知道值(常量被传递),并且想要展开函数。例如,如果一个函数在两个不同的地方使用具有不同静态参数,则内联可以减少分支。这是针对在内部循环中使用的函数。 - HaltingState
1
另一个例子是:我进行音频DSP编码。有时候我无法使用调试器,因为非内联函数调用(来自许多访问器函数和其他东西)变得如此昂贵,以至于代码无法快速服务缓冲区。 - DCBillen
2
只是提醒一下...你需要同时指定inline__attribute__((always_inline))。我刚在带有GCC的Android NDK r10d上测试了一下。也许不是标准环境,但从我所读到的来看,这个要求对所有平台都是相同的。 - rwong
3
另一个例子(非基于优化):在为微控制器编写一个函数以在运行时写入其内部闪存时,我需要在开始写入之前将实际写入操作的程序复制到RAM中,因为不允许同时进行读写。如果该程序调用任何未内联的函数,那么我必须将所有依赖项复制到RAM中,并动态调整任何跳转地址,这比强制内联解决方案更加复杂。 - Ponkadoodle
1
强制内联提供了类似于C++中非类型模板参数的部分功能:当您知道您想要为每个参数值编译一个新函数时。您可以尝试使用宏来获得此功能,但是强制内联通常更清晰(虽然不太可移植)。 - BeeOnRope
显示剩余2条评论
8个回答

55

是的。

always_inline

通常情况下,只有在指定了优化选项时才会内联函数。对于声明为内联的函数,即使没有指定优化级别,此属性也会将其内联。


41

应该需要。我非常推崇手动内联。当然,过度使用会造成问题。但通常情况下,在优化代码时,会发现有一两个函数必须内联,否则性能会急剧下降。而且,据我的经验,当使用内联关键字时,C编译器通常不会自动将这些函数内联。

我完全愿意让编译器为我大部分的代码进行内联。只有在那半打或者更少的绝对至关重要的情况下,我才非常在意。人们认为“编译器在这方面做得很好。”请拿出证据来证明。到目前为止,我从未见过一个C编译器在没有使用某种强制内联语法(msvc上的__forceinline,gcc上的__attribute__((always_inline)))的情况下自动内联我告诉它的至关重要的代码片段。


7
谢谢您对 msvc 和 gcc 的比较! - Zak
13
我同意,但是我更强烈地使用内联方式。我在数千个函数上使用 __forceinline,并节省了一个由600台服务器组成的农场的20%。假设编译器会就内联做出最佳决策是不正确的。编译器只是在猜测,无论是有根据的猜测还是没有根据的猜测。编译器不知道你是否编写了该函数以优化使用常量参数形成的表达式等等。 - johnnycrash
5
使用gcc编译器时,你还需要显式地指定 inline 关键字:__attribute__((always_inline)) inline YourFunc(... 否则会出现警告信息:warning: always_inline function might not be inlinable [-Wattributes] - slashmais

23

是的,它会生效。这并不意味着这是一个好主意。


内联函数并不总是能提高性能(例如,缓存问题)。 - Basile Starynkevitch
13
有时我使用它的一个非常好的原因是:在开发音频DSP应用程序时,有时调试版本无法快速处理以跟上采样率。通过强制使用像访问器函数这样的内联函数,我能够进行测试和调试。 - DCBillen
7
更正:这并不一定意味着这是一个好主意。有时候是好的。 - No-Bugs Hare

13

根据GCC优化选项文档,你可以使用参数调整内联。

-finline-limit=n
By default, GCC limits the size of functions that can be inlined. This flag 
allows coarse control of this limit. n is the size of functions that can be 
inlined in number of  pseudo instructions.

Inlining is actually controlled by a number of parameters, which may be specified
individually by using --param name=value. The -finline-limit=n option sets some 
of these parameters as follows:

    max-inline-insns-single is set to n/2. 
    max-inline-insns-auto is set to n/2.

我建议更详细地阅读有关内联的所有参数,并适当设置它们。


6
我想在这里补充一点,我有一个SIMD数学库,其中内联对性能至关重要。最初我将所有函数设置为内联,但反汇编显示,即使对于最简单的运算符,它也会决定实际调用函数。无论是MSVC还是Clang,都显示了这一点,而且所有优化标志都开启了。
我按照SO中其他帖子中建议的做法添加了__forceinline(对于MSVC)和__attribute__((always_inline))(对于所有其他编译器)。在各种紧密循环中,从基本乘法到正弦等操作,性能均有25-35%的显著提升。
我没有弄清楚为什么他们很难内联(也许模板代码更难?),但底线是:手动内联有非常有效的用例,并且可以获得巨大的加速效果。
如果您感兴趣,这是我实现它的地方。https://github.com/redorav/hlslpp

2
模板函数代码往往不会被内联,而是每个特化都进入单独的.text部分,以便实现“模糊链接”(请参见https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Vague-Linkage.html)。通过强制内联,您基本上失去了在不同编译单元中显式特化模板函数的能力。 - Géza Török
我明白了,感谢@GézaTörök的解释,这解释了这个行为。大多数数学类都很难在没有模板的情况下编写(更不用说性能提升了),因此明确强制内联似乎经常是必须的。 - RedOrav

5

是的,它将内联函数,而不考虑任何其他设置选项。请参见这里


1

你也可以使用__always_inline。我一直在使用这个函数来编写GCC 4.8.1的C++成员函数。但是在GCC文档中没有找到一个好的解释。


-4
实际上答案是“不”。这只意味着即使禁用了优化,该函数仍然有可能被内联。

6
最高的答案有一句话是直接引用并明确说明了“这个属性内联该函数”。我没有看到任何关于“候选人”的参考。你的信息来源是什么? - underscore_d
4
对于 inline 关键字而言,这是正确的;但对于 always_inline 属性而言,则不然。请参考此处 - Bilow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接