4. MESI 状态转换详解:本地读/写、远程读/写触发的状态迁移图与总线事务

MESI 协议的核心在于每个 Cache Line 的四种状态(Modified、Exclusive、Shared、Invalid)在本地与远程读写操作下的精确迁移。理解这些迁移路径以及伴随的总线事务,是 ARM 多核缓存一致性移植适配的基础。本章通过状态迁移图、总线事务表与典型场景分析,详细拆解每一种转换路径。

4.1 MESI 状态定义回顾

状态缩写含义数据有效性与主存一致性其他核副本
ModifiedM已修改有效不一致(脏)无
ExclusiveE独占有效一致(干净)无
SharedS共享有效一致(干净)可能有
InvalidI无效无效——
关键概念: M 状态是“脏”的,E 和 S 状态是“干净”的。只有 M 状态的 Cache Line 在被替换或远程读取时需要写回主存。

4.2 本地读/写触发的状态迁移

本地操作是指当前核(Local Core)访问自己的 Cache。总线事务仅在需要获取数据或通知其他核时产生。

4.2.1 本地读(Local Read, LR)

  • I → E/S: Cache Line 无效,发起 BusRd 总线事务。若其他核无副本,则进入 E 状态;若其他核有 Shared 副本,则进入 S 状态。
  • S → S: 命中,状态不变,无总线事务。
  • E → E: 命中,状态不变,无总线事务。
  • M → M: 命中,状态不变,无总线事务。

4.2.2 本地写(Local Write, LW)

  • I → M: Cache Line 无效,发起 BusRdX 总线事务,通知其他核无效化其副本。数据加载后直接修改,标记为 M。
  • S → M: 当前为 Shared,发起 BusUpgr 总线事务,使其他核副本无效化。数据修改后进入 M。
  • E → M: 当前为 Exclusive,无总线事务(因为本核独占),直接修改数据进入 M。
  • M → M: 命中,直接修改,状态不变,无总线事务。
ARM 移植要点: 在 ARM Cortex-A 系列中,BusRdX 和 BusUpgr 在 ACE(AXI Coherency Extensions)总线上分别映射为 ReadUnique 和 CleanUnique 事务。移植时需要确保总线桥接逻辑正确转换这些事务类型。

4.3 远程读/写触发的状态迁移

远程操作是指其他核(Remote Core)访问当前核持有的 Cache Line。当前核作为“监听者”响应总线事务。

4.3.1 远程读(Remote Read, RR)

  • M → S: 远程核发起 BusRd,当前核提供数据(Cache-to-Cache 传输),数据写回主存,状态降级为 S。
  • E → S: 远程核发起 BusRd,当前核提供数据(或主存提供),状态降级为 S。
  • S → S: 远程核发起 BusRd,状态不变。
  • I → I: 无效状态,无影响。

4.3.2 远程写(Remote Write, RW)

  • M → I: 远程核发起 BusRdX,当前核提供数据并写回主存,状态变为 I。
  • E → I: 远程核发起 BusRdX,状态变为 I。
  • S → I: 远程核发起 BusRdX 或 BusUpgr,状态变为 I。
  • I → I: 无效状态,无影响。

4.4 MESI 状态迁移全景图

下图展示了所有本地与远程操作触发的状态转换路径。箭头上的标签表示触发事件。

MESI 状态迁移全景图 MESI 状态迁移全景图 M E S I LR: BusRd (无副本→E / 有副本→S) LW: BusRdX LW: BusUpgr LW: 无总线事务 RR: BusRd (提供数据+写回) RR: BusRd RW: BusRdX (提供数据+写回) RW: BusRdX RW: BusRdX/BusUpgr LR/RR LR LR/LW 图例说明 实线箭头:本地操作(LR/LW) 虚线箭头:远程操作(RR/RW) M(已修改,脏) E(独占,干净) S(共享,干净) I(无效) 注:LR=本地读,LW=本地写,RR=远程读,RW=远程写

