性能优化:编译器优化选项 -O2/-O3 究竟有多强大?
之前的“性能优化的一般策略及方法”一文中介绍了多种性能优化的方法。根据以往的项目经验,开启编译器优化选项可能是立竿见影、成本最低、效果最好的方式了。
这么说可能还不够直观,举个真实的例子:我所参与的自动驾驶的项目中,无需修改任何代码,仅仅增加一个 -O2
选项,进程整体的 CPU loading 可以从 50% 降到 30% 左右,某些关键函数的执行时间可以从 1700us 降低到 700us 左右。
编译器能优化能力远比你想象中的强大!往后翻翻附录,看看那些多到让人眼花的优化选项你就知道,很多的人工优化都是不必要的,编译器会做得更快,更好,更安全!人工优化,不仅会降低代码的可读性和可维护性,而且非常容易引入 bug!
实际上,不管是 -O2
还是 -O3
,都是一组优化选项的集合,要知道具体做了什么,可以通过 gcc/g++ 的 -c -Q --help=optimizers
参数
例如我用的 aarch64-unknown-nto-qnx7.1.0-g++ 编译器,如果想知道加了 -O2
之后开启了哪些优化项,可以通过以下 3 条命令:
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q -O2 --help=optimizers > /tmp/O2-opts
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q --help=optimizers > /tmp/O-opts
$ diff /tmp/O2-opts /tmp/O-opts | grep enabled
< -fdevirtualize [enabled]
< -finline-functions-called-once [enabled]
< -finline-small-functions [enabled]
< -foptimize-strlen [enabled]
< -freorder-blocks [enabled]
< -freorder-functions [enabled]
< -ftree-switch-conversion [enabled]
< -ftree-tail-merge [enabled]
...
随便看了几个,就足以感受到编译器优化选项的强大:
- finline-xxx:内联函数,以避免函数调用开销。顺便提一句:代码中的
inline
关键字只是一个对编译器的提示,编译器会根据具体情况作出最佳的选择,无论是否有inline
关键字 - fdevirtualize:尝试把虚函数调用转换为直接调用,以避免虚函数导致的额外开销
- freorder-blocks:对函数中的代码块重新排序,以减少分支数、提高代码局部性
- freorder-functions:对对象中函数重新排序,以提升代码局部性:把经常执行的函数放到 ".text.hot" 节,不常执行的函数放到 ".text.unlikely" 节
...
完整的优化项很多,具体每个选项的确切解释需要查看编译器手册。
小结
- 如果性能不理想,先检查是否开启了编译器优化选项。这可能是最快、最有效的手段了。
- 编译器能优化能力远比你想象中的强大!
- 不要在没有开启优化选项的时候就开始盲目改代码,很多都是徒劳,甚至降低性能、引入 bug:编译器优化会做得更快、更安全
- 如果开了优化选项,你的程序出现问题,不要怀疑编译器,大概率是因为你的代码不规范,使用了 C/C++ “未定义”行为导致的
- 需要注意,在汽车领域中,对优化选项有一定的限制,比如我的项目中,编译器的 Safety Manual 明确说明了最大只支持
-O2
的优化等级
附录
授人以渔
关于这个问题,我第一开始想到的是问 ChatGPT,但是得到的结果并不满意。然后想到的是 RTFM!
man gcc
搜索关键字 /optimiz
,很快就找到了我要的答案:
gcc 支持的优化选项
Optimization Options
-faggressive-loop-optimizations -falign-functions[=n[:m:[n2[:m2]]]] -falign-jumps[=n[:m:[n2[:m2]]]] -falign-labels[=n[:m:[n2[:m2]]]]
-falign-loops[=n[:m:[n2[:m2]]]] -fno-allocation-dce -fallow-store-data-races -fassociative-math -fauto-profile -fauto-profile[=path]
-fauto-inc-dec -fbranch-probabilities -fcaller-saves -fcombine-stack-adjustments -fconserve-stack -fcompare-elim -fcprop-registers
-fcrossjumping -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules -fcx-limited-range -fdata-sections -fdce -fdelayed-branch
-fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively -fdevirtualize-at-ltrans -fdse -fearly-inlining -fipa-sra
-fexpensive-optimizations -ffat-lto-objects -ffast-math -ffinite-math-only -ffloat-store -fexcess-precision=style -ffinite-loops
-fforward-propagate -ffp-contract=style -ffunction-sections -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm -fgraphite-identity
-fgcse-sm -fhoist-adjacent-loads -fif-conversion -fif-conversion2 -findirect-inlining -finline-functions -finline-functions-called-once
-finline-limit=n -finline-small-functions -fipa-modref -fipa-cp -fipa-cp-clone -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile
-fipa-pure-const -fipa-reference -fipa-reference-addressable -fipa-stack-alignment -fipa-icf -fira-algorithm=algorithm
-flive-patching=level -fira-region=region -fira-hoist-pressure -fira-loop-pressure -fno-ira-share-save-slots -fno-ira-share-spill-slots
-fisolate-erroneous-paths-dereference -fisolate-erroneous-paths-attribute -fivopts -fkeep-inline-functions -fkeep-static-functions
-fkeep-static-consts -flimit-function-alignment -flive-range-shrinkage -floop-block -floop-interchange -floop-strip-mine
-floop-unroll-and-jam -floop-nest-optimize -floop-parallelize-all -flra-remat -flto -flto-compression-level -flto-partition=alg
-fmerge-all-constants -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves -fmove-loop-invariants -fno-branch-count-reg
-fno-defer-pop -fno-fp-int-builtin-inexact -fno-function-cse -fno-guess-branch-probability -fno-inline -fno-math-errno -fno-peephole
-fno-peephole2 -fno-printf-return-value -fno-sched-interblock -fno-sched-spec -fno-signed-zeros -fno-toplevel-reorder -fno-trapping-math
-fno-zero-initialized-in-bss -fomit-frame-pointer -foptimize-sibling-calls -fpartial-inlining -fpeel-loops -fpredictive-commoning
-fprefetch-loop-arrays -fprofile-correction -fprofile-use -fprofile-use=path -fprofile-partial-training -fprofile-values
-fprofile-reorder-functions -freciprocal-math -free -frename-registers -freorder-blocks -freorder-blocks-algorithm=algorithm
-freorder-blocks-and-partition -freorder-functions -frerun-cse-after-loop -freschedule-modulo-scheduled-loops -frounding-math
-fsave-optimization-record -fsched2-use-superblocks -fsched-pressure -fsched-spec-load -fsched-spec-load-dangerous
-fsched-stalled-insns-dep[=n] -fsched-stalled-insns[=n] -fsched-group-heuristic -fsched-critical-path-heuristic -fsched-spec-insn-heuristic
-fsched-rank-heuristic -fsched-last-insn-heuristic -fsched-dep-count-heuristic -fschedule-fusion -fschedule-insns -fschedule-insns2
-fsection-anchors -fselective-scheduling -fselective-scheduling2 -fsel-sched-pipelining -fsel-sched-pipelining-outer-loops
-fsemantic-interposition -fshrink-wrap -fshrink-wrap-separate -fsignaling-nans -fsingle-precision-constant -fsplit-ivs-in-unroller
-fsplit-loops -fsplit-paths -fsplit-wide-types -fsplit-wide-types-early -fssa-backprop -fssa-phiopt -fstdarg-opt -fstore-merging
-fstrict-aliasing -fthread-jumps -ftracer -ftree-bit-ccp -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-coalesce-vars
-ftree-copy-prop -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre -fcode-hoisting -ftree-loop-if-convert
-ftree-loop-im -ftree-phiprop -ftree-loop-distribution -ftree-loop-distribute-patterns -ftree-loop-ivcanon -ftree-loop-linear
-ftree-loop-optimize -ftree-loop-vectorize -ftree-parallelize-loops=n -ftree-pre -ftree-partial-pre -ftree-pta -ftree-reassoc
-ftree-scev-cprop -ftree-sink -ftree-slsr -ftree-sra -ftree-switch-conversion -ftree-tail-merge -ftree-ter -ftree-vectorize -ftree-vrp
-funconstrained-commons -funit-at-a-time -funroll-all-loops -funroll-loops -funsafe-math-optimizations -funswitch-loops -fipa-ra
-fvariable-expansion-in-unroller -fvect-cost-model -fvpt -fweb -fwhole-program -fwpa -fuse-linker-plugin -fzero-call-used-regs --param
name=value -O -O0 -O1 -O2 -O3 -Os -Ofast -Og
aarch64-unknown-nto-qnx7.1.0-g++ 加 -O2
相较于默认不加 -O2
增加的优化选项(完整列表)
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q -O2 --help=optimizers > /tmp/O2-opts
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q --help=optimizers > /tmp/O-opts
$ diff /tmp/O2-opts /tmp/O-opts | grep enabled
< -falign-labels [enabled]
< -fbranch-count-reg [enabled]
< -fcaller-saves [enabled]
< -fcode-hoisting [enabled]
< -fcombine-stack-adjustments [enabled]
< -fcompare-elim [enabled]
< -fcprop-registers [enabled]
< -fcrossjumping [enabled]
< -fcse-follow-jumps [enabled]
< -fdefer-pop [enabled]
< -fdevirtualize [enabled]
< -fdevirtualize-speculatively [enabled]
< -fexpensive-optimizations [enabled]
< -fforward-propagate [enabled]
< -fgcse [enabled]
< -fguess-branch-probability [enabled]
< -fhoist-adjacent-loads [enabled]
< -fif-conversion [enabled]
< -fif-conversion2 [enabled]
< -findirect-inlining [enabled]
< -finline-functions-called-once [enabled]
< -finline-small-functions [enabled]
< -fipa-bit-cp [enabled]
< -fipa-cp [enabled]
< -fipa-icf [enabled]
< -fipa-icf-functions [enabled]
< -fipa-icf-variables [enabled]
< -fipa-profile [enabled]
< -fipa-pure-const [enabled]
< -fipa-ra [enabled]
< -fipa-reference [enabled]
< -fipa-sra [enabled]
< -fipa-vrp [enabled]
< -fisolate-erroneous-paths-dereference [enabled]
< -flra-remat [enabled]
< -fmove-loop-invariants [enabled]
< -foptimize-sibling-calls [enabled]
< -foptimize-strlen [enabled]
< -fpartial-inlining [enabled]
< -fpeephole2 [enabled]
< -freorder-blocks [enabled]
< -freorder-functions [enabled]
< -frerun-cse-after-loop [enabled]
< -fsched-pressure [enabled]
< -fschedule-insns [enabled]
< -fschedule-insns2 [enabled]
< -fsection-anchors [enabled]
< -fshrink-wrap [enabled]
< -fsplit-wide-types [enabled]
< -fssa-phiopt [enabled]
< -fstore-merging [enabled]
< -fstrict-aliasing [enabled]
< -fthread-jumps [enabled]
< -ftree-bit-ccp [enabled]
< -ftree-builtin-call-dce [enabled]
< -ftree-ccp [enabled]
< -ftree-ch [enabled]
< -ftree-coalesce-vars [enabled]
< -ftree-copy-prop [enabled]
< -ftree-dce [enabled]
< -ftree-dominator-opts [enabled]
< -ftree-dse [enabled]
< -ftree-fre [enabled]
< -ftree-pre [enabled]
< -ftree-pta [enabled]
< -ftree-sink [enabled]
< -ftree-slsr [enabled]
< -ftree-sra [enabled]
< -ftree-switch-conversion [enabled]
< -ftree-tail-merge [enabled]
< -ftree-ter [enabled]
< -ftree-vrp [enabled]
性能优化:编译器优化选项 -O2/-O3 究竟有多强大?的更多相关文章
- gcc 优化选项 -O1 -O2 -O3 -Os 优先级
http://hi.baidu.com/xiaole10368/item/7cea9b1369cc240db88a1a5c 少优化->多优化: O0 -->> O1 -->&g ...
- gcc 优化选项 -O1 -O2 -O3 -Os 优先级,-fomit-frame-pointer
英文:https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html#Optimize-Options 少优化->多优化: ...
- 探索c#之尾递归编译器优化
阅读目录: 递归运用 尾递归优化 编译器优化 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数. 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果. 递归最重 ...
- gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化【转】
转自:http://blog.csdn.net/qinrenzhi/article/details/78334677 相关博客http://blog.chinaunix.net/uid-2495495 ...
- GCC笔记(警告.优化以及调试选项)
GCC提供了大量的警告选项,对代码中可能存在的问题提出警告,通常可以使用-Wall来开启以下警告: -Waddress -Warray-bounds (only with -O2) -Wc++0x-c ...
- GCC(警告.优化以及调试选项)
GCC(警告.优化以及调试选项) [介绍] gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件 预处 ...
- 【转】C 编译器优化过程中的 Bug
C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...
- 编译器优化:何为SLP矢量化
摘要:SLP矢量化的目标是将相似的独立指令组合成向量指令,内存访问.算术运算.比较运算.PHI节点都可以使用这种技术进行矢量化. 本文分享自华为云社区<编译器优化那些事儿(1):SLP矢量化介绍 ...
- Swift 性能探索和优化分析
本文首发在 CSDN<程序员>杂志,订阅地址 http://dingyue.programmer.com.cn/. Apple 在推出 Swift 时就将其冠以先进,安全和高效的新一代编程 ...
- C#编译器优化那点事
使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...
随机推荐
- 下载安装JDK 和 IntelliJ IDEA 和 ActiveMq
wget http://yun.diandaxia.com/other/jdk-8u92-linux-x64.rpm rpm -ivh jdk-8u92-linux-x64.rpm wget http ...
- HBase-Hbase启动异常java.lang.IllegalArgumentException: object is not an instance of declaring class
1.问题描述 HBase启动时异常如下: java.lang.IllegalArgumentException: object is not an instance of declaring clas ...
- C++ map自定义比较函数遵守严格弱序
C++ map自定义比较函数遵守严格弱序 问题背景及定位 背景:这个问题是在将tablesaw(一个Java的数据处理项目)迁移到C++时出现的. 问题位置:SplitOn()函数,在数据流水线中的a ...
- Wireguard笔记(三) lan-to-lan子网穿透和多网段并存
目录 Wireguard笔记(一) 节点安装配置和参数说明 Wireguard笔记(二) 命令行操作 Wireguard笔记(三) lan-to-lan子网穿透和多网段并存 多 Wireguard 服 ...
- 【framework】ATMS启动流程
1 前言 ATMS 即 ActivityTaskManagerService,用于管理 Activity 及其容器(任务.堆栈.显示等).ATMS 在 Android 10 中才出现,由原来的 A ...
- html中iframe调用兄弟iframe中的js方法
问题说明 最近工作中碰到一个页面有一个主iframe A,用于操作主要业务元素.其中有一个弹出框里面也嵌入了一个iframe B, 此时,我需要在B中调用A中JS的指定方法.下面咱们来通过例子还原一下 ...
- C++ 线程的学习---线程同步
因为是学习篇,写下是为了个人的学习与理解.故参考其他文章为多. 为什么需要线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而 ...
- 【Android 逆向】【攻防世界】黑客精神
1. apk 安装到手机,提示输入注册码 2. jadx打开apk MainActivity.java @Override // android.app.Activity public void on ...
- django自定义模型管理器Manager及方法
django自定义模型管理器Manager及方法 自定义管理器(Manager) 在语句Book.objects.all()中,objects是一个特殊的属性,通过它来查询数据库,它就是模型的一个Ma ...
- 【系统选型】OA需求分析,OA系统选型及各供应商对比。
去年公司内部做OA信息化升级,需要更新换代一下OA系统,当时OA选型整理下来的资料分享一下. 需求调研整理后如下: 一共四个模块需要更新&升级 : OA模块(包括行政) + 合同模块 + 费 ...