1. CPU缓存
cpu高速缓存的由来
- 在CPU的全部取指令周期中(程序计算),至少需要访问一次存储器(也就是我们所说物理内存上的数据)
- 通常需要多次访问存储器的取操作数或者保存结果,CPU处理计算的速度明显受限于访问存储器的限制
- 因此解决方案就是利用局部性原理,在CPU与物理内存之间提供一个容量小并且速度快的存储器,称为高速缓存
高速缓存概述
- 缓存是分“段”(line)的,一个段对应一块存储空间,大小是 32(较早的 ARM、90 年代 /2000 年代早期的 x86 和 PowerPC)、64(较新的 ARM 和 x86)或 128(较新的 Power ISA 机器)字节
- 高速缓存包含物理内存部分数据副本
- cpu读取数据时将会先检查高速缓存中的数据是否存在,存在就返回,不存在就读取物理内存数据
高速缓存和内存
高速缓存分为L1-L3 Cache
- L1 Cache: 一级缓存是CPU第一层高速缓存,分为指令缓存和数据缓存,一般服务器的CPU的L1缓存容量在32-4096kb,现在的L1 Cache都不能直接与内存直连传输数据
- L2 Cache: 由于L1级别高速缓存容量的限制,为了再次提高CPU的运算速度,在CPU外部放置一个高速存储器,即二级缓存
- L3 Cache: 现在的L3缓存都是内置的,主要是进一步降低内存延迟,提升处理器运算能力,一般是多核共享一个L3缓存
CPU系统架构
2. 缓存一致性与MESI协议
单CPU缓存的读与写操作
-
缓存读操作
- CPU读取数据时,先在L1中寻找,再从L2中寻找,再从L3中寻找,然后是内存,最后是外存储器(持久化介质)
- 如果只处理读取操作,那么不论是L1-L3的缓存,都将会和主内存的数据保持一致
-
缓存写操作
- 缓存直写:直接透过本级缓存,直接将数据写入到下一级缓存或主内存中,写入成功/失败后将对应的缓存内容也执行更新/丢弃操作,这样缓存中的数据与将与主内存数据一致
- 缓存回写:将修改本级缓存并记录标志段,通过标志段将数据回写到下一级缓存或主内存中,如果标志段被丢弃也将会先进行一次回收,也保证所有级别的缓存数据保持一致
缓存的一致性协议
- 多核缓存的写操作问题
- 场景: 在一个多核且每核都有对应的缓存的处理器进行读写操作
- 假设有一个CPU缓存了主内存上的某一段数据,在另一个CPU上需要对该内存段的数据进行写操作,此时在写数据的CPU更新了缓存而其他CPU并且更新到缓存,这时候便会产生缓存数据的不一致性
缓存一致性约定
如何解决上述的问题,出现缓存数据不一致的原因如下:
- 多核CPU都有对应的高速缓存,每核缓存的数据都无法共享
- 这时候我们会想到就是让缓存能够为多核CPU共享,但出现的问题就是处理器运算能力性能会下降,每次都需要等待其中一个CPU进行写操作之后才能够进行下一步的处理
- 那么我们的期望就是使用多核缓存,同时也能够让它们运作变得像操作一组缓存一样,那么缓存的一致性协议就是为了这一点而设计解决问题的
缓存的MESI协议
缓存的一致性协议有很多种,比较典型的就是MESI协议,关于MESI协议简述如下:
- 失效(Invalid)缓存段: 缓存不存在或者已经失效过时
- 共享(Shared)缓存段: 数据有效,并与主内存以及其他Cache的数据保持一致,用于读缓存操作
- 独占(Exclusive)缓存段: 数据有效,与主内存的数据保持一致,与S的区别就是在于该处理器处于独占的状态时,其他的cpu缓存将会失效
- 已修改(Modified)缓存段,属于脏段,表示当前的cpu缓存已经修改过,但是还没有同步到主内存中,为当前的cpu所专有
- 小结:也就是cpu控制缓存的读写操作,还需要监听其他cpu发生的通知,保证缓存最终数据的一致性
cpu数据读写流程
3. 内存屏障
CPU优化手段:运行时指令重排序
- 为什么会出现指令重排序
当CPU写缓存时发现区块正被其他CPU占用,为了提高CPU处理性能,可能将后面的读缓存命令优先执行
- 指令重排原则
重排需要遵循as-if-serial语义规则,即不管怎么进行重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变.编译器/runtime/处理器都必须遵循as-if-serial语义,也就是说编译器和处理器不会对存在数据依赖关系的操作做重排序
CPU高速缓存存在的问题
- 缓存中的数据与主内存的数据并不是实时同步的,各CPU(或CPU核心)间缓存的数据也不是实时同步的,也就是在同一个时间点,各CPU所看到同一个内存地址的数据的值可能是不一致的
- 指令重排序存在问题,虽然遵循as-if-serial语义,但是仅仅能保证是在单核CPU下单线程自己执行的情况下保证结果是正确的,如果是多核多线程,指令逻辑无法分辨因果关联,可能会出现乱序,导致程序运行结果出现错误.
内存屏障
- 定义
是一类同步屏障指令,它使得CPU或编译器在对内存进行操作的时候,严格按照一定的顺序来执行, 也就是说在memory barrier之前的指令和memory barrier之后的指令不会由于系统优化等原因而导致乱序
- 内存屏障指令
- 写内存屏障,在指令后插入Store Barrier,能让写入缓存中最新的数据更新写入主内存,让其他线程可见.强制写入主内存,这种显示调用,CPU就不会因为性能考虑而去对指令重排
- 读内存屏障,在指令前插入Load Barrier,可以让高速缓存中的数据失效,强制从新主内存中加载数据读取主内存内容,让CPU缓存与主内存保持一致,避免缓存导致的一致性问题
- 完全内存屏障,保障了早于屏障的内存读写操作的结果提交到内存之后,再执行晚于屏障的读写操作
- 作用
- 就是解决上述CPU高速缓存存在的问题
来源:CSDN
作者:疾风先生
链接:https://blog.csdn.net/wind_602/article/details/103914263