CPU 高速缓存(Cache Memory)
CPU 为何要有高速缓存
CPU 在摩尔定律的领导下以每 18 个月翻一番的速度在倒退,然而内存和硬盘的倒退速度远远不迭 CPU。这就造成了高性能能的内存和硬盘价格及其低廉。然而 CPU 的高度运算须要高速的数据。为了解决这个问题,CPU 厂商在 CPU 中内置了大量的高速缓存以解决 I\O 速度和 CPU 运算速度之间的不匹配问题。
在 CPU 拜访存储设备时,无论是存取数据抑或存取指令,都趋于汇集在一片间断的区域中,这就被称为局部性原理。
工夫局部性(Temporal Locality):如果一个信息项正在被拜访,那么在近期它很可能还会被再次拜访。
比方循环、递归、办法的重复调用等。
空间局部性(Spatial Locality):如果一个存储器的地位被援用,那么未来他左近的地位也会被援用。
比方程序执行的代码、间断创立的两个对象、数组等。
带有高速缓存的 CPU 执行计算的流程
- 程序以及数据被加载到主内存
- 指令和数据被加载到 CPU 的高速缓存
- CPU 执行指令,把后果写到高速缓存
- 高速缓存中的数据写回主内存
目前风行的多级缓存构造
因为 CPU 的运算速度超过了 1 级缓存的数据 I\O 能力,CPU 厂商又引入了多级的缓存构造。
多级缓存构造
多核 CPU 多级缓存一致性协定 MESI
多核 CPU 的状况下有多个一级缓存,如何保障缓存外部数据的统一, 不让零碎数据凌乱。这里就引出了一个一致性的协定 MESI。
MESI 协定缓存状态
MESI 是指 4 中状态的首字母。每个 Cache line 有 4 个状态,可用 2 个 bit 示意,它们别离是:
缓存行(Cache line): 缓存存储数据的单元。
状态 | 形容 | 监听工作 |
---|---|---|
M 批改 (Modified) | 该 Cache line 无效,数据被批改了,和内存中的数据不统一,数据只存在于本 Cache 中。 | 缓存行必须时刻监听所有试图读该缓存行绝对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成 S(共享)状态之前被提早执行。 |
E 独享、互斥 (Exclusive) | 该 Cache line 无效,数据和内存中的数据统一,数据只存在于本 Cache 中。 | 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行须要变成 S(共享)状态。 |
S 共享 (Shared) | 该 Cache line 无效,数据和内存中的数据统一,数据存在于很多 Cache 中。 | 缓存行也必须监听其它缓存使该缓存行有效或者独享该缓存行的申请,并将该缓存行变成有效(Invalid)。 |
I 有效 (Invalid) | 该 Cache line 有效。 | 无 |
触发事件 | 形容 |
---|---|
本地读取(Local read) | 本地 cache 读取本地 cache 数据 |
本地写入(Local write) | 本地 cache 写入本地 cache 数据 |
远端读取(Remote read) | 其余 cache 读取本地 cache 数据 |
远端写入(Remote write) | 其余 cache 写入本地 cache 数据 |
状态 | 触发本地读取 | 触发本地写入 | 触发远端读取 | 触发远端写入 |
---|---|---|---|---|
M 状态(批改) | 本地 cache:M 触发 cache:M 其余 cache:I | 本地 cache:M 触发 cache:M 其余 cache:I | 本地 cache:M→E→S 触发 cache:I→S 其余 cache:I→S 同步主内存后批改为 E 独享, 同步触发、其余 cache 后本地、触发、其余 cache 批改为 S 共享 | 本地 cache:M→E→S→I 触发 cache:I→S→E→M 其余 cache:I→S→I 同步和读取一样, 同步实现后触发 cache 改为 M,本地、其余 cache 改为 I |
E 状态(独享) | 本地 cache:E 触发 cache:E 其余 cache:I | 本地 cache:E→M 触发 cache:E→M 其余 cache:I 本地 cache 变更为 M, 其余 cache 状态该当是 I(有效) | 本地 cache:E→S 触发 cache:I→S 其余 cache:I→S 当其余 cache 要读取该数据时,其余、触发、本地 cache 都被设置为 S(共享) | 本地 cache:E→S→I 触发 cache:I→S→E→M 其余 cache:I→S→I 当触发 cache 批改本地 cache 独享数据时时,将本地、触发、其余 cache 批改为 S 共享. 而后触发 cache 批改为独享,其余、本地 cache 批改为 I(有效),触发 cache 再批改为 M |
S 状态 (共享) | 本地 cache:S 触发 cache:S 其余 cache:S | 本地 cache:S→E→M 触发 cache:S→E→M 其余 cache:S→I 当本地 cache 批改时,将本地 cache 批改为 E, 其余 cache 批改为 I, 而后再将本地 cache 为 M 状态 | 本地 cache:S 触发 cache:S 其余 cache:S | 本地 cache:S→I 触发 cache:S→E→M 其余 cache:S→I 当触发 cache 要批改本地共享数据时,触发 cache 批改为 E(独享), 本地、其余 cache 批改为 I(有效), 触发 cache 再次批改为 M(批改) |
I 状态(有效) | 本地 cache:I→S 或者 I→E 触发 cache:I→S 或者 I →E 其余 cache:E、M、I→S、I 本地、触发 cache 将从 I 有效批改为 S 共享或者 E 独享,其余 cache 将从 E、M、I 变为 S 或者 I | 本地 cache:I→S→E→M 触发 cache:I→S→E→M 其余 cache:M、E、S→S→I | 既然是本 cache 是 I,其余 cache 操作与它无关 | 既然是本 cache 是 I,其余 cache 操作与它无关 |
M | E | S | I | |
---|---|---|---|---|
M | × | × | × | √ |
E | × | × | × | √ |
S | × | × | √ | √ |
I | √ | √ | √ | √ |
`
value = 3;void exeToCPUA(){ value = 10; isFinsh = true;}void exeToCPUB(){ if(isFinsh){ //value肯定等于10?! assert value == 10; }}`
试想一下开始执行时,CPU A 保留着 finished 在 E(独享) 状态,而 value 并没有保留在它的缓存中。(例如,Invalid)。在这种状况下,value 会比 finished 更迟地摈弃存储缓存。齐全有可能 CPU B 读取 finished 的值为 true,而 value 的值不等于 10。即 isFinsh 的赋值在 value 赋值之前。这种在可辨认的行为中产生的变动称为重排序(reordings)。留神,这不意味着你的指令的地位被歹意(或者好心)地更改。它只是意味着其余的 CPU 会读到跟程序中写入的程序不一样的后果。~顺便提一下 NIO 的设计和 Store Bufferes 的设计是十分相像的。~### 硬件内存模型执行生效也不是一个简略的操作,它须要处理器去解决。另外,存储缓存(Store Buffers)并不是无穷大的,所以处理器有时须要期待生效确认的返回。这两个操作都会使得性能大幅升高。为了应酬这种状况,引入了生效队列。它们的约定如下:* 对于所有的收到的 Invalidate 申请,Invalidate Acknowlege 音讯必须立即发送* Invalidate 并不真正执行,而是被放在一个非凡的队列中,在不便的时候才会去执行。* 处理器不会发送任何音讯给所解决的缓存条目,直到它解决 Invalidate。即使是这样处理器未然不晓得什么时候优化是容许的,而什么时候并不容许。 罗唆处理器将这个工作丢给了写代码的人。这就是内存屏障(Memory Barriers)。> 写屏障 Store Memory Barrier(a.k.a. ST, SMB, smp_wmb) 是一条通知处理器在执行这之后的指令之前,利用所有曾经在存储缓存(store buffer)中的保留的指令。> 读屏障 Load Memory Barrier (a.k.a. LD, RMB, smp_rmb) 是一条通知处理器在执行任何的加载前,先利用所有曾经在生效队列中的生效操作的指令。`
void executedOnCpu0() { value = 10; //在更新数据之前必须将所有存储缓存(store buffer)中的指令执行结束。 storeMemoryBarrier(); finished = true;}void executedOnCpu1() { while(!finished); //在读取之前将所有生效队列中对于该数据的指令执行结束。 loadMemoryBarrier(); assert value == 10;}`
##### 援用文章http://www.importnew.com/1058...https://www.cnblogs.com/yanlo...