Skip to content

CPU

Cache

缓存行 (Cache Line)

缓存行是 CPU 缓存(L1、L2、L3)与主内存 (RAM) 之间数据交换的最小单位,通常大小为 64 字节

利用空间局部性 (Spatial Locality)。当 CPU 请求一个字节的数据时,OS 知道程序很可能接下来会访问周围的字节。因此,CPU 会一口气把整个 64 字节的缓存行都从 RAM/L3 搬到 L1/L2 中。

缓存块的结构

缓存(Cache)本质上是一个高速的查找表。它被组织成一系列缓存块 (Cache Block)

组成部分 描述
数据区 (Data) 存储实际的 64 字节 数据(即缓存行)。
有效位 (Valid Bit) 类似于页表中的有效位,用于标记这个缓存块中存储的数据是否有效或已初始化。
标记 (Tag) 存储一个地址片段,用于识别这个缓存块中的数据来自 RAM 中的哪个地址

分组相联映射 (Set-Associative Mapping)

速度

在一颗 ~3 GHz 的现代 CPU 上,大概是这样:Gist+1

  • CPU 一个时钟周期:≈ 0.3–0.4 ns
  • L1 Cache 命中:≈ 0.5–1 ns(大约 3–4 个周期)
  • L2 Cache 命中:≈ 3–5 ns(大约 10–15 个周期)
  • L3 Cache 命中:≈ 10–20 ns(几十个周期)
  • 主内存 DRAM:≈ 80–150 ns(两百多甚至几百个周期)

你可以先记一条粗略比例:

L1 : L2 : L3 : 内存 ≈ 1 : 10 : 30 : 100

MESI

针对同一条 cache line,每个核心自己的缓存里都有一个状态:

  • M (Modified):我这份是最新的,只在我这里,并且比内存新(脏)。
  • E (Exclusive):我这份是最新的,只在我这里,而且和内存一致(干净)。
  • S (Shared):我这份是最新的,可能多个核都有,而且和内存一致(干净)。
  • I (Invalid):我这里没有有效副本。

读(Read)

  • 我若是 M/E/S:直接读,不发总线事务(命中)。
  • 我若是 I:必须去拿数据(发 BusRd)。 拿回来后是 E 还是 S 取决于“别人有没有这行”。

写(Write)

  • 我若是 M:直接写。
  • 我若是 E:直接升级成 M(不需要通知别人,因为别人没有)。
  • 我若是 S:必须让别人都失效(发 BusUpgr),然后 S→M
  • 我若是 I:必须“读到并拿到独占”(发 BusRdX 或 RFO),然后 I→M

BusRd(读共享):我缺这行,想读。

BusRdX / RFO(读并独占):我缺这行,但我想写,需要独占。

BusUpgr(升级为独占):我已经有 S,只是要写,让别人失效即可(不用再搬数据)。