以下是几条优化C++的方法
如何获取最高性能?
- 选择正确的算法
- 使用低overhead的语言(C++、Rust)
- 正确的编译选项
- 了解底层硬件
了解底层硬件可以帮助我们获取更多的性能
仅仅通过C++代码是无法预测性能的,性能很依赖CPU与内存的底层实现。
上图为Intel大概的构架。
分支预测
数组排序与不排序,性能会差一倍
通过Vtune可以看到相关耗时
其耗时来自预测。
构架中的BPU用于分支预测,分支预测失败越多耗时就越长。
在第五个时间戳的时候cpu并不知道要执行啥,所以会进行分支预测,继续执行。
如果预测失败可能会导致15~20个cycle
编译器也会做相应优化,如果数字为int时编译器会自动去除分支。
除了分支以外,以下这几项也会导致分支预测:
- 函数指针
- 函数返回地址
- 虚函数
以下代码,如果同一种同时执行效率更高。
命中缓存
int的vector,vector的offset不同。
发现Offset不同的情况下性能也不一样。
这个性能的差异是L1 Data Cache引起的。
L1的实现是通过硬件实现的hashtable实现的 Key占8字节,cacheline占64字节
我们可以通过l1d.replacement看到cache missing的次数
数值计算
上述代码,不同的数字计算的速度并不一样。
为整数时计算比0.3等特殊数字要快得多,值得注意的是0.5也很快(二次幂)。
这个实际上和硬件相关的处理模块也有关
通过fp_assist.any可以看到浮点计算的开关次数
在Intel的芯片上可以用相应的开关加速计算
多线程访问
同时访问同一块内存,线程越多,速度越慢
第一个核读入了A,
第二个核读取的时候,会从第一个核中读入,会比从内存中读取更多
第二个核写入的时候第二个核的数据和第一个核不同步了。
导致需要将数据同步到第一个核
为了解决这个问题,我们可以将不同的操作数放到不同的cacheline中。
例如原来的cache分布是这样子:
我们可以将数字放到不同的cacheline中,
这样就不会产生写入的冲突。
用这个命令可以看到不同核数据失效的次数