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

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:

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

4.我不想被优化

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

重新用O2编译:

$ 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")))等进行外科手术式地调整。

总结

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

(0)

相关推荐

  • Linux下利用unzip命令如何解压多个文件详解

    linux中提示没有unzip命令解决方法 如果你如法使用unzip命令解压.zip文件,可能是你没有安装unzip软件,下面是安装方法 命令: yum list | grep zip/unzip #获取安装列表 安装命令: yum install zip #提示输入时,请输入y: 安装命令:yum install unzip #提示输入时,请输入y: Linux下直接使用unzip *.zip解压多个文件会报错 可以使用unzip '*.zip'或者 unzip "*.zip"或者u

  • Linux 如何快速找到运行中的进程

    1 进程概述 通俗的讲程序是一个包含可以执行代码的静态的文件.进程是一个开始执行但是还没有结束的程序的实例. 当程序被系统调用到内存以后,系统会给程序分配一定的资源(内存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用. 1.1 进程的分类 按照进程的功能和运行的程序分类,进程可划分为两大类: 系统进程 可以执行内存资源分配和进程切换等管理工作,而且该进程的运行不受用户的干预,即使是root用户也不能干预系统进程的运行. 用户进程 通过执行用户程序.应用程序或内核之外的系统程序而

  • Linux 命令head和tail常见用法详解

    head和tail是一组想对应的命令,默认分别显示文件的开头和末尾10行记录. head head 命令可以将一段文本的开头一部分输出到标准输出. head命令既可以处理文本文件也可以处理标准输入. 基本应用 处理文本文件: head input.txt 当有多个文件输入时,head会顺序处理并输出: head input1.txt input2.txt 处理标准输入: ls | head 当没有其他参数时,head默认输出前10行,当然,head有各种参数. 可选参数 -n: 输出的行数 例如

  • Linux中sudo、su和su -命令的区别小结

    前言 在Linux系统中,由于root的权限过大,一般情况都不使用它.只有在一些特殊情况下才采用登录root执行管理任务,一般情况下临时使用root权限多采用su和sudo命令. su命令就是切换用户的工具,怎么理解呢?比如我们以普通用户tom登录的,但要添加用户任务,执行useradd ,tom用户没有这个权限,而这个权限恰恰由root所拥有.解决办法无法有两个,一是退出tom用户,重新以root用户登录,但这种办法并不是最好的:二是我们没有必要退出tom用户,可以用su来切换到root下进行

  • linux 下隐藏进程的一种方法及遇到的坑

    前言 1.本文所用到的工具在 https://github.com/gianlucaborello/libprocesshider 可以下载 2.思路就是利用 LD_PRELOAD 来实现系统函数的劫持 LD_PRELOAD是什么: LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库.这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数.通过这个环境变量,我们可以在主程序和其动态链

  • Linux命令技巧之30个必会的命令技巧

    在Unix/Linux下,高效工作方式不是操作图形页面,而是命令行操作,命令行意味着更容易自动化.使用过Linux系统的朋友应该都知道它的命令行强大之处.本文讲述了Linux下的查找,删除,打包,解压,查询及VIM等30个常用命令技巧 1.Vim自动添加注释及智能换行 # vi ~/.vimrc set autoindent set tabstop=4 set shiftwidth=4 function AddTitle() call setline(1,"#!/bin/bash")

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

    01.编译选项和内核编译 Linux内核(英语:linux kernel),是一种计算机操作系统内核,已C语言和汇编语言写成,匹配POSIX标准,以GNU通用公共许可证发布.从技术上说Linux只是一个内核."内核"指的是一个提供硬件抽象层.磁盘及文件控制.多任务等功能的系统软件. 所以首先我们都知道,Linux内核如果用O0编译,是无法编译过的,Linux的内核编译,要么是O2,要么是Os,这点从Linux的Makefile里面可以看出: 当选择了 CONFIG_CC_OPTIMIZ

  • Aliyun Linux 编译安装 php7.3 tengine2.3.2 mysql8.0 redis5的过程详解

    介绍 之前写过 CentOS 安装 PHP,MySQL,Nginx 的相关文章,具体介绍这里就不写了,直接上操作步骤. 安装 Tengine 1. 安装必要的编译环境 yum update yum install gcc gcc-c++ autoconf automake 2. 安装需要的组件 PCRE PCRE(Perl Compatible Regular Expressions) http://www.pcre.org 是一个Perl库,包括 perl 兼容的正则表达式库.nginx re

  • linux 编译安装python3.6的教程详解

    1. 首先去官网  https://www.python.org/downloads/source/ 下载 Gzipped source tarball 不要下载 " XZ compressed source tarball " ,目前 python3.6 最新版压缩包名字是:Python-3.6.7.tgz. 把下载的压缩包随便放到一个地方,也可以放到桌面(便于安装过后删除安装包和解压后的安装包). 2. 命令行切换到上面压缩文件所在的目录(比如桌面),然后输入 tar -xzf P

  • 高并发nginx服务器的linux内核优化配置讲解

    由于默认的linux内核参数考虑的是最通用场景,这明显不符合用于支持高并发访问的Web服务器的定义,所以需要修改Linux内核参数,是的Nginx可以拥有更高的性能: 在优化内核时,可以做的事情很多,不过,我们通常会根据业务特点来进行调整,当Nginx作为静态web内容服务器.反向代理或者提供压缩服务器的服务器时,期内核参数的调整都是不同的,这里针对最通用的.使Nginx支持更多并发请求的TCP网络参数做简单的配置: 以下linux 系统内核优化配置均经在线业务系统测试,并发10万左右服务器运行

  • ubuntu16.04 linux 编译安装apache2.4.33的教程详解

    下载软件包: wget http://mirror.bit.edu.cn/apache//httpd/httpd-2.4.33.tar.gz wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-1.6.3.tar.gz wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-util-1.6.1.tar.gz 首先需要安装apr和apr-util tar xf apr-1.6.

  • linux编译kernel和svn版本冲突的解决办法

    现象 系统本来可以正常编译linux系统kernel,但在安装svn后,kernel编译出错. CHK include/linux/version.h CHK include/generated/utsrelease.h make[1]: `include/generated/mach-types.h' is up to date. CALL scripts/checksyscalls.sh CHK include/generated/compile.h gcc: directory: No s

  • linux编译内核的方法

    1.下载需要的内核版本 2.上传到操作系统 3.解压到/usr/src目录下 比如:3.19内核 tar -xvf linux-3.19.tar.xz -C /usr/src 4.创建连接 cd /usr/src ln -sv /usr/src/linux-3.19 Linux 5.进行内核设置 cd /usr/src/linux make menuconfig 这步,最好是拷贝一个前面运行的.config文件,在这个文件上进行修改,否则,可能重启起不来. 比如下面这样: cp /boot/co

  • Vue项目打包编译优化方案

    1. 不生成.map文件 默认情况下,当我们执行 npm run build 命令打包完一个项目后,会得到一个dist目录,里面有一个js目录,存放了该项目编译后的所有js文件. 我们发现每个js文件都有一个相应的 .map 文件,它们仅是用来调试代码的,可以加快打包速度,但会增大打包体积,线上我们是不需要这个代码的.这里我们需要配置不生成map文件. vue-cli2 config/index.js文件中,找到 productionSourceMap: true 这一行,将 true 改为 f

  • 详解Java编译优化之循环展开和粗化锁

    循环展开和粗化锁 我们先来回顾一下什么是循环展开. 循环展开就是说,像下面的循环遍历的例子: for (int i = 0; i < 1000; i++) { x += 0x51; } 因为每次循环都需要做跳转操作,所以为了提升效率,上面的代码其实可以被优化为下面的: for (int i = 0; i < 250; i++) { x += 0x144; //0x51 * 4 } 注意上面我们使用的是16进制数字,至于为什么要使用16进制呢?这是为了方便我们在后面的assembly代码中快速找

  • Linux编译LVGL仿真器出错问题解决

    目录 一.错误现象 二.错误分析 三.错误解决 一.错误现象 我在虚拟机下使用 LVGL 仿真器,编译仿真器源代码时发生报错 cc: error: unrecognized command line option '-Wshift-negative-value' cc: error: unrecognized command line option '-Wshift-negative-value' cc: error: unrecognized command line option '-Wsh

随机推荐