第六章 一致性协议
在本章中,我们将回到第二章介绍的缓存一致性主题。在第二章中,我们定义了缓存一致性以理解其在支持内存一致性中的作用,但未深入探讨缓存一致性协议具体的工作原理或实现方式。本章将先概述缓存一致性协议的通用原理,随后两章再讨论特定类别的协议。我们将在 6.1 节介绍缓存一致性协议的整体框架,6.2 节说明如何描述协议,6.3 节给出一个简单具体的协议示例,并在 6.4 节探讨协议设计空间。
6.1 整体框架
缓存一致性协议的目标是通过执行第 2.3 节引入(此处重新陈述)的不变量来维护缓存一致性:
1. 单写多读(SWMR)不变量:对于任意内存位置 A,在任意给定(逻辑)时刻,仅存在单个核心可对 A 执行写操作(同时也可读取),或多个核心仅可读取 A。
2. 数据值不变量:一个周期开始时内存位置的值,与上一个读写周期结束时该位置的值相同。【注,读写周期】
为实现这些不变量,我们为每个存储结构(每个缓存和 LLC / 内存)关联一个称为一致性控制器的有限状态机。这些控制器构成一个分布式系统,通过相互交换消息确保每个缓存块始终满足 SWMR 和数据值不变量。这些有限状态机的交互由缓存一致性协议定义。
缓存一致性控制器有多项职责。缓存中的一致性控制器(称为缓存控制器)如图 6.1 所示。缓存控制器需处理两类源发出的请求。
核心侧:与处理器核心接口连接,接收核心的加载(load)和存储(store)请求,并返回加载值。缓存未命中时,控制器通过发送对包含目标地址的缓存块的缓存一致性请求(如只读权限请求)发起缓存一致性事务。该请求通过互连网络发送至一个或多个缓存一致性控制器【注,那到底是一个还是多个?】。事务包含请求消息及为满足请求消息而交换的其他消息(如从其他控制器发送给请求者的数据响应消息)。事务类型和消息内容取决于具体协议。
网络侧:通过互连网络与系统其他部分接口连接,接收并处理缓存一致性请求和响应,处理逻辑同样依赖具体协议。【注,文字没有提及发送缓存一致性请求】
LLC / 内存中的缓存一致性控制器(称为内存控制器)如图 6.2 所示,其结构与缓存控制器类似,但通常仅有网络侧,不发起缓存一致性请求或接收响应【注,仅接收缓存一致性请求或发出响应】。其他代理(如 I/O 设备)可根据需求表现为类似缓存控制器[注,PCIe,UVM ?]、内存控制器或两者兼具的行为。
每个缓存一致性控制器为每个缓存块实现一组有限状态机(逻辑上每个块对应一个独立但相同的状态机),并根据块的状态接收和处理事件(如传入的缓存一致性消息)。对于块 B 的事件类型 E(如核心向缓存控制器发起的存储请求),控制器执行的操作(如发起读写权限的一致性请求)是 E 和 B 当前状态(如只读状态)的函数,操作后可能改变 B 的状态。
6.2 缓存一致性协议的描述方法
缓存一致性协议通过定义缓存一致性控制器的行为来描述。描述方式有多种,但缓存控制器的行为特性适合用表格形式描述 [9]。如表 6.1 所示,表格的行对应块状态,列对应事件,表中每个状态 / 事件项称为一个状态转移。事件 E 对应块 B 的转移包含两部分:(a) E 发生时执行的操作;(b) 块 B 的下一个状态。转移格式为 “操作 / 下一个状态”,若下一个状态与当前状态相同则可省略 “下一个状态” 部分。例如,若核心发送对块 B 的存储请求且块 B 处于只读状态(RO),表格显示控制器将执行 “发起对块 B 的读写权限一致性请求” 操作,并将块 B 状态改为 RW。【注,RO -> RW 】
为简化说明,表 6.1 的示例有意未完全展开【注,体现在 or 的使用上?】,但已体现表格说明方法描述控制器行为的能力。完整描述缓存一致性协议需明确定义缓存控制器和内存控制器的表格。
不同缓存一致性协议的差异体现在控制器说明的不同,包括块状态集合、事务类型、事件类型和状态转移逻辑的差异。6.4 节将通过探讨各方面的设计选项来描述缓存一致性协议的设计空间,在此之前先介绍一个简单具体的协议。
6.3 简单一致性协议示例
为帮助理解缓存一致性协议,我们以一个简单协议为例。系统模型基于 2.1 节的基准模型,但互连网络限定为共享总线:核心可通过一组共享线路发送消息,所有核心和 LLC / 内存均可监听总线消息。
At the LLC/memory, the state I denotes that all caches hold the block in state I, and the state V denotes that one cache holds the block in state V.
cache 中的每个缓存块有两种稳定缓存一致性状态:I(无效)和 V(有效)。LLC / 内存中的块同样有 I 和 V 两种状态,其中 I 表示所有缓存了该块的缓存的状态均为 I 状态,V 表示某一缓存了该块的缓存的状态为 V 状态。【注,如果cache了本空间块的所有 cache 的状态都为 I,那么本块自己在 LLC 的状态也为I;否则,只要有一个 cache 中,对本块空间的 cache 的状态为 V,则自己在 LLC 中也标识为V。】缓存块还有一个临时状态 IVD(见下文讨论)。系统启动时,所有缓存块和 LLC / 内存块均处于 I 状态。核心可向其缓存控制器发起加载和存储请求,当缓存控制器需要为其他块腾出空间时会隐式生成 “驱逐块” 事件。缓存未命中的加载和存储操作会发起缓存一致性事务以获取有效缓存块副本。与本指南中的所有协议一样,假设采用回写缓存:存储命中时仅更新本地缓存,待 “驱逐块” 事件触发时再将整个块写回 LLC / 内存。
协议通过三种总线消息实现两类缓存一致性事务:
Get: 请求获取块;
DataResp:传输块数据;
Put: 将块写回内存控制器。
加载或存储未命中时,缓存控制器发送 Get 消息发起 Get 事务,并等待对应的 DataResp 消息。Get 事务具有原子性:从缓存发送 Get 消息到总线上出现对应 DataResp 消息期间,总线不可被其他 Get 或 Put 事务占用【注,考察:针对本协议 or 全部协议?本协议。提到的是使用总线而已,不包括 network】。“驱逐块” 事件触发时,缓存控制器向内存控制器发送包含完整缓存块数据的 Put 消息。
图 6.3 展示了稳定缓存一致性状态之间的转移关系。我们用 “Own” 和 “Other” 前缀区分当前缓存控制器发起的事务消息与其他控制器发起的消息。需注意,若当前缓存控制器的块处于 V 状态,而其他缓存通过 Get 消息(OtherGet)请求该块,当前控制器必须通过 DataResp 消息(图中未显示)返回块数据,并将状态转为 I。【注,其他新 core 拿走数据后可能会改掉,也可能仅仅是 load,此时在新 core 中的缓存里呈现 V 状态,所以原core 缓存中的数据状态需要 I 掉。V 的唯一性?】
表 6.2 和表 6.3 更详细地描述了该协议,阴影单元格表示不可能的状态转移。例如,若缓存中的块处于 V 状态,缓存控制器不应在总线上接收到自己发送的 Put 请求(因此时块应已转为 I 状态)。【注,这个解释貌似不合理。 不是Put结束后才从V到I么?原因应该是,这种Own-Put 是没有驱动者动机的,所以不会发生。】
临时状态 IVD 对应处于 I 状态但正在等待数据(通过 DataResp 消息)以转为 V 状态的块。当稳定状态之间的转移非原子时会出现临时状态。在此简单协议中,单个消息的本方发送和对方接收,结合起来是原子的,但从内存控制器获取块,需发送 Get 消息并接收 DataResp 消息,其间存在不确定的时间间隔,IVD 状态即表示协议正在等待 DataResp。6.4.1 节将深入讨论临时状态。
该缓存一致性协议在许多方面较为简单且效率有限,但其目的是帮助理解 协议的描述方法。本书在介绍不同类型的缓存一致性协议时,将始终采用这种表格式的描述方法。
【注,Get-V:V表示有 core中的cache持有有效数据,故,Mem Controller 不需要参与后续工作】
6.4 一致性协议设计空间概述
如 6.1 节所述,缓存一致性协议设计者必须为系统中每种类型的缓存一致性控制器选择状态、事务、事件、状态转移逻辑。稳定状态的选择在很大程度上与协议的其他部分无关。例如,存在监听(snooping)和目录(directory)两类不同的缓存一致性协议,架构师可以使用相同的稳定状态集合设计监听协议或目录协议。我们将在 6.4.1 节独立于具体协议讨论稳定状态。类似地,事务的选择也基本独立于特定协议,相关内容在 6.4.2 节讨论。然而,与稳定状态和事务不同,事件、状态转移和特定临时状态高度依赖于一致性协议,无法孤立讨论。因此,6.4.3 节将探讨缓存一致性协议中的几个主要设计决策。
6.4.1 状态
在仅有单个参与者的系统中(如无缓存一致性 DMA 的单核处理器),缓存块的状态要么是有效(valid),要么是无效(invalid)。若需要区分脏块(dirty block),缓存块可能有两种有效状态:脏块的最新写入值与其他副本不同。例如,在包含回写式 L1 缓存的两级缓存层次结构中,L1 中的块相对于 L2 缓存中的过期副本可能是脏的。
具有多个参与者的系统也可仅使用上述两到三种状态(如 6.3 节的示例),但我们通常希望区分不同类型的有效状态。缓存块的状态可编码以下四个特征:有效性(validity)、脏状态(dirtiness)、独占性(exclusivity)和所有权(ownership)[10],后两者是多参与者系统特有的属性:
有效性:有效块包含该块的最新值,可被读取,但仅当块处于独占状态时允许写入。
脏状态:与单核处理器类似,若缓存块的值为最新且与 LLC / 内存中的值不同,且缓存控制器负责最终将新值更新到 LLC / 内存,则该块为脏块。“干净”(clean)通常作为脏状态的反义词使用。
独占性:若缓存块是系统中唯一的私有缓存副本(即除共享 LLC 外,其他缓存无该块副本),则该块处于独占状态。
所有权:若缓存控制器(或内存控制器)负责响应某块的缓存一致性请求,则称其为该块的所有者。在大多数协议中,每个块在任意时刻恰好有一个所有者。由于容量不足或冲突未命中而需要驱逐块时,若该块是被本参与者所有的,必须先将所有权转移给其他缓存一致性控制器,否则不能驱逐该块;在某些协议中,非被本参与者所有的那些缓存块可直接驱逐(无需发送消息)。
本节先讨论常用的稳定状态(即块未处于缓存一致性事务过程中的状态),再介绍用于描述事务过程中块状态的临时状态。
稳定状态
许多一致性协议采用 Sweazey 和 Smith 首次提出的经典五状态 MOESI 模型的子集 [10]。MOESI(通常发音为 “MO-sey” 或 “mo-EE-see”)描述缓存中块的状态,其中最基本的三个状态是 MSI,O 和 E 状态可选但非必需。每个状态对应上述特征的不同组合:
M (odified,修改态):块有效、独占、拥有所有权,可能为脏状态。块可被读写,缓存中是唯一有效副本,缓存必须响应块请求,LLC / 内存中的副本可能过期。【注,大红大紫的块】
S (hared,共享态):块有效但非独占、非脏、无所有权。缓存持有只读副本,其他缓存可能有有效只读副本。
I (nvalid,无效态):块无效。缓存要么不包含该块,要么包含可能过期的副本且不可读写。本指南中不区分这两种情况(尽管前者有时称为 “未存在” 状态)。
最基本的协议仅使用 MSI 状态,但在某些场景下添加 O 和 E 状态可优化性能。后续章节讨论带或不带这些状态的监听协议和目录协议时,将详细分析这些优化。以下是完整的 MOESI 状态列表:
M (odified,修改态)
O (wned,拥有态):块有效、拥有所有权、可能为脏状态,但非独占。缓存持有只读副本并必须响应块请求,其他缓存可能有只读副本但非所有者【注不止单V?与前述简单协议不同?V/I,非所有者不需要响应块请求吧】,LLC / 内存中的副本可能过期。
E (xclusive,独占态):块有效、独占、干净。缓存持有只读副本,其他缓存无有效副本,LLC / 内存中的副本为最新【注,由单纯的 load 导致的一种状态】。本指南中,独占态被视为拥有所有权(尽管某些协议不将独占态视为所有权状态)。后续章节介绍 MESI 监听协议和目录协议时,将讨论是否将独占块视为所有者的相关问题。
S (hared,共享态)
I (nvalid,无效态)
图 6.4 以维恩图展示 MOESI 状态的特征归属:除 I 态外均为有效态;M、O、E 态为所有权状态;M 和 E 态表示独占性(其他缓存无有效副本);M 和 O 态表示块可能为脏状态。回顾 6.3 节的简单示例,该协议实际上将 MOES 状态简化为单一 V 态。
尽管 MOESI 状态非常常见,但并非稳定状态的全部可能。例如,F (orward,转发态) 与 O 态类似,但块为干净状态(LLC / 内存中的副本为最新)。一致性状态有多种可能,本指南重点讨论知名的 MOESI 状态。
临时状态
截至目前,我们仅讨论了块无一致性活动时的稳定状态(协议名称通常基于稳定状态,如 “MESI 协议”)。但正如 6.3 节示例所示,从一个稳定状态过渡到另一个稳定状态时可能存在临时状态。在 6.3 节中,IVD 状态(处于 I 态,等待转为 V 态,等待 DataResp 消息)即为临时状态。在更复杂的协议中,可能出现数十种临时状态。临时状态通常用 XYZ 符号表示,其中 X 为源稳定状态,Y 为目标稳定状态,Z 为触发状态转移完成的事件类型。例如,后续章节的协议中,IMD 表示块先前处于 I 态,待 D (ata) 消息到达后将转为 M 态【注,估计发生在写miss】。
LLC / 内存中块的状态
前述状态(稳定态和临时态)均针对缓存中的块。LLC 和内存中的块也有对应状态,通常有两种命名方式(命名惯例不影响功能或性能,但可能使不熟悉的架构师产生困惑):
缓存中心法:这是最常见的方式,LLC / 内存中块的状态是各缓存中该块状态的聚合。例如:
所有缓存中的块均为 I 态 → LLC / 内存状态为 I;一个或多个缓存中的块为 S 态 → LLC / 内存状态为 S;单个缓存中的块为 M 态 → LLC / 内存状态为 M。
内存中心法:LLC / 内存中块的状态对应内存控制器对该块的权限(而非缓存的权限)。例如:所有缓存中的块均为 I 态 → LLC / 内存状态为 O(而非缓存中心法的 I),因 LLC / 内存此时充当块的所有者;一个或多个缓存中的块为 S 态 → LLC / 内存状态仍为 O(同理);单个缓存中的块为 M 或 O 态 → LLC / 内存状态为 I(因 LLC / 内存中的副本无效)。
本指南中的所有协议均对 LLC / 内存中的块状态采用缓存中心法命名。
块状态的维护
系统实现必须维护缓存、LLC 和内存中块的状态。对于缓存和 LLC而言,其中的每个块的状态通常只需扩展几个 bit,因为稳定的状态数量通常比较少(如 MOESI 协议的 5 种状态需 3 bit/块)。缓存一致性协议可能有大量临时状态,但仅需为处于未完成一致性事务的块维护这些状态。实现中通常通过向未命中状态处理寄存器(MSHR)或 用于跟踪未完成事务的类似结构中添加额外位来维护临时状态 [4]。【注,同时出现这些临时状态的块的数量,比较少,没必要每个块都带一个这类结构或寄存器】
对于内存而言,更大的总容量似乎会带来显著挑战。但当前多数多核系统采用包含性LLC设计,这意味着 LLC 会保留系统中所有缓存块的副本(包括"独占"块)。在包含性LLC架构下,内存无需显式维护缓存一致性状态——若某块存在于 LLC 中,其内存状态与 LLC 状态保持一致;若不存在于 LLC 中,则内存中该块状态隐式为无效(因为包含性 LLC 的缺失意味着该块不在任何缓存中)。侧边栏将讨论在多核与包含性 LLC 出现之前的内存状态维护方式。【注,LLC 的意义 见 6.5节】
上述内存讨论基于单颗多核芯片系统(本入门手册主要讨论场景)【注,单路,单 socket】。多芯片系统中,在内存逻辑层面显式维护缓存一致性状态可能更具优势。
6.4.2 事务
大多数缓存一致性协议都包含一组类似的事务,因为一致性控制器的基本目标是相似的。例如,几乎所有协议都有一个用于获取块的共享(只读)访问权限的事务。表6.4 列出了一组常见事务,并针对每个事务描述了发起事务的请求者的目标。这些事务均由缓存控制器响应其关联 core 的请求而发起。表6.5 则列出了 core 可向其缓存控制器发出的请求,以及这些请求如何促使缓存控制器发起缓存一致性事务。
侧边栏:多核时代之前 —— 在内存中维护一致性状态
传统的多核之前协议需要为每个内存块维护一致性状态,且无法像 6.4.1 节所述那样利用 LLC。我们简要讨论几种维护状态的方法及相关工程权衡。
为每个内存块增加状态位。最通用的实现是为每个内存块添加额外位以维护一致性状态。若内存有 N 种可能状态,每个块需要 log2 N。位额外空间。尽管这种设计通用性强且概念简单,但存在几个缺点:成本增加,现代面向块的 DRAM 芯片通常至少 4 位宽(常见更宽),添加 2-3 位额外位存在物理难度。此外,修改内存结构会导致无法使用商用 DRAM 模块(如 DIMM),显著增加成本。幸运的是,对于每个块仅需少量状态位的协议,可通过修改 ECC 码存储这些位 —— 通过在更大粒度(如 512 位而非 64 位)上维护 ECC,可在使用商用 DRAM 模块的同时 “隐藏” 少量额外位 [1,5,7]。延迟问题,在 DRAM 中存储状态位意味着获取状态需承担完整的 DRAM 延迟,即使块的最新版本存储在其他缓存中,这可能增加缓存间一致性传输的延迟。性能影响,状态变更需执行 DRAM 的 “读 - 改 - 写” 周期,可能影响功耗和 DRAM 带宽。
内存中每个块单状态位。Synapse 协议 [3] 采用的设计是使用单个位区分两种稳定状态(I 和 V),临时状态通过小型专用结构维护。这种设计是上述方案的子集,存储成本最低。
零位逻辑或。为避免修改内存,可让缓存按需重构内存状态。内存状态是所有缓存中块状态的函数,因此若所有缓存聚合其状态,即可推断内存状态。系统可通过让所有核心向输入数等于缓存数的逻辑或门(或或门树)发送 “是否拥有?” 信号,推断内存是否为块的所有者:若输出为高,表示某缓存是所有者;若为低,则内存是所有者。此方案无需在内存中维护任何状态,但实现快速或操作(无论是逻辑门还是线或)可能存在难度。
【注,Upgrade 应该是程序中先执行了 load,后来又执行了 write 同一个缓存块中的地址,导致了 upgrade 到RW】
尽管大多数缓存一致性协议使用类似的事务集合,但缓存一致性控制器执行事务的交互方式差异显著。如下一节所述,在某些协议(如监听协议)中,缓存控制器通过向系统中所有一致性控制器广播 GetS 请求发起获取共享事务,当前块所有者的控制器用包含目标数据的消息响应请求者。相反,在其他协议(如目录协议)中,缓存控制器通过向预定义的特定缓存一致性控制器(块的归属节点)单播 GetS 消息发起事务,该控制器可能直接响应或转发请求至其他控制器处理。
6.4.3 协议主要设计选项
缓存一致性协议的设计方式繁多,即使使用相同的状态和事务集合,也可能衍生出多种不同协议。协议设计决定了每个一致性控制器可能的事件和状态转移逻辑 —— 与状态和事务不同,事件和转移无法脱离具体协议单独罗列。
尽管一致性协议的设计空间庞大,但有两个关键设计决策对协议的其他部分有重大影响,我们逐一讨论:
监听协议 vs. 目录协议
一致性协议主要分为两类:监听(snooping)协议和目录(directory)协议。以下先简要概述,第 7 章和第 8 章将分别深入讨论:
监听协议:缓存控制器通过向所有其他一致性控制器广播请求消息发起块请求,各控制器协同 “执行正确操作”(如所有者向请求者发送数据响应)。监听协议依赖互连网络以内存一致顺序向所有核心传递广播消息。大多数监听协议假设请求按全局顺序到达(如通过共享总线),但也可支持更高级的互连网络和宽松顺序。
目录协议:缓存控制器通过向块归属的内存控制器单播请求消息发起块请求,内存控制器维护目录,记录 LLC / 内存中每个块的状态(如当前所有者或共享者列表)。当块请求到达归属节点时,内存控制器查询目录状态:若为 GetS 请求,目录状态可确定所有者 —— 若 LLC / 内存是所有者,直接向请求者发送数据响应;若某缓存控制器是所有者,则将请求转发至该控制器,由其响应请求者。
选择 snooping 还是 directory,需要做一些设计权衡。监听协议逻辑简单,但广播机制难以扩展至大规模核心;目录协议通过单播实现可扩展性,但当归属节点非所有者时,事务需额外消息转发,延迟更高;协议选择影响互连网络设计(如传统监听协议要求请求消息全局有序)。
无效化 vs. 更新
缓存一致性协议的另一关键设计决策是处理核心写操作的方式,该决策与协议类型(监听或目录)无关,有如下两种选择。
无效式协议:核心写块时,发起缓存一致性事务使所有其他缓存中的副本无效。副本无效后,请求者可安全写入,避免其他核心读取旧值。若其他核心后续需读取该块,必须发起新事务获取最新副本,从而维持一致性。
更新式协议:核心写块时,发起事务将所有其他缓存中的副本更新为新值。此方案减少了核心读取新写块的延迟(无需等待 GetS 事务完成),但通常比无效化协议消耗更多带宽(更新消息需包含地址和新值,而非仅地址)。此外,更新协议使内存一致性模型的实现大幅复杂化 —— 例如,当多个缓存需对同一块的多个副本执行更新时,维持写原子性(5.5 节)变得极为困难。由于复杂性高,更新协议极少实现,本指南重点讨论更常见的无效化协议。
混合设计
上述两类设计决策均存在混合方案。监听 - 目录混合协议[2,6] 结合两者特性,例如在小规模集群内使用监听,跨集群使用目录;无效化 - 更新混合协议[8] 在部分场景使用更新式(如近邻缓存)以减少延迟,其他场景使用无效式以降低带宽消耗。一致性协议的设计空间丰富多样,架构师无需局限于特定设计风格。
6.5 翻译补充:注解 LLC 的架构意义
LLC(Last-Level Cache,末级缓存)在现代多核处理器系统中具有关键作用,其引入主要带来以下核心意义:
6.5.1. 降低平均内存访问延迟
缓存层级优化:作为所有核心共享的最后一级缓存,LLC 弥补了私有缓存(L1/L2)容量不足的缺陷,减少核心直接访问主内存的频率。
数据局部性利用:通过存储频繁访问的数据块,缩短核心的访存路径,显著降低由内存墙(Memory Wall)带来的性能损失。
6.5.2. 提升系统吞吐量与能效
减少片外通信:LLC 的命中可避免高能耗的片外内存访问(DRAM),降低功耗并提升能效比(尤其对移动/服务器芯片至关重要)。
资源共享:多核竞争内存带宽时,LLC 作为缓冲区可缓解带宽压力,提高整体吞吐量。
6.5.3. 简化一致性协议实现
包含性缓存(Inclusive LLC)设计:
状态集中管理:LLC 维护所有核心私有缓存中块的副本,使得内存控制器无需单独跟踪缓存状态(如MOESI协议中,内存只需依赖LLC状态即可判断块是否有效)。
一致性效率提升:侦听(Snooping)或目录(Directory)协议可通过LLC快速定位数据所有者,减少一致性事务的复杂度(例如广播请求范围缩小)。
6.5.4. 支持异构计算与数据共享
多核/多线程协同:LLC 作为共享存储层,便于不同核心间高效共享数据(如生产者-消费者模型),减少私有缓存间的冗余复制。
异构加速器集成:GPU/FPGA等加速器可通过LLC与CPU核心交换数据,避免直接访问主存带来的延迟。
6.5.5. 优化内存访问模式
预取与缓存替换策略:LLC 可采用更智能的预取算法(如空间预取)和替换策略(如动态分区),适应多核工作负载的多样性。
NUMA架构支持:在多插槽系统中,LLC 可减少跨NUMA节点的远程内存访问。
6.5.6. 增强可扩展性
缓解一致性风暴:随着核心数增加,LLC 作为集中式或分布式共享层,能有效过滤大量核心间的缓存一致性请求(尤其在目录协议中作为中间节点)。
设计权衡与挑战
面积与功耗:LLC 通常占用较大芯片面积(如现代CPU中可达数十MB),需在容量与功耗间平衡。
包含性策略选择:非包含性(Non-inclusive)或独占性(Exclusive)LLC 可能更适合特定场景(如低延迟敏感型应用)。
6.5.7 LLC 应用实例
Intel Smart Cache:多核CPU共享LLC,支持动态分配缓存空间给高优先级核心。
AMD Zen架构:采用多CCX模块设计,每个CCX包含共享LLC以优化核心间通信。
LLC 的引入本质上是权衡“速度-容量-功耗-缓存一致性”后的系统级优化,是多核时代不可或缺的设计要素。
6.6 翻译补充:AMD GPU 系统中的缓存一致性协议
AMD GPU 系统中的缓存一致性协议通常采用 基于目录(Directory-based) 的协议,而非侦听(Snooping)协议。以下是详细分析和验证方法:
6.6.1. 为什么 AMD GPU 更可能使用 Directory 协议?
(1) 可扩展性需求
GPU 通常包含大量计算单元(CU/SIMD核心),核心数量远超 CPU(如 RDNA3 架构可达数千个线程并行)。
Snooping 协议 需要广播请求,在 GPU 高并行场景下会导致严重的带宽竞争和延迟问题,而 Directory 协议通过点对点通信 更适应大规模核心扩展。
(2) 内存层次结构
AMD GPU 采用 异构内存系统(如 HBM/GDDR + 多级缓存),且 GPU 的 L2 Cache 通常作为全局共享缓存(类比 LLC)。
Directory 协议天然适合 非均匀内存访问(NUMA) 和 分布式缓存 的场景(如 CDNA 架构的 Infinity Fabric 互联)。
(3) 官方文献与专利佐证
AMD 在技术文档(如 CDNA 白皮书)中提到使用 基于代理(Proxy)的一致性管理,这是 Directory 协议的典型特征。
专利(如 US20210389821A1)显示 AMD 使用 分布式目录 跟踪缓存行状态,减少广播开销。
6.6.2. 验证方法
(1) 硬件性能特征分析
带宽敏感度测试:
若协议为 Snooping,增加核心数会显著提升总线带宽压力(广播风暴)。
若为 Directory,带宽增长相对平缓(仅目录节点参与通信)。
方法:通过微基准测试(如并发原子操作)观察带宽随核心数的变化曲线。
延迟测试:
Directory 协议在远程访问时延迟较高(需查询目录),而 Snooping 的延迟相对均匀。
方法:测量不同核心间数据共享的延迟分布(如使用 rdtsc 指令)。
(2) 架构文档与工具
ROCm 工具链:AMD 的 ROCm 开源工具(如 rocprofiler)可追踪缓存一致性事务,分析消息模式(广播 vs 点对点)。
LLC 缺失率监控:通过性能计数器(如 l2_cache_misses)观察一致性事务的触发条件。
(3) 逆向工程(高级方法)
指令集分析:检查 GPU 指令集中是否包含显式的目录管理指令(如 FLUSH_OWNER 类操作)。
硅片显微成像:通过物理层分析(如芯片延迟扫描)定位目录结构的存在(需专业设备)。
(4) 对比已知设计
NVIDIA GPU 公开使用 MOESI + Directory(如 Volta 架构),AMD 作为主要竞争对手,大概率采用类似方案。
CPU-GPU 一致性(如 AMD 的 hUMA)也依赖目录协议(如 Infinity Fabric 的全局地址空间管理)。
6.6.3. 例外情况
小规模 GPU:低端 GPU(如部分移动端 RDNA2)可能简化设计,使用类 Snooping 的轻量协议。
特定工作负载优化:部分计算任务可能绕过一致性协议(如局部性极强的图形渲染)。
但是,AMD GPU 主要使用 基于目录的一致性协议,验证需结合性能测试、官方文档和工具链分析。其设计选择反映了 GPU 对可扩展性和带宽效率的核心需求。