多级缓存

为什么需要 CPU cache?

CPU 的频率太快了,快到主存跟不上,这样在处理器时钟周期内,CPU 常常需要等待主存,浪费资源,所以 cache 的出现,是为了缓解 CPU 和内存之间速度的不匹配问题(结构:cpu->cache->memort)

cache 工作原理

cache 的工作原理是基于“局部性”原理,它包含以下两个方面:

  • 时间局部性:如果某个数据被访问,那么在不久的将来他很可能被再次访问
  • 空间局部性:如果某个数据被访问,那么与他相邻的数据很快也可能被访问

多级缓存是什么

左图为最简单的高速缓存的配置,数据的读取和存储都经过高速缓存,CPU 核心与高速缓存有一条特殊的快速通道;主存和高速缓存都连在系统总线上,这条总线还用于其他组件的通信。
高速缓存出现不久,系统变得越来越复杂,高速缓存与主存之间的速度差异被拉大,直到加入了另一级缓存,新加入的这级缓存比第一缓存更大,而且更慢,而且经济上不合适,所以有了二级缓存,甚至是三级缓存。

20201229113915

cache 带来的问题

cache 给系统带来性能上飞跃的同时,也引入了新的问题“缓存一致性问题”。设想如下场景(cpu 一共有两个核,core1 和 core2):
以 i++为例,i 的初始值是 0.那么在开始每个核都存储了 i 的值 0,当第 core1 块做 i++的时候,其缓存中的值变成了 1,即使马上回写到主内存,那么在回写之后 core2 缓存中的 i 值依然是 0,其执行 i++,回写到内存就会覆盖第一块内核的操作,使得最终的结果是 1,而不是预期中的 2。

缓存一致性

本模块转自《大话处理器》Cache 一致性协议之 MESI

为了达到数据访问的一致,需要各个处理器在访问缓存时遵循一些协议,在读写时根据协议来操作,比较经典的 Cache 一致性协议当属 MESI 协议,很多其他的处理器都是使用它的变种。

单核 Cache 中每个 Cache line 有 2 个标志:dirty 和 valid 标志,它们很好的描述了 Cache 和 Memory(内存)之间的数据关系(数据是否有效,数据是否被修改),而在多核处理器中,多个核会共享一些数据,MESI 协议就包含了描述共享的状态。

MESI 协议

在 MESI 协议中,每个 Cache line 有 4 个状态,可用 2 个 bit 表示,它们分别是:

状态 描述
M(Modified) 这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本 Cache 中。
E(Exclusive) 这行数据有效,数据和内存中的数据一致,数据只存在于本 Cache 中。
S(Shared) 这行数据有效,数据和内存中的数据一致,数据存在于很多 Cache 中。
I(Invalid) 这行数据无效。
  • M(Modified)和 E(Exclusive)状态的 Cache line,数据是独有的,不同点在于 M 状态的数据是 dirty 的(和内存的不一致),E 状态的数据是 clean 的(和内存的一致)。
  • S(Shared)状态的 Cache line,数据和其他 Core 的 Cache 共享。只有 clean 的数据才能被多个 Cache 共享。
  • I(Invalid)表示这个 Cache line 无效。

E 状态示例如下:

20201229114621
只有 Core 0 访问变量 x,它的 Cache line 状态为 E(Exclusive)。

S 状态示例如下:

20201229114748
3 个 Core 都访问变量 x,它们对应的 Cache line 为 S(Shared)状态。

M 状态和 I 状态示例如下:

20201229114818
Core 0 修改了 x 的值之后,这个 Cache line 变成了 M(Modified)状态,其他 Core 对应的 Cache line 变成了 I(Invalid)状态。

状态迁移

在 MESI 协议中,每个 Cache 的 Cache 控制器不仅知道自己的读写操作,而且也监听(snoop)其它 Cache 的读写操作。每个 Cache line 所处的状态根据本核和其它核的读写操作在 4 个状态间进行迁移。

MESI 协议状态迁移图如下:

20201229114916

  • Local Read 表示本内核读本 Cache 中的值
  • Local Write 表示本内核写本 Cache 中的值
  • Remote Read 表示其它内核读其它 Cache 中的值
  • Remote Write 表示其它内核写其它 Cache 中的值
  • 箭头表示本 Cache line 状态的迁移
  • 环形箭头表示状态不变

当内核需要访问的数据不在本 Cache 中,而其它 Cache 有这份数据的备份时,本 Cache 既可以从内存中导入数据,也可以从其它 Cache 中导入数据,不同的处理器会有不同的选择。MESI 协议为了使自己更加通用,没有定义这些细节,只定义了状态之间的迁移,下面的描述假设本 Cache 从内存中导入数据。

MESI 状态之间的迁移过程如下:

当前状态

事件

行为

下一个状态

I(Invalid)

Local Read

如果其它Cache没有这份数据,本Cache从内存中取数据,Cache line状态变成E;

如果其它Cache有这份数据,且状态为M,则将数据更新到内存,本Cache再从内存中取数据,2个Cache 的Cache line状态都变成S;

如果其它Cache有这份数据,且状态为S或者E,本Cache从内存中取数据,这些Cache 的Cache line状态都变成S

E/S

Local Write

从内存中取数据,在Cache中修改,状态变成M;

如果其它Cache有这份数据,且状态为M,则要先将数据更新到内存;

如果其它Cache有这份数据,则其它Cache的Cache line状态变成I

M

Remote Read

既然是Invalid,别的核的操作与它无关

I

Remote Write

既然是Invalid,别的核的操作与它无关

I

E(Exclusive)

Local Read

从Cache中取数据,状态不变

E

Local Write

修改Cache中的数据,状态变成M

M

Remote Read

数据和其它核共用,状态变成了S

S

Remote Write

数据被修改,本Cache line不能再使用,状态变成I

I

S(Shared)

Local Read

从Cache中取数据,状态不变

S

Local Write

修改Cache中的数据,状态变成M,

其它核共享的Cache line状态变成I

M

Remote Read

状态不变

S

Remote Write

数据被修改,本Cache line不能再使用,状态变成I

I

M(Modified)

Local Read

从Cache中取数据,状态不变

M

Local Write

修改Cache中的数据,状态不变

M

Remote Read

这行数据被写到内存中,使其它核能使用到最新的数据,状态变成S

S

Remote Write

这行数据被写到内存中,使其它核能使用到最新的数据,由于其它核会修改这行数据,

状态变成I

I

参考