当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Linux编译优化必须掌握的几个姿势总结

    栏目:Linux/apache问题 时间:2019-10-11 13:15

    01、编译选项和内核编译

    Linux内核(英语:linux kernel),是一种计算机操作系统内核,已C语言和汇编语言写成,匹配POSIX标准,以GNU通用公共许可证发布。从技术上说Linux只是一个内核。“内核”指的是一个提供硬件抽象层、磁盘及文件控制、多任务等功能的系统软件。

    所以首先我们都知道,Linux内核如果用O0编译,是无法编译过的,Linux的内核编译,要么是O2,要么是Os,这点从Linux的Makefile里面可以看出:

    当选择了

    CONFIG_CC_OPTIMIZE_FOR_SIZE

    它会是Os,否则就是O2。

    其实O2和Os,都是一些优化选项的集合:

    gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
    
    gcc -c -Q -Os --help=optimizers > /tmp/Os-opts

    前者倾向于基于速度的优化,后者倾向于基于size更小的优化。对比二者的开关选项:

    meld /tmp/O2-opts /tmp/Os-opts 

    发现差异小的可怜:

    O2和Os都使能了inline small函数和called once的函数,但是O2里面-finline-functions是关闭的,而Os里面是开的。O2里面optimize-strlen是开的,Os里面这个选项是关闭的。相关选项的含义可以通过"man gcc"看出(有问题,找男人),譬如man gcc后检索inline-functions:

    从O0到O1,O2,O3,是一个开启的优化选项逐步加大的过程:

    kernel用O0编译不过,是因为kernel本身也没有想用O0能够编译过,它的设计里面包含了编译会优化的假想。下面我们用一个简单的例子来说明。

    02、一个简单的例子

    下面的代码:

    O0编译会报如下错,说f()函数没有定义:

    $ gcc -O0 cc.c
    
    cc.c:1:13: warning: ‘f' used but never defined [enabled by default]
    
     void f(void);
    
        ^
    
    /tmp/ccTwwtHG.o: In function `main':
    
    cc.c:(.text+0x19): undefined reference to `f'
    
    collect2: error: ld returned 1 exit status

    但是用O2编译,则没有问题:

    $ gcc -O2 cc.c

    原因在于,O2编译,它意识到a==1,所以if(a>2),它不会成立,所以f()没有定义也没有关系。

    把代码稍微改一下后:

    O2这个时候也不行了:

    $ gcc -O2 cc.c
    
    /tmp/ccXiyBHn.o: In function `main':
    
    cc.c:(.text.startup+0x7): undefined reference to `f'
    
    collect2: error: ld returned 1 exit status

    所以,通过这个例子,大家可以看出来为什么同样的代码,用O2就可以过,用O0就过不了。内核里面有许多类似设想编译器会进行优化的代码。

    3.我们不想inline了

    由于编译的优化,有些函数(比如小函数和全工程里面只被一个人调用的函数)虽然没有显示地写成inline,但是编译器优化为inline了,这给调试造成了一些麻烦,因为找不到这个函数对应的symbol了。

    这个时候,我们可以显示地写明某些函数我们不想inline: