失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 应用程序性能瓶颈中的CPU缓存优化

应用程序性能瓶颈中的CPU缓存优化

时间:2019-03-09 08:56:13

相关推荐

应用程序性能瓶颈中的CPU缓存优化

1.前言

在应用程序中会有大量的对变量的操作,在一般情况下不会导致问题,但在多线程操作共享变量时,不当的操作会产生大量的冗余操作,造成性能的浪费。这篇文章主要从编码方式与逻辑策略对变量从CPU寄存器,CPU缓存,直至内存,描述变量的生命周期,性能瓶颈与解决方式。

2.基本原理

2.1 硬件架构

在CPU需要对数据进行操作时,会按照以下顺序对数据进行获取,若未获取到则继续向下一级获取,直至内存中命中。

在上面是普通的双路(安装了两颗CPU)双核CPU,也有不带L3的CPU。一般情况下CPU数据读取是按照上述过程执行。可以看出L1,L2是核内共享,L3为CPU内多核共享,而内存为多CPU共享,寄存器会优先去L1查找,再去L2,L3,内存中查找。不同CPU架构可能会导致L1,L2,L3架构层次不同。

注意:L1分为数据L1和指令L1两部分

2.2 存储层次

这里引用一张《深入理解计算机系统》中的图

里面完整描述了各部件与速度的关系,各部件获取数据的速度大约在:

时钟周期:时钟周期是CPU主频的倒数,比如2GHz主频的CPU,一个时钟周期是0.5ns,也就是说,主频越高,时钟周期越小。

2.3 实际参数

以下是一个6核12线程i7-10750H CPU的参数。

缓存大小:

在上面的结构中,可以看到,6个核心中,每个核心有32K的数据L1,32K的指令L1,还有256K的L2,12M的L3。在上面可以看到,L1和L2前面分别跟了‘6 X’,而L3没有,表明L3为CPU共享三级缓存。

缓存路数:

可以看到缓存后有个8-way,4-way,16-way这种,缓存路数用来将缓存行打包标记,用于快速查找数据。比如L1的数据缓存有32K,每个缓存行有64B,那么这个L1的数据缓存中就有32*1024/64=512个缓存行,而这的8-way代表将每8个缓存行打包为512/8=64标记。

CPU差异:

不同CPU架构不同,比如AMD 5700U采用Zen2架构,他的L3为两个,多核共享,并不是常见的CPU核内共享。

2.4 缓存行

缓存行是CPU中很重要的一个结构,在CPU读取数据A时,后面可能再次访问到,并且可能会访问到相邻的数据B,所以为了读取效率,应用到了缓存行的概念,CPU会在读取数据时,将命中对象相邻的区域也读取到缓存行中,这个区域也就是缓存行的大小一般是64Byte。

3.性能瓶颈

3.1 提升缓存命中率

在CPU的L1缓存中,分为数据缓存与指令缓存,数据缓存用来存储被缓存到的数据,指令缓存用户存放CPU的逻辑判断信息。

3.1.1 数据缓存命中

当对一个数组进行遍历的时候,如果在使用到缓存的时候多次击穿缓存,会造成大量的性能损失,导致性能不达预期,为提高缓存命中率,我们应该顺序的读取缓存中的内容,尽可能提高数据缓存命中率,提高程序运行效率。

CPU缓存与性能优化 | 码农家园 ()

3.1.2 指令缓存命中

在CPU中具备分支预测功能,当代码中出现if,switch等分支语句时,意味着CPU可以选择跳转到两段不同的指令去运行。如果分支预测器可以预测接下来要在哪段代码执行(比如if还是else中的指令),就可以提前把这些指令放在缓存中,CPU 执行时就会更快。

容易命中的判断放前面:

在需要做逻辑判断时,使用尽可能的将最容易命中的概率放在前面,将不容易命中的放后面,这样能减少判断次数,提高效率。

数据先排序再循环:

在数据需要循环数据并排序的时候,尽量先排序再进行循环处理,提高分支预测命中率。

3.1.3 多核CPU下缓存命中(核绑定)

在现代多核CPU中,多个CPU核对同一资源竞争的情况下会导致缓存的丢失,也导致程序性能的下降,所以在程序中,配置线程个数不一定是越多越好,而是因地制宜,根据程序对性能的需求与硬件的条件,设定不同参数,达到最高性能。而有时程序需要对数据进行计算的时候,频繁的CPU切换会导致大量的缓存穿透,造成性能下降,我们可以在这时绑定CPU,强制CPU在某个核心中计算。

3.2 伪缓存行

解决方式:缓存行填充

如果觉得《应用程序性能瓶颈中的CPU缓存优化》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。