【CMAKE】c++代码编译加速以及优化项
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用gdb中的 p命令查看变量的值,改变变量的值等。并且把获取最快的编译速度作为它的目标。当优化标识被启用之后,gcc编译器将会试图改变程序的结构(当然会在保证变换之后的程序与源程
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.htmlhttps://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用gdb中的 p命令查看变量的值,改变变量的值等。并且优先采用最快的编译速度
当优化标识被启用之后,gcc编译器将会改变程序的结构(当然会在保证变换之后的程序与源程序语义等价的前提之下),以满足代码大小最小或运行速度更快,当然二者是不可兼得的。在不同的gcc配置和目标平台下,同一个标识所采用的优化种类也是不一样的。-O会在大大优化循环中的运行速度。
优化参数
-O1
这两个命令的效果是一样的,目的都是在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度。并开启如下的优化选项:
-fauto-inc-dec
-fbranch-count-reg
-fcombine-stack-adjustments
-fcompare-elim
-fcprop-registers
-fdce
-fdefer-pop
-fdelayed-branch
-fdse
-fforward-propagate
-fguess-branch-probability
-fif-conversion2
-fif-conversion
-finline-functions-called-once
-fipa-pure-const
-fipa-profile
-fipa-reference
-fmerge-constants
-fmove-loop-invariants
-freorder-blocks
-fshrink-wrap
-fshrink-wrap-separate
-fsplit-wide-types
-fssa-backprop
-fssa-phiopt
-fstore-merging
-ftree-bit-ccp
-ftree-ccp
-ftree-ch
-ftree-coalesce-vars
-ftree-copy-prop
-ftree-dce
-ftree-dominator-opts
-ftree-dse
-ftree-forwprop
-ftree-fre
-ftree-phiprop
-ftree-sink
-ftree-slsr
-ftree-sra
-ftree-pta
-ftree-ter
-funit-at-a-time
-O2
该优化选项会牺牲部分编译速度,除了执行-O1所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。
-fthread-jumps
-falign-functions -falign-jumps
-falign-loops -falign-labels
-fcaller-saves
-fcrossjumping
-fcse-follow-jumps -fcse-skip-blocks
-fdelete-null-pointer-checks
-fdevirtualize -fdevirtualize-speculatively
-fexpensive-optimizations
-fgcse -fgcse-lm
-fhoist-adjacent-loads
-finline-small-functions
-findirect-inlining
-fipa-cp
-fipa-cp-alignment
-fipa-bit-cp
-fipa-sra
-fipa-icf
-fisolate-erroneous-paths-dereference
-flra-remat
-foptimize-sibling-calls
-foptimize-strlen
-fpartial-inlining
-fpeephole2
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition -freorder-functions
-frerun-cse-after-loop
-fsched-interblock -fsched-spec
-fschedule-insns -fschedule-insns2
-fstrict-aliasing -fstrict-overflow
-ftree-builtin-call-dce
-ftree-switch-conversion -ftree-tail-merge
-fcode-hoisting
-ftree-pre
-ftree-vrp
-fipa-ra
-O3
该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等。
-finline-functions // 采用一些启发式算法对函数进行内联
-funswitch-loops // 执行循环unswitch变换
-fpredictive-commoning //
-fgcse-after-reload //执行全局的共同子表达式消除
-ftree-loop-vectorize //
-ftree-loop-distribute-patterns
-fsplit-paths
-ftree-slp-vectorize
-fvect-cost-model
-ftree-partial-pre
-fpeel-loops
-fipa-cp-clone options
这个选项会提高执行代码的大小,当然会降低目标代码的执行时间。
-Os
这个优化标识和-O3有异曲同工之妙,当然两者的目标不一样,-O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。
为了降低目标代码大小,会禁用下列优化选项,一般就是压缩内存中的对齐空白(alignment padding)
-falign-functions
-falign-jumps
-falign-loops
-falign-labels
-freorder-blocks
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition
-fprefetch-loop-arrays
-Ofast:
该选项将不会严格遵循语言标准,除了启用所有的-O3优化选项之外,也会针对某些语言启用部分优化。如:-ffast-math ,对于Fortran语言,还会启用下列选项:
-fno-protect-parens
-fstack-arrays
-Og:
该标识会精心挑选部分与-g选项不冲突的优化选项,当然就能提供合理的优化水平,同时产生较好的可调试信息和对语言标准的遵循程度。
其他编译参数
Cmake中添加方法
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS_RELEASE -Ofast)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall")
-std=c++14启用c++14标准当然对应的GLIBCXX_USE_CXX11_ABI=0也应该被设置
-shared 建立共享library
-rdynamic 用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 或者gdb backtrace来实现向后跟踪)
-undefined dynamic_lookup 令所有未定义的符号标记在运行时查找
-fvisibility=hidden 决定共享库中的符号是否可见,如果为hidden有以下优势
- 提升动态共享对象(DSO(Dynamic Shared Object))的加载效率
- 使得优化器生成更好的代码**(具体原理待研究)**
- 减少DSO的大小
- 避免符号冲突
更新默认gcc
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7
update-alternatives --list gcc
性能测试
如图进行的累加测试
程序 | -Ofast | C++ | Pybind(将循环放入c++中) | Pybind(循环放在python中) | Python |
---|---|---|---|---|---|
100w iter 累加 编译命令 c++ -shared -rdynamic -fPIC -undefined -fvisibility=hidden -std=c++14 $(python3 -m pybind11 --includes) ex.cpp -o ex$(python3-config --extension-suffix) | 否 | 0.00227s | 0.00234s ↓3.08% (相比纯c++速度略下降) | 0.89s 相比循环在C++中速度大幅下降 调用空函数也非常耗时,比纯python慢10倍 0.5149s | 0.115s |
是 | 0.000895s ↑ 60.57% (打开-O优化的提升) | 0.000939s ↑ 59.87% (打开-O优化的提升) | 0.2044 ↑ 77.03%(打开-O优化的提升) | \ |
1、开启-Ofast对循环优化较大,通过删除循环内没有改变值的变量赋值操作, 减少循环内执行指令的数量。并将中间变量直接分配在寄存器中
2、Pybind11中调用c++函数需要将所有参数都进行类型转换,使用循环频繁调用 c++接口会导致速度下降
3、当循环放在Python代码中没有被优化到,导致速度有所下降
4、Python循环会非常慢主要是python返回的都是可迭代对象内部的__iter__,并且都需记录要状态更新
5、Python中算数是没有类型的,所有在执行__add__操作时候,都必须检测操作数类型(具体可以参考该拿什么拯救你,Slow Python)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)