编译器内联调用什么
what calls does the compiler inline?
你怎么知道什么会或什么不会被编译器内联?
有时我被告知一些小的优化是没有意义的,因为编译器会内联某些调用或计算,其他时候类似的优化似乎被推荐。
是什么规则让我们知道什么时候我们需要或不需要优化这些东西?
查看程序集是否内联是唯一可靠的方法。
是否内联完全依赖于编译器——因为编译器对是否内联有最终决定。
不考虑过早的优化:如果它真的很重要(或者如果你只是好奇),你可以使用特定于编译器的pragmas来强制函数内联/不内联,然后适当地配置文件,看看你是否能做出比编译器更好的决定。
然而,在某些情况下,你可以确定一个函数不能内联:
- 在编译时不能确定类型的虚调用函数。
- 递归函数永远不能完全内联,除非最大深度可以静态确定。
这可能看起来有点离题,但我认为这很重要。
是什么规则让我们知道什么时候我们需要或不需要优化这些东西?
我想说,在回答这个问题之前,有两条规则可以发挥作用:
-
这可能无关紧要。除非您在发布版本中对代码进行了概要分析,并证明与函数调用相关的开销是代码中的主要瓶颈,否则您最好忘记
inline
代码的性能含义。 -
你很少或根本无法控制编译器将内联或不内联什么。如果编译器认为合适的话,可以忽略
inline
。有些东西不可能内联。有些平台提供了类似force_inline
的语言扩展,但即使是这些也可以忽略不计。
没有固定的规则。甚至还有一些测试可以测试您关于优化的假设。
How can you tell what will or what won't be made inline by the compiler?
你不能:)例如,如果你使用内联关键字,它只是一个提示,编译器没有义务尊重它。然而,如果你需要疯狂的优化,似乎你可能需要在比c/c++更低的级别编码,并使用汇编调用
你已经看过了吗?
例如:GCC是否内联没有'inline'关键字?
为什么不把所有的东西都标记为内联呢?
你问的问题是非常普遍的——因为它取决于诸如哪个编译器之类的事情,更不用说哪个版本了。听起来你所做的是一种不成熟的优化——你应该分析你的代码,找出减慢速度的地方。这将使"这将被内联吗?"的问题变得没有意义,因为您将看到编译器,内联和其他优化的效果。
没有办法确定,关于内联为什么和何时是好的实践的细节,我建议阅读这个c++ FAQ
您无法知道编译器在优化阶段将内联什么:您应该记住精确编译器的启发式。不过,您可以指定想要内联的内容。
微软的编译器很长一段时间都有/Ob优化标志,强制它内联所有且仅显式声明inline
的函数。这是非标准的,默认情况下,它的行为符合标准,即将关键字仅作为提示。Intel Parallel Studio编译器的行为类似。
你怎么知道编译器会把什么变成内联的,什么不会呢?
一般情况下不能。
您可能需要阅读Herb Sutter的Inline Redux文章。它公开了许多技术来解释何时可能发生内联,知道后者会发生……你得到的信息就越多。
例如,在JIT环境中,你可以观察一个循环,意识到它的整个主体都是在一个对象上执行的,这个对象经常是Foo
类型的,将整个主体专门化为Foo
,这允许虚拟方法的完全内联,现在在循环的顶部检查对象是否是Foo
,如果是的话,切换到完全内联的主体版本,而不是具有虚拟调用的通用版本。
那么什么可以内联呢?
一般c++编译器的特性:
- 编译时间内联(历史)
- 链接时间内联(LTO优化包的一部分)
这意味着它们只能基于静态(在编译时已知)信息进行优化。
在编译时,这意味着如果静态类型是虚拟调用,则可能被去虚拟化(内联的第一步:猜测实际调用的函数;))。这意味着任何定义可见的函数都可以内联。
在库的链接时,你基本上公开了新的函数定义,允许内联一些调用。
在可执行文件的链接时,WPA(整个程序分析)可以通过意识到某些类永远不会派生,从而开始添加一些非虚拟化,因此就该可执行文件而言,可以将其视为final
。GCC和LLVM(我怀疑vc++可以)都不能执行这种优化,因为它们没有字节码来保持类层次结构。
如果编译器愿意,可以转储它们拥有的中间表示(某种程度上是字节码),并等待安装内联操作系统特定的调用。虽然我知道没有(c++)这样做。
运行时更改在c++中是相当棘手的,因为内存(例如函数地址)是程序员可以访问的,所以很难只进行安全的转换…
- 什么时候调用组成单元对象的析构函数
- 什么时候调用析构函数
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- boost odeint什么时候真正调用观测者
- unique_ptr:在分配之前调用 reset 有什么效果
- 是什么让放置新调用对象的构造函数?
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 什么是仅调用一次并调用参数的控制台应用
- 使用动态链接加载程序 <dlfcn.h> 而不是直接函数调用的目的是什么?
- 什么时候可以使用常量装饰调用我的重载函数?
- 如果结构中的字符串比使用的 p/调用签名长或短,会发生什么情况?
- 我正在尝试学习如何在 c++ 中传递指针,但出现错误:没有用于调用"test"的匹配函数。我做错了什么?
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- "noexcept-expression 由于对......的调用而计算为'假'"是什么意思?
- 运算符++();调用和++(*this)有什么区别?
- C++ 此函数调用之前的(void)有什么作用?
- C++:将向量传递给函数,然后在main中调用函数.错过了什么