V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xwu
V2EX  ›  C++

为何使用 inline 函数并不能达到真正 inline 写代码的性能?

  •  
  •   xwu · 69 天前 · 2612 次点击
    这是一个创建于 69 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 inline 关键字定义函数

    #include <chrono>
    #include <iostream>
    
    using namespace std;
    using namespace chrono;
    
    inline int minus_ab(int a, int b) {
        return a - b;
    }
    
    inline int add_ab(int a, int b) {
        return a + b;
    }
    
    inline int multi_ab(int a, int b) {
        return a * b;
    }
    
    
    int main(int argc, char** argv){
        auto tick = high_resolution_clock::now();
        int x;
        int max_kRound = atoi(argv[1]);
        int a=1, b=2;
        for (int i=0; i<max_kRound*1000; i++) {
            x = add_ab(a, b);
            x = minus_ab(a, b);
            x = multi_ab(a, b);
        }
        auto tock = high_resolution_clock::now();
        auto duration = duration_cast<microseconds>(tock - tick);
        cout << "max round= " << max_kRound << "k" << endl;
        cout << duration.count() / 1000 << " ms" << endl;
    }
    

    真正 inline 的写代码

    ...
        for (int i=0; i<max_kRound*1000; i++) {
            x = a+b;
            x = a-b;
            x = a*b;
        }
    ... 
    

    上面两个程序我分别设置循环数为 1e9 ,结果第一个程序大概是第二个的三倍时间。我理解的 inline 是在编译阶段把函数中的代码拷贝到函数调用出,所以两个代码应该是等价的,为什么性能上有差别?

    另外我还尝试去掉 inline 结果速度比用 inline 还快。是我对 inline 的理解不对吗?

    第 1 条附言  ·  69 天前
    感谢各位大佬的答疑解惑,总结一下是因为我编译的时候没有加 `-O` 来选择所需的 Optimization Level ,所以 inline 并没有起作用。另外就是 inline 的主要使用场景已经不再是插代码,而是处理多个同名函数。
    另外,这里附上我查到的对 `-O` flag 的解释。

    >
    option optimization level execution time code size memory usage compile time
    -O0 optimization for compilation time (default) + + - -
    -O1 or -O optimization for code size and execution time - - + +
    -O2 optimization more for code size and execution time -- + ++
    -O3 optimization more for code size and execution time --- + +++
    -Os optimization for code size -- ++
    -Ofast O3 with fast none accurate math calculations --- + +++
    16 条回复    2022-11-27 18:09:34 +08:00
    yianing
        1
    yianing  
       69 天前 via Android   ❤️ 1
    inline 大多还是用作多次定义用的,但是有 static 一般也不用 inline ,内联这个语意要看编译器,https://en.cppreference.com/w/cpp/language/inline
    wudicgi
        2
    wudicgi  
       69 天前   ❤️ 1
    先看看汇编,是否真的把代码内联进去了。或者是汇编代码有什么其他差异

    inline 修饰符本身不是强制的, MSVC 有 __forceinline, gcc 有 __attribute__((always_inline)) 修饰符强制内联
    AlohaV2
        3
    AlohaV2  
       69 天前
    加-O3 再试试
    ivan_wl
        4
    ivan_wl  
       69 天前
    你这个代码里对 x 一番操作,最后又没有使用 x ,这个 x 可能会被优化掉的吧
    disk
        5
    disk  
       69 天前
    inline 只是建议,你这段代码不好,不开优化不会展开,开了整个循环直接被优化掉
    codehz
        6
    codehz  
       69 天前
    inline 的语义早就改了,甚至和 inline 这个词本来的意思都不一样了,强制或者建议两个都不是,唯一的用途就是打破 ODR 可以多次定义,正因为如此,inline 也可以被用在变量上了
    Opportunity
        7
    Opportunity  
       69 天前
    都是巧合,你这代码开 o2 就把循环体全优化掉了,实际就是给 atoi 计时
    agagega
        8
    agagega  
       69 天前 via iPhone
    inline 更多的意义已经是改变编译器处理多个同名函数的方式了,具体有没有 inline ,效果变好没有,看汇编吧
    xtreme1
        9
    xtreme1  
       69 天前
    当前的主流编译器都会忽略 inline 作为指令(建议)生成内联函数这个原始含义了.
    真正的含义楼上都说完了
    msg7086
        10
    msg7086  
       69 天前 via Android
    1.你理解的当然不对。
    2.纠结优化前的代码性能没有什么意义,谁发布软件会发非优化版的。优化后全变成常数根本测不出性能差距来。

    你这些代码就算不会被优化掉,也会被优化成 simd 展开,到最后根本不会去执行加减乘除,都是跑 avx2 指令去了。
    minami
        11
    minami  
       69 天前
    inline 现在很大程度上取决于编译器怎么想,想要真正 inline ,还是用宏吧
    icyalala
        12
    icyalala  
       69 天前
    虽然但是。。
    像上面说的,开了优化就没区别了。想要了解编译器怎么想的,去看看 https://godbolt.org/z/ee3ahjsx9
    但你要想在没有优化时也 inline ,那就加个 __attribute__((always_inline))
    Tanix2
        13
    Tanix2  
       69 天前
    第一个 diff 窗口是加 inline 和不加 inline 的汇编对比,第二个对比窗口是加 inline 和删掉函数手动 inline 的对比,优化等级都是-O1 ,main 函数是完全一样的: https://godbolt.org/z/xfxa8x14M
    现代的编译器已经足够智能了,inline 的含义也发生了变化,一般的建议是只对可能出现在多个编译单元的函数用 inline ,比如定义在头文件中的函数。
    dynos01
        14
    dynos01  
       68 天前
    https://en.cppreference.com/w/cpp/language/inline

    Since this meaning of the keyword inline is non-binding, compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline. Those optimization choices do not change the rules regarding multiple definitions and shared statics listed above.

    编译器并不是见到 inline 就一定会内联一个函数。多数情况下,编译器比程序员更了解一个函数适合不适合 inline ,所以就不用操心这个问题了。
    Jooooooooo
        15
    Jooooooooo  
       68 天前
    因为你测性能的代码完全是错的.
    dazhangpan
        16
    dazhangpan  
       67 天前
    现在还有对底层性能优化感兴趣的人啊 XD
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   实用小工具   ·   3121 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 44ms · UTC 09:56 · PVG 17:56 · LAX 01:56 · JFK 04:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.