【问题标题】:How do I force gcc to inline a function?如何强制 gcc 内联函数?
【发布时间】:2012-01-12 22:56:42
【问题描述】:

__attribute__((always_inline)) 是否强制一个函数被 gcc 内联?

【问题讨论】:

  • GCC 使用代码大小作为启发式来确定是否内联。我有一个网络/序列化库,由于代码大小,默认情况下它不会内联函数。我做了内联,它在基准测试中提高了 30% 的性能。内联的一个原因是,如果您在编译时知道值(传入常量)并且想要展平函数。例如,如果一个函数在两个不同的地方使用不同的静态参数,内联可以减少分支。这是用于内部循环中的函数。
  • 另一个例子原因:我做音频 DSP 编码。有时我不能使用调试器,因为非内联函数调用(来自许多访问器函数和东西)变得非常昂贵,代码无法足够快地为缓冲区提供服务。
  • 提醒一下……您需要同时指定inline__attribute__((always_inline))。我刚刚在带有 GCC 的 Android NDK r10d 上对此进行了测试。也许不是标准环境,但据我所知,这个要求对于所有平台都是相同的。
  • 另一个例子(不是基于优化的):在为微控制器编写函数以在运行时写入其内部闪存时,我需要复制执行实际从闪存写入内存的例程在开始写入之前,因为不允许同时读取和写入。如果这个例程调用任何非内联函数,那么我必须将所有依赖项复制到 ram 并动态调整任何跳转地址,这比强制内联解决方案复杂得多。
  • 强制内联提供了类似于 C++ 中至少部分非类型模板参数的功能:当您知道要为参数的每个值编译一个新函数时。您可以尝试使用宏来获得此功能,但强制内联通常更简洁(尽管可移植性较差)。

标签: gcc inline compiler-flags


【解决方案1】:

是的。

always_inline

通常,除非指定优化,否则函数不会内联。对于声明为内联的函数,即使未指定优化级别,此属性也会内联函数。

【讨论】:

    【解决方案2】:

    应该的。我是手动内联的忠实粉丝。当然,过量使用它是一件坏事。但通常在优化代码时,会有一两个函数需要内联,否则性能会下降。坦率地说,根据我的经验,C 编译器在使用 inline 关键字时通常内联这些函数。

    我非常愿意让编译器为我内联我的大部分代码。我真正关心的只是那六个左右绝对重要的病例。人们说“编译器在这方面做得很好”。我想看看这方面的证据,拜托。到目前为止,我从未见过 C 编译器在不使用某种强制内联语法的情况下内联我告诉它的一段重要代码(__forceinline on msvc __attribute__((always_inline)) on gcc)。

    【讨论】:

    • 我很欣赏 msvc 与 gcc 的比较!
    • 我同意,但我强制内联的方式比它更多。我在数千个函数上使用 __forceinline 并节省了 600 个服务器场的 20%。假设编译器将做出最佳决定 WRT 内联是不正确的。编译器在猜测。有根据的猜测与否,这仍然是一个猜测。编译器不知道您编写的函数是为了优化由常量参数形成的表达式。等等等等等等。
    • 使用 gcc 你还需要明确指定inline__attribute__((always_inline)) inline YourFunc(... 否则你会得到warning: always_inline function might not be inlinable [-Wattributes]
    【解决方案3】:

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

    【讨论】:

    • 内联函数并不总能提高性能(例如缓存问题)。
    • 我有时使用它的一个很好的理由示例:在开发音频 DSP 应用程序时,有时调试构建的处理速度不足以跟上采样率。通过强制诸如访问器函数之类的东西内联,我能够测试和调试。
    • 更正:这并不一定意味着这是一个好主意。有时确实如此。
    【解决方案4】:

    根据gcc optimize options 文档,您可以使用参数调整内联:

    -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.
    

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

    【讨论】:

      【解决方案5】:

      是的。无论设置任何其他选项,它都会内联该函数。见here

      【讨论】:

        【解决方案6】:

        我想在这里补充一点,我有一个 SIMD 数学库,其中内联对性能来说绝对是至关重要的。最初我将所有函数都设置为内联,但反汇编表明,即使对于最琐碎的运算符,它也会决定实际调用该函数。 MSVC 和 Clang 都显示了这一点,所有优化标志都打开了。

        我按照 SO 中其他帖子中的建议进行操作,并为 MSVC 添加了__forceinline,为所有其他编译器添加了__attribute__((always_inline))。在从基本乘法到正弦运算的各种紧密循环中,性能始终有 25-35% 的提升。

        我不明白为什么他们很难进行内联(也许模板代码更难?),但底线是:手动内联有非常有效的用例,并且可以获得巨大的加速。

        如果您好奇,这就是我实现它的地方。 https://github.com/redorav/hlslpp

        【讨论】:

        • 模板函数代码往往不会被内联,而是每个特化都进入一个单独的.text 部分,以使“模糊链接”成为可能(参见gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Vague-Linkage.html)。通过强制内联,您基本上失去了在不同编译单元中显式专门化模板函数的能力。
        • 我明白了,感谢@GézaTörök 的解释,它解释了这种行为。大多数数学课在没有模板的情况下很难编写(更不用说性能增益了),所以似乎明确强制内联通常是必须的。
        【解决方案7】:

        也可以使用__always_inline。我一直将它用于 GCC 4.8.1 的 C++ 成员函数。但在 GCC 文档中找不到很好的解释。

        【讨论】:

          【解决方案8】:

          其实答案是“不”。这意味着即使禁用了优化,该函数也是内联的候选者。

          【讨论】:

          • 但最重要的答案有一个直接引用,专门说“这个属性内联函数”。我根本看不到那里提到任何“候选人”。你的来源是什么?
          • 这适用于inline 关键字,不适用于always_inline 属性,请参阅here
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-20
          • 2013-06-04
          • 1970-01-01
          • 1970-01-01
          • 2010-12-01
          • 2020-02-17
          • 2011-03-20
          相关资源
          最近更新 更多