CPU缓存怎么工作的:局部性原理
我们都知道,CPU需要和内存访存数据。而内存的时延是相当的大的,CPU可能需要等待300到600个甚至更多的CPU周期。所以CPU需要时延低的储存器,当这些储存器命中的时候,CPU可以等待很短时间就能完事了。
但是在一般的解释的CPU缓存之前,理解CPU缓存能够工作的前提是要注意到程序的访存局部性。
你可以想象,如果CPU对每一个数据的访存的概率是均等的。如果你一个程序需要200M的数据在缓存和内存里,你可以想象,缓存的命中概率纯粹就是缓存大小和程序这个数据大小的比值。那么对于这个例子,现在处理的缓存大小可以说加速效果相当的有限。而实际程序万一还需要数GB的数据,那缓存的效果就微乎其微了。
缓存能够极大程度加速CPU性能,他的前提就是程序的局部性。也就是程序又倾向于短时间内访问比较靠近的值。时间上被引用过的内存位置容易被再次引用,空间上最近引用过的内存位置和周边的内存位置容易被再次引用等等。
这使得,CPU短时间内对不同数据访存的概率并不是平均分布的,而是具有明显的倾向的。这也是CPU缓存的有明显的加速效果原因的,CPU缓存可以把访存概率高的数据缓存进缓存中。
可以看到这里的情况,24KiB的缓存大小可以可以达到90%的命中率,也就是说这里90%的概率,CPU的访存会在这24KiB的缓存大小里解决。
实际上CPU绝大部分情况下等待一二三级缓存的时间逐渐减少,但是一二三级缓存每级都有数倍的逐级增长。这也意味着,访存一二三级缓存的概率也是数分之一的逐级减少。
再看看实际情况:我这里用skylake架构的6700HQ和9400测试了PR导出视频,Vray CPU benchmark,和chrome浏览器,cinebench R20/R23,handbrake,arctime导出视频的情况。大约估算了一下缓存命中率。
Vray CPU | PR port video | R23 | R20 | Arctime | handbrake | Chrome | |
hit in L1 | 1.0000 | 1.0000 | 1.0000 | 1.0000 | 1.0000 | 1.0000 | 1.0000 |
hit in L2/L1 | 0.1603 | 0.0217 | 0.0655 | 0.0621 | 0.0462 | 0.0680 | 0.0000 |
hit in L3/L1 | 0.0641 | 0.0121 | 0.0466 | 0.0461 | 0.0308 | 0.0680 | 0.0917 |
hit in DRAM/L1 | 0.0107 | 0.0066 | 0.0019 | 0.0018 | 0.0253 | 0.0099 | 0.0336 |
可以想象的是,像SPEC06这样的测试,即使如此,armv9的ppt上二级和三级缓存翻倍依旧有9%的性能提升,这本身就足以体现这种测试对缓存规模的依赖之大。(甚至感觉有些过了)
程序的局部性原理是缓存依赖的基础,正是因为局部性原理,才能让大小这么小的缓存极大的程度的加速程序。也正是因为这,所以当缓存越来越大,增加缓存提升的命中率越来越少,体现出明显的边际效应递减的现象。