C++ 如果只从一个位置调用函数,那么将其内联总是更好吗?

C++ 如果只从一个位置调用函数,那么将其内联总是更好吗?,c++,c,performance,optimization,micro-optimization,C++,C,Performance,Optimization,Micro Optimization,如果一个函数只在一个地方使用,并且一些分析显示它没有内联,那么强制编译器内联它是否总是有性能优势 显然是“profile and see”(在所讨论的函数中,它确实被证明是一个小的性能提升)。我的提问主要是出于好奇——一个相当智能的编译器在性能上有什么缺点吗?你不能“强制”编译器内联它,除非你考虑一些你没有提到的特定于实现的工具,所以这个问题完全没有意义 如果您的编译器已经不这样做了,那么这是有原因的。如果函数只调用一次,那么内联函数应该不会有性能上的缺点。但是,这并不意味着您应该盲目地内联所有

如果一个函数只在一个地方使用,并且一些分析显示它没有内联,那么强制编译器内联它是否总是有性能优势

显然是“profile and see”(在所讨论的函数中,它确实被证明是一个小的性能提升)。我的提问主要是出于好奇——一个相当智能的编译器在性能上有什么缺点吗?

你不能“强制”编译器内联它,除非你考虑一些你没有提到的特定于实现的工具,所以这个问题完全没有意义


如果您的编译器已经不这样做了,那么这是有原因的。

如果函数只调用一次,那么内联函数应该不会有性能上的缺点。但是,这并不意味着您应该盲目地内联所有函数。例如,如果所讨论的代码是Linux内核代码,并且您正在使用BUG_ON或WARN_ON语句打印堆栈跟踪,则无法获得包含内联函数的完整堆栈跟踪。相反,堆栈跟踪只包含调用函数的名称


而且,正如另一个答案所解释的,“内联”实际上并不强制编译器内联函数,它只是对编译器的一个提示。但是,GCC中实际上有一个属性
\uuuuuuu attribute((始终为内联))
,它应该强制编译器内联函数。

不,有明显的例外。以这段代码为例:

void do_something_often(void) {
    x++;
    if (x == 100000000) {
        do_a_lot_of_work();
    }
}

比如说,
经常做某事()
经常从很多地方被调用
do\u lot\u of \u work()
很少被调用(每一亿次调用中就有一次)。将
做大量的工作()
内联到
经常做某事()
不会给你带来任何好处。由于
do\u some\u frequency()
几乎什么都不做,因此如果将它内联到调用它的函数中会更好,而且在极少数情况下,他们需要调用
do\u lot\u work()
,他们会将它调用得太离谱。通过这种方式,他们几乎每次都保存一个函数调用,并在每个调用站点保存代码膨胀。

一个合理的情况是,不内联函数(即使只从单个位置调用)是有意义的,即对函数的调用很少且几乎总是被跳过。将函数调用前的指令和函数调用后的指令紧密地保存在内存中可能会允许将这些指令保存在处理器缓存中,而如果这些指令块在内存中分离,则这是不可能的


编译器仍然可以像使用
goto
一样编译函数调用,避免跟踪返回地址,但是如果编译器已经确定函数调用很少,然后,不必花那么多时间优化调用是有意义的。

确保函数定义没有导出。如果是,则显然需要对其进行编译,这意味着如果函数很大,则调用可能不会内联。(记住,内联的是调用,而不是函数。函数可能在一个地方内联,然后在另一个地方调用,等等)

因此,即使您知道函数只从一个地方调用,编译器也可能不会。确保将函数的定义隐藏到其他对象文件中,例如在匿名命名空间中定义函数


也就是说,即使只从一个地方调用它,也并不意味着将其内联始终是一个好主意。如果很少调用函数,则可能会在CPU缓存中浪费大量内存。

这取决于编写函数的方式

在某些情况下,是的

void doSomething(int *src,                 int *dst, 
                 const int loopCountInner, const int loopCountOuter)
{
     int i, j;
     for(i=0; i<loopCounterOuter; i++){
         for(j=0; j<loopCounterInner; j++){
             *dst = someCalculations(*src);
             src++; 
             dst++
         }
     }
}
void doSomething(int*src,int*dst,
常量int loopCountInner,常量int loopCountOuter)
{
int i,j;

对于(i=0;iNo),如果代码是一个很少使用的函数,那么将其远离“热路径”将是有益的。无论代码是否实际使用,内联函数都将使用缓存空间[instruction cache]。LTCG等工具与配置文件引导优化相结合(在MSFT世界中,不确定Linux)尽最大努力使很少使用的代码远离热路径,这可能会产生显著的差异

这取决于调用的频率。如果调用方总是调用它,则内联更有可能起到帮助作用。如果函数很大,而且是很少调用的陷阱函数,则内联可能不是一个好主意。您可以“鼓励”编译器将其内联,它通常会侦听。大多数编译器都有强制内联说明符,除非它是不可能的(递归、虚拟等),否则强制内联。@ MyStudi:好的,但我试图指出,这是作为C++(和C)的问题提出的。语言。这不是你所说的。<代码>如果函数只被调用一次,在内嵌它<代码>时不存在性能上的缺点。这不是完全正确的,你必须考虑它可能会浪费缓存内存。我不明白我的Calimimg和手册是什么区别。手册声称除非使用-O,否则“内联”函数是不内联的,我声称“内联”只是对编译器的一个提示。此外,手册声称即使不使用-O,属性也会内联函数,我还声称它会强制内联。对我来说,这些语句似乎是兼容的。@sbabbi以及它到底如何浪费缓存内存?如果只调用一次函数,代码中只有一个位置函数的代码被插入,这样缓存中就不会有重复的代码。当然,如果它是一个很少被调用的“slowpath”函数,那么缓存对齐可能不是在所有情况下都是最优的,但是你可以使用内置的expect或