C++ 内联速度与编译器优化

C++ 内联速度与编译器优化,c++,visual-studio,optimization,visual-studio-2008,inline,C++,Visual Studio,Optimization,Visual Studio 2008,Inline,我正在做一些关于内联函数的速度优势的实践研究。我没有带这本书,但我读的一篇文章表明,进行函数调用需要相当大的开销;当任何一个可执行文件的大小都可以忽略,或者可以保留时,为了提高速度,应该将函数声明为内联 我已经编写了下面的代码来测试这个理论,从我所知道的,将函数声明为内联函数对速度没有好处。在我的计算机上调用4294967295次时,这两个函数都会在196秒内执行 我的问题是,对于为什么会发生这种情况,你有什么想法?是现代编译器优化吗?是不是因为函数中缺少大型计算 如对此事有任何见解,将不胜感激

我正在做一些关于内联函数的速度优势的实践研究。我没有带这本书,但我读的一篇文章表明,进行函数调用需要相当大的开销;当任何一个可执行文件的大小都可以忽略,或者可以保留时,为了提高速度,应该将函数声明为内联

我已经编写了下面的代码来测试这个理论,从我所知道的,将函数声明为内联函数对速度没有好处。在我的计算机上调用4294967295次时,这两个函数都会在196秒内执行

我的问题是,对于为什么会发生这种情况,你有什么想法?是现代编译器优化吗?是不是因为函数中缺少大型计算

如对此事有任何见解,将不胜感激。提前感谢朋友们

#include < iostream >
#include < time.h >

// RESEARCH                                                   Jared Thomson 2010
////////////////////////////////////////////////////////////////////////////////
// Two functions that preform an identacle arbitrary floating point calculation
// one function is inline, the other is not.

double test(double a, double b, double c);
double inlineTest(double a, double b, double c);

double test(double a, double b, double c){
    a = (3.1415 / 1.2345) / 4 + 5;
    b = 9.999 / a + (a * a);
    c = a *=b;
    return c;
}

inline
double inlineTest(double a, double b, double c){
    a = (3.1415 / 1.2345) / 4 + 5;
    b = 9.999 / a + (a * a);
    c = a *=b;
    return c;
}

