【CMAKE】c++代码编译加速以及优化项

  新闻资讯     |      2024-07-29 14:56
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.htmlhttps://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用gdb中的 p命令查看变量的值,改变变量的值等。并且优先采用最快的编译速度

当优化标识被启用之后,gcc编译器将会改变程序的结构(当然会在保证变换之后的程序与源程序语义等价的前提之下),以满足代码大小最小或运行速度更快,当然二者是不可兼得的。在不同的gcc配置和目标平台下,同一个标识所采用的优化种类也是不一样的。-O会在大大优化循环中的运行速度。

这两个命令的效果是一样的,目的都是在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度。并开启如下的优化选项:

 
 

该优化选项会牺牲部分编译速度,除了执行-O1所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。

 
 

该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等。

 

这个选项会提高执行代码的大小,当然会降低目标代码的执行时间。

这个优化标识和-O3有异曲同工之妙,当然两者的目标不一样,-O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。

为了降低目标代码大小,会禁用下列优化选项,一般就是压缩内存中的对齐空白(alignment padding)

 
 

该选项将不会严格遵循语言标准,除了启用所有的-O3优化选项之外,也会针对某些语言启用部分优化。如:-ffast-math ,对于Fortran语言,还会启用下列选项:

 
 

该标识会精心挑选部分与-g选项不冲突的优化选项,当然就能提供合理的优化水平,同时产生较好的可调试信息和对语言标准的遵循程度。

Cmake中添加方法

 

-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