之前的“性能优化的一般策略及方法”一文中介绍了多种性能优化的方法。根据以往的项目经验,开启编译器优化选项可能是立竿见影、成本最低、效果最好的方式了。

这么说可能还不够直观,举个真实的例子:我所参与的自动驾驶的项目中,无需修改任何代码,仅仅增加一个 -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" 节

    ...

完整的优化项很多,具体每个选项的确切解释需要查看编译器手册。

小结

  1. 如果性能不理想,先检查是否开启了编译器优化选项。这可能是最快、最有效的手段了。
  2. 编译器能优化能力远比你想象中的强大!
  3. 不要在没有开启优化选项的时候就开始盲目改代码,很多都是徒劳,甚至降低性能、引入 bug:编译器优化会做得更快、更安全
  4. 如果开了优化选项,你的程序出现问题,不要怀疑编译器,大概率是因为你的代码不规范,使用了 C/C++ “未定义”行为导致的
  5. 需要注意,在汽车领域中,对优化选项有一定的限制,比如我的项目中,编译器的 Safety Manual 明确说明了最大只支持 -O2 的优化等级

附录

授人以渔

关于这个问题,我第一开始想到的是问 ChatGPT,但是得到的结果并不满意。然后想到的是 RTFM!

man gcc

在线版本:https://manpages.org/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 究竟有多强大?的更多相关文章

  1. gcc 优化选项 -O1 -O2 -O3 -Os 优先级

    http://hi.baidu.com/xiaole10368/item/7cea9b1369cc240db88a1a5c 少优化->多优化: O0 -->> O1 -->&g ...

  2. gcc 优化选项 -O1 -O2 -O3 -Os 优先级,-fomit-frame-pointer

    英文:https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html#Optimize-Options 少优化->多优化: ...

  3. 探索c#之尾递归编译器优化

    阅读目录: 递归运用 尾递归优化 编译器优化 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数. 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果. 递归最重 ...

  4. gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化【转】

    转自:http://blog.csdn.net/qinrenzhi/article/details/78334677 相关博客http://blog.chinaunix.net/uid-2495495 ...

  5. GCC笔记(警告.优化以及调试选项)

    GCC提供了大量的警告选项,对代码中可能存在的问题提出警告,通常可以使用-Wall来开启以下警告: -Waddress -Warray-bounds (only with -O2) -Wc++0x-c ...

  6. GCC(警告.优化以及调试选项)

    GCC(警告.优化以及调试选项) [介绍] gcc and g++分别是gnu的c & c++编译器   gcc/g++在执行编译工作的时候,总共需要4步   1.预处理,生成.i的文件 预处 ...

  7. 【转】C 编译器优化过程中的 Bug

    C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...

  8. 编译器优化:何为SLP矢量化

    摘要:SLP矢量化的目标是将相似的独立指令组合成向量指令,内存访问.算术运算.比较运算.PHI节点都可以使用这种技术进行矢量化. 本文分享自华为云社区<编译器优化那些事儿(1):SLP矢量化介绍 ...

  9. Swift 性能探索和优化分析

    本文首发在 CSDN<程序员>杂志,订阅地址 http://dingyue.programmer.com.cn/. Apple 在推出 Swift 时就将其冠以先进,安全和高效的新一代编程 ...

  10. C#编译器优化那点事

    使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...

随机推荐

  1. AOF

    AOF 基础概念 以日志的形式记录了每个写操作 在redis重新运行时,会将这些操作重新执行一遍 文件形式:appendonly.aof 开启AOF需要更改配置文件:appendonly:yes AO ...

  2. NC50614 取石子游戏 1

    题目链接 题目 题目描述 有一种有趣的游戏,玩法如下: 玩家:2人: 道具:N颗石子: 规则: 游戏双方轮流取石子:每人每次取走若干颗石子(最少取1颗,最多取K颗):石子取光,则游戏结束:最后取石子的 ...

  3. NC20684 wpy的请求

    题目链接 题目 题目描述 "题目名称只是吸引你来做题的啦,其实和题目没什么卵关系:o(* ̄▽ ̄*)o" -- 历史--殿堂 wpy移情别恋啦,他不喜欢spfa了,现在他喜欢使用di ...

  4. NC24949 [USACO 2008 Jan S]Running

    题目链接 题目 题目描述 The cows are trying to become better athletes, so Bessie is running on a track for exac ...

  5. Linux进程通信 | 消息队列

    什么是消息队列? 假设你是一个快递员,你需要将货物从一个仓库运到另一个仓库.但是你发现自己的时间不够用,需要另外请一个人来帮忙.那么,你们之间如何进行协作呢? 一种方式是直接将货物全部交给对方,但这样 ...

  6. AIR32F103(二) Linux环境和LibOpenCM3项目模板

    目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...

  7. 解决邮件客户端QQ Mail及Thunderbird无法登入Outlook的问题

    最近无论是安卓手机的邮件客户端, 或者是 Ubuntu 下的 Thunderbird 都无法登入 Outlook 账号, 原因是需要开启双因素验证. 这个在 Outlook 界面上是不能直接设置的, ...

  8. 【framework】DisplayContent简介

    1 前言 ​ DisplayContent 用于管理屏幕,一块屏幕对应一个 DisplayContent 对象,虽然手机只有一个显示屏,但是可以创建多个 DisplayContent 对象,如投屏时, ...

  9. Java设计模式-原型模式Prototype

    介绍 当我们有一个类的实例(Prototype)并且我们想通过复制原型来创建新对象时,通常使用Prototype模式. 原型模式是一种创建型设计模式.能够复制已有对象, 而又无需使代码依赖它们所属的类 ...

  10. Java使用ConcurrentHashMap实现简单的内存式缓存

    需求说明: 实际项目中我打算把用户和组织信息放到缓存中,基于此提出以下几点需求: 1.数据存储在内存中: 2.允许以键值对的方式存储对象类数据并带有过期策略: 3.不限制内存使用,但cache也不能给 ...