// ENTRY POINT                                                Jared Thomson 2010
////////////////////////////////////////////////////////////////////////////////
int main(){
    const unsigned int maxUINT = -1;
    clock_t start = clock();

    //============================ NON-INLINE TEST ===============================//
    for(unsigned int i = 0; i < maxUINT; ++i)
        test(1.1,2.2,3.3);

    clock_t end = clock();
    std::cout << maxUINT << " calls to non inline function took " 
              << (end - start)/CLOCKS_PER_SEC << " seconds.\n";

    start = clock();

    //============================ INLINE TEST ===================================//
    for(unsigned int i = 0; i < maxUINT; ++i)
        test(1.1,2.2,3.3);

    end = clock();
    std::cout << maxUINT << " calls to inline function took " 
              << (end - start)/CLOCKS_PER_SEC << " seconds.\n";

    getchar(); // Wait for input.
    return 0;
} // Main.
#包括
#包括
//研究贾里德·汤姆森2010
////////////////////////////////////////////////////////////////////////////////
//执行标识符任意浮点计算的两个函数
//一个函数是内联的,另一个不是。
双重测试(双重a、双重b、双重c);
双入口测试(双a、双b、双c);
双重测试(双重a、双重b、双重c){
a=(3.1415/1.2345)/4+5;
b=9.999/a+(a*a);
c=a*=b;
返回c;
}
内联
双入口测试(双a、双b、双c){
a=(3.1415/1.2345)/4+5;
b=9.999/a+(a*a);
c=a*=b;
返回c;
}
//入口点Jared Thomson 2010
////////////////////////////////////////////////////////////////////////////////
int main(){
常量无符号整数最大值=-1;
时钟启动=时钟();
//===========================================非在线测试===============================//
for(无符号整数i=0;istd::cout关键字
inline
基本上是无用的。它只是一个建议。编译器可以随意忽略它并拒绝内联这样的函数,也可以随意内联未声明
inline
关键字的函数

如果你真的对函数调用开销的测试感兴趣,你应该检查生成的程序集,以确保函数真的是(或不是)内联的。我对VC++不是很熟悉,但它可能有一种编译器特定的方法来强制或禁止函数内联(但是C++标准<代码>内联关键字将不是它)。 因此,我想对您调查的大背景的答案是:不要担心显式内联。现代编译器知道何时内联和何时不内联,并且通常会比非常有经验的程序员做出更好的决定。这就是为什么
内联
关键字经常被完全忽略的原因。您应该您不必担心显式强制或禁止函数内联,除非您有非常特殊的需要这样做(分析您的程序的执行情况并发现瓶颈可以通过强制编译器出于某种原因没有执行的内联来解决)

回复:大会:

; 30   :     const unsigned int maxUINT = -1;
; 31   :     clock_t start = clock();

    mov esi, DWORD PTR __imp__clock
    push    edi
    call    esi
    mov edi, eax

; 32   :     
; 33   :     //============================ NON-INLINE TEST ===============================//
; 34   :     for(unsigned int i = 0; i < maxUINT; ++i)
; 35   :         blank(1.1,2.2,3.3);
; 36   :     
; 37   :     clock_t end = clock();

    call    esi
;30:const unsigned int maxUINT=-1;
;31:clock_t start=clock();
mov esi,DWORD PTR输入时钟
推式电子数据交换
打电话给esi
电子数据交换
; 32   :     
;33://===========================================非在线测试===============================//
;34:for(无符号整数i=0;i
该大会是:

  • 读钟
  • 存储时钟值
  • 再看一次钟
  • 注意缺少的是:调用函数很多次

    编译器注意到您对函数的结果不做任何处理,并且函数没有副作用,因此根本不会调用它


    通过关闭优化(在调试模式下)进行编译,您很可能会让它调用函数。

    这两个函数都可以内联。非内联函数的定义与使用点位于同一个编译单元中,因此编译器有权内联它,即使您没有要求也可以

    组装后,我们可以为您确认

    编辑:用于禁止内联的MSVC编译器pragma是:

    #pragma auto_inline(off)
        void myFunction() { 
            // ...
        }
    #pragma auto_inline(on)
    

    可能会发生两件事:

  • 编译器可能同时内联这两个函数,也可能两个函数都没有内联。请查看编译器文档,了解如何控制这一点

  • 您的函数可能非常复杂,以至于执行函数调用的开销不足以在测试中产生很大的差异

  • 内联对于非常小的函数很好,但并不总是更好。代码膨胀会阻止CPU缓存代码

    一般来说,内联getter/setter函数和其他一行程序。然后,在性能调优期间,如果您认为内联函数会得到提升,您可以尝试内联函数。

    嗯,不应该

    //============================ INLINE TEST ===================================//
        for(unsigned int i = 0; i < maxUINT; ++i)
            test(1.1,2.2,3.3);
    
    //=======================================================在线测试===================================//
    for(无符号整数i=0;i

    //=======================================================在线测试===================================//
    for(无符号整数i=0;i
    ?


    但是如果这只是一个输入错误,那么建议您查看一个disassembler或reflector,看看代码是否实际是内联的或仍然是堆栈的。

    如果此测试每个循环花费196秒,那么您一定没有打开优化;关闭优化后,编译器通常不会内联任何内容

    然而,随着优化的进行,编译器可以自由地注意到
    //============================ INLINE TEST ===================================//
        for(unsigned int i = 0; i < maxUINT; ++i)
             inlineTest(1.1,2.2,3.3);
    
    #define RADTODEG(x) ((x) * 57.29578)