4.5 总线事务类型与触发条件

总线事务触发操作事务方向数据源对监听核的影响
BusRd本地读 I 状态请求核 → 总线主存或其他 CacheM→S, E→S, S 不变
BusRdX本地写 I 状态请求核 → 总线主存或其他 CacheM→I, E→I, S→I
BusUpgr本地写 S 状态请求核 → 总线无数据(仅无效化)S→I
ARM 移植警告: 在 ARMv8 架构中,BusUpgr 对应 ACE 协议的 CleanUnique 事务。如果总线桥接实现错误地将 CleanUnique 当作 ReadUnique 处理,会导致不必要的 Cache Line 回写,造成性能损失。务必在移植时区分这两种事务的语义。

4.6 典型场景:Cache Line 状态迁移流程

以下通过一个 4 核系统的示例,展示一个 Cache Line 从 I 状态开始,经历多次读写操作后的完整状态变化。

  1. Core 0 本地读(I→E): Core 0 发起 BusRd,其他核无副本,进入 E 状态。
  2. Core 1 本地读(E→S, I→S): Core 1 发起 BusRd,Core 0 监听到后降级为 S,Core 1 进入 S。
  3. Core 0 本地写(S→M): Core 0 发起 BusUpgr,Core 1 的 S 状态变为 I,Core 0 进入 M。
  4. Core 2 远程读(M→S, I→S): Core 2 发起 BusRd,Core 0 提供数据并写回主存,降级为 S,Core 2 进入 S。
  5. Core 3 远程写(S→I, S→I, M→I): Core 3 发起 BusRdX,所有其他核的副本无效化,Core 3 进入 M。
性能观察: 步骤 4 中 M→S 的降级触发了 Cache-to-Cache 传输和写回,延迟较高。在 ARM 多核系统中,频繁的 M→S→M 振荡会导致“一致性抖动”,应通过软件数据布局(如核间私有数据与共享数据分离)来避免。

4.7 状态迁移与总线事务对照表

当前状态操作下一状态总线事务数据流
I本地读E / SBusRd主存/Cache → 请求核
I本地写MBusRdX主存/Cache → 请求核 + 无效化
S本地读S无—
S本地写MBusUpgr无效化其他核
E本地读E无—
E本地写M无—
M本地读M无—
M本地写M无—
M远程读SBusRd当前核 → 请求核 + 写回主存
E远程读SBusRd当前核/主存 → 请求核
S远程读SBusRd主存/其他核 → 请求核
M远程写IBusRdX当前核 → 请求核 + 写回主存
E远程写IBusRdX请求核获取数据
S远程写IBusRdX / BusUpgr请求核获取数据或仅无效化

4.8 ARM 移植中的状态转换注意事项

  • M 状态写回时机: 在 ARM 实现中,M 状态 Cache Line 被远程读时,必须保证数据写回主存后再响应 BusRd,否则会导致数据不一致。ACE 协议通过 WriteBack 和 WriteClean 事务区分是否需要保留 Cache 副本。
  • E 状态优化: E 状态是 ARM 性能优化的重点。本地写 E 状态无需总线事务,这是单线程性能的关键。移植时应确保 Cache 控制器在分配新行时优先尝试 E 状态。
  • S 状态无效化延迟: 远程写触发 S→I 时,ARM 处理器通常使用“监听无效化”机制。如果监听延迟过高,可能导致写操作等待。在移植中,建议使用“写更新”队列来隐藏无效化延迟。
  • 总线事务合并: 在 ARM 多核集群中,多个核同时写同一 Cache Line 时,总线控制器应合并 BusUpgr 事务,避免广播风暴。
移植经验: 在将 MESI 协议移植到 ARM Cortex-A76 集群时,我们发现 E→M 的无总线事务路径对 SPEC CPU 性能贡献约 8-12%。确保 Cache 控制器在本地写命中 E 状态时不产生任何 snoop 请求,是移植性能达标的关键。