服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Linux|Centos|Ubuntu|系统进程|Fedora|注册表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服务器之家 - 服务器系统 - Linux - Linux编译优化必须掌握的几个姿势总结

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

2022-07-20 11:56宋宝华 Linux

内核是操作系统的核心,也是操作系统最基本的部分。下面这篇文章主要给大家总结介绍了关于Linux编译优化必须掌握的几个姿势,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧

01、编译选项和内核编译

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

所以首先我们都知道,linux内核如果用o0编译,是无法编译过的,linux的内核编译,要么是o2,要么是os,这点从linux的makefile里面可以看出:

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

当选择了

config_cc_optimize_for_size

它会是os,否则就是o2。

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

?
1
2
3
gcc -c -q -o2 --help=optimizers > /tmp/o2-opts
 
gcc -c -q -os --help=optimizers > /tmp/os-opts

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

?
1
meld /tmp/o2-opts /tmp/os-opts

发现差异小的可怜:

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

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

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

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

从o0到o1,o2,o3,是一个开启的优化选项逐步加大的过程:

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

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

02、一个简单的例子

下面的代码:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
$ 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编译,则没有问题:

?
1
$ gcc -o2 cc.c

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

把代码稍微改一下后:

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

o2这个时候也不行了:

?
1
2
3
4
5
6
7
$ 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:

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

否则,上面2个函数,即便你代码里面没有写inline,由于o2和os使能了相关的inline选项,也可能被编译器自动inline掉,如果我们想拒绝inline,可以通过noline来标识。

4.我不想被优化

在全局已经使能o1, o2, o3, os的情况下,某个单独的函数我们不想做任何的优化,可以用__attribute__((optimize("o0")))来修饰这个函数,比如我们把上述用o2可以编译过的代码进行如下修改:

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

重新用o2编译:

?
1
2
3
4
5
6
7
$ gcc -o2 cc.c
 
/tmp/cc8m338p.o: in function `main':
 
cc.c:(.text+0x19): undefined reference to `f'
 
collect2: error: ld returned 1 exit status

5. 总结的话

下面给几条实践指南:

  1. 尽量不要尝试用o0去编译内核,这不符合真实的工程实践,也不太被主流linux社区所支持;内核依赖o2/os去做较多的优化;
  2. 追求你的代码在o2的情况下,仍然是正确的,代码要经得起编译优化;比如o0工作正常,而o2不正常,应该尽可能从自身找原因,分析汇编;
  3. 如果在全局优化的情况下,想针对某个局部避免优化,可以尝试用noinline,__attribute__((optimize("o0")))等进行外科手术式地调整。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:https://mp.weixin.qq.com/s/CIYzI6SAWcHWTD6z3PvOuQ

延伸 · 阅读

精彩推荐