C++性能优化简单总结

什么样的代码是高度优化的?

 我们先出去数据结构和算法本身的使用。
 
 C++ 的高效代码通常是利用了各种编译器优化和语言特性来最大程度地提高执行效率和资源利用率的代码。我们需要编写编译器友好的代码来
 让编译器优化或者说编写出不用编译器高度优化优化也能达到同样效果的代码。
 pipeline, cache 是性能优化一个很重要的点  我们需要编写编译器友好优化型的代码更有利于提高效率
 但其实使用矢量化计算的代码编写难度是很高的,更像是在写汇编,如果不是做hpc的我们可以尽量让编译器来优化就足够了。
 还有就是用CUDA这种GPU编程可以很好加速并行计算 (现在还没学)
性能优化就不得不提一下测试框架  Google benchmark     gtest    doctest  
intel的vtune
Linux  perf工具
还有内存泄漏的工具 valgrind 当然他也有不仅限于内存泄漏检查的功能
  • 编译器一般都会进行经典的常量折叠 , 但一般不是万能的 ,如果你的代码过于复杂 就不会优化。
  • 经典的不变量提出循环体优化
  • xmm系列寄存器 浮点数优化的 矢量寄存器
  • simd 向量优化 avx see 指令集 这个得看兼容性 (开启O3的时候会有simd优化) memset底层就是simd
  • 可以使用 GCC -march=native -O3 让编译器自动检测当前硬件支持的指令集
  • 在进行指针操作的时候 可以 显示 表明 两个指针不会有重合 使用__restrict关键字 方便编译器优化
  • 使用voilatile 可以告诉 处理器取内容的时候必须是在内存里 而不是在寄存器里的
  • 可以使用openmp 他会强制进行并行计算 (基于 fork 和join 的并行计算框架)非常灵活 对代码的入侵性小。没有数据依赖的一些操作可以用openmp 实现并行。编译器集成了openmp 可以使用-fopenmp,只需要下载一些头文件。
  • constexpr可以进行 编译器求值 但constexpr不能保证一定在编译器求值 可以了解一下c++20 consteval
  • 内联优化 其实inline 这个关键词没什么用 在内联方面 ,而是放在在头文件里,可以在两个模块里存在,然后再一个地方初始化。可以理解为共具有 extern 和static的好处
  • 内联的化如果编译期 找不到他的实现体编译器是做不了内联的 如果想要内联 就尽量放在同一个文件里
  • 可以使用无锁数据结构 一般是用原子变量+内存序 来做的 开销比使用mutex低 因为mutex 底层就是cas 之类的硬件原语实现的
  • 有if分支的循环体是很难simd矢量化的 ,如果是跳跃访问的化矢量化也是很困难的甚至无法simd
  • if 还可能会影响分支预测 从而影响pipeline的工作影响效率, 有 unlikely 这样的提示编译器的
  • 字节对齐 更有利于优化
  • 结构体的SOA 和AOS SOA不符合面向对象编程 (OOP) 的习惯,但常常有利于性能。又称之为面向数据编程 (DOP) 更容易simd矢量化
  • 浮点优化的CPU周期是很长的,编译器不优化是因为可能÷0,编译器很葱末, 但是乘法很快我们可以变成乘法计算 但是可能精度损失,我们可以 -ffast-math让编译器大胆优化除法。
  • std的math是带重载的 如果用c语言的可能会有意想不到的BUG。
  • 除了经典的 map reduce 可以进行并行计算 ,分治一类的操作(没有数据依赖)我们也可以轻松进行并行,经典的就是快速排序,大数据的时候我们进行并行,当数据量小的时候 ,进行并行可能会有OS的开销,我们可以串行计算
  • 想要一个很好的并行结果,就必须要保证尽量不让cpu空转 ,cpu可以流水行,cache line也可以进行预取 ,可以更好的达到mem-bound
  • 写入内存的粒度很小可能会造成不必要的读取 ,intel _mm_stream_si32指令可以绕开缓存 得凑够一个cache line的时候再择机写回内存,这样可以充分利用硬件的特性,提高写入的效率和性能。当然只适用于纯写入,如果还要读的话反而还要同步等待stream执行完成。
  • 在进行IO密集型的任务时候 ,协程才是更好的方案
  • 一维数组比二维数组更高效
  • 多线程的伪共享,如果两个核心访问到了的同一缓存行,cpu为了安全起见 只允许一个核心 写入统一地址的缓存行,从而导致读写这个变量的速度受限于三级缓存的速度,而不是一级缓存的速度,要想消除错误共享很简单,只需要把每个核心写入的地址尽可能分散开了就行了。
  • jemalloc tcmalloc 这些对多线程 内存分配优化的库 因为他们都会有线程局部缓存,通过Hook技术替换
  • noexcept 会让函数不抛出异常 ,在减少二进制的同时,并且可以让编译器更可能的优化
  • 尽量避免拷贝 就像Spdlog 里 采用的都是 视图 我们只需要拿到弱引用 集date () size()
  • 尽量使用移动操作 std::move() 对简单数据类型没有用 ,注意c++返回值优化 不要返回std::move(tmp) 妨碍优化
  • alloctor 这样的内存池化技术来管理内存
  • 在网上看到了循环迭代器优于指针??? 其实开了编译优化以后 大家生成的汇编代码都是一样的
  • 尽量使用位运算 一般而言位运算都是高效的
  • 模板元编程 可以将数据尽量放到编译期计算 ,可以进行类型检查,避免了运行时的重复计算,提高了运行时效率。
  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值