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

这么说可能还不够直观,举个真实的例子:我所参与的自动驾驶的项目中,无需修改任何代码,仅仅增加一个 -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. Ubuntu+Minio对象存储+pm2进程管理

    Minio是一个go编写的高性能对象存储服务,它兼容Amazon S3 API.无论是静态网站的托管,还是数据存储分析,亦或是数据的备份与恢复等多种场景下,都可以为我们提供解决方案. ubuntu安装 ...

  2. JS 判断两个数组是否相等,元素以及顺序相等,顺序不同但元素相等

    壹 ❀ 引 在日常开发中,判断两个数组是否相等应该是较为常见的场景,因为常用,所以想着简单记录下.关于判断数组相等,这里我分为两种场景,第一种是数组完全相等,即数组元素相同且元素顺序一致:第二则为元素 ...

  3. NC14685 加边的无向图

    题目链接 题目 题目描述 给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~ 输入描述 第一行两个正整数 n 和 m . 接下来的m行中,每行两个正整数 i ...

  4. Swoole从入门到入土(15)——WebSocket服务器[初步接触]

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.换句话说,Websocket让web可以与服务端实现长连接. 在Swoole中,通过内置的 WebSock ...

  5. spring boot整合mybatis-plus报错:There is no getter for property named ‘ew‘ in ‘xxx‘

    问题说明 spring boot整合mybatis-plus报错:There is no getter for property named 'ew' in 'xxx' 问题解决 XXXmapper. ...

  6. 双哈希_Birthday_Cake

    Birthday Cake 思路:找到每个串的公共前后缀,统计公共前后缀之间的字符串的hash值,并判断所给n个串中是否存在符合条件的串 eg:abbddab 对于该串,我们不难发现,公共前后缀是ab ...

  7. Java异常处理的20个最佳实践:告别系统崩溃

    引言 在Java编程中,异常处理是一个至关重要的环节,它不仅涉及到程序的稳定性和安全性,还关系到用户体验和系统资源的合理利用.合理的异常处理能够使得程序在面对不可预知错误时,能够优雅地恢复或者给出明确 ...

  8. 代码+案例,实战解析BeautifulSoup4

    本文分享自华为云社区<从HTML到实战:深入解析BeautifulSoup4的爬虫奇妙世界>,作者:柠檬味拥抱. 网络上的信息浩如烟海,而爬虫技术正是帮助我们从中获取有用信息的重要工具.在 ...

  9. win10 wsl 运行后没有反应

    wsl 运行一段时间后执行没有反应, 需要重启LxssManager 管理员模式打开 powshell 找到pid, 结束pid >tasklist /svc /fi "service ...

  10. win32-UI Automation

    使用UI Automation遍历窗口的所有控件标题和类 #include <Windows.h> #include <stdio.h> #include <UIAuto ...