可以在以下位置找到摘要和其他讨论:L1 caches usually have split design, but L2, L3 caches have unified design, why?。
简介
拆分缓存是由两个物理上分开部分组成的缓存,其中一个称为指令缓存,专用于保存指令,另一个称为数据缓存,专用于保存指令。保存数据(即指令存储器操作数)。指令缓存和数据缓存都在逻辑上被认为是单个缓存,被描述为拆分缓存,因为它们都是相同物理地址空间的硬件管理缓存,位于内存的同一级别等级制度。取指请求仅由指令高速缓存处理,内存操作数读取和写入请求仅由数据高速缓存处理。未拆分的缓存称为统一缓存。
Harvard 与 von Neumann 架构的区别最初适用于主内存。然而,大多数现代计算机系统都实现了modified Harvard architecture,其中 L1 缓存实现了哈佛架构,而内存层次结构的其余部分实现了冯诺依曼架构。因此,在现代系统中,哈佛与冯诺依曼的区别主要适用于 L1 缓存设计。这就是为什么拆分缓存设计也称为哈佛缓存设计,统一缓存设计也称为冯诺依曼的原因。修改后的哈佛架构的维基百科文章讨论了three variants of the architecture,其中一个是拆分缓存设计。
据我所知,拆分缓存设计的想法最早是由 James Bell、David Casasent 和 C. Cordon Bell 在其题为 An Investigation of Alternative Cache Organizations 的论文中提出并评估的,该论文于 1974 年发表在 IEEE TC 期刊 ( IEEE version 更清楚一些)。作者使用模拟器发现,对于研究中考虑的几乎所有缓存容量,均等拆分会产生最佳性能(参见图 5)。来自论文:
通常,最好的性能出现在一半的缓存专用
用于指令,一半用于数据。
他们还提供了与相同容量的统一缓存设计的比较,他们最初的结论是拆分设计与统一设计相比没有优势。
如图6所示,最佳专用缓存CUXD的性能
(一半分配给指令,一半分配给数据)一般来说是相当的
类似于同构缓存(CUX);额外的复杂性
因此,专用的缓存控制是不合理的。
实际上我并不清楚该论文是否评估了拆分设计或在指令和数据之间进行分区的缓存。有一段说:
到目前为止,缓存内存被假定为由
均质细胞。但可以想象,一个功能专业的
缓存的分区可以提供更高的性能。例如,
也许一个缓存正好一半用于指令,一半用于数据
会比同质的更有效;或者,一个
仅持有指令可能比仅持有指令更好
数据。为了检验这些假设,将缓存划分为
专门针对特定用途的部分进行了调查。
(此段落由https://www.textfixer.com/tools/remove-white-spaces.php自动格式化。)
在我看来,作者们正在谈论拆分和分区设计。但目前尚不清楚模拟器中实现了哪些设计以及如何配置模拟器进行评估。
请注意,论文没有讨论为什么拆分设计可能比统一设计具有更好或更差的性能。还要注意作者如何使用术语“专用缓存”和“同构缓存”。 “分裂”和“统一”这两个词出现在后来的作品中,我相信这是艾伦·杰伊·史密斯在 1978 年在Directions for memory hierarchies and their components: research and development 中首次使用的。但我不确定,因为艾伦使用这些词的方式给人的印象是它们是已经众所周知。在 Alan 的论文中,我认为第一个使用拆分缓存设计的处理器是 1975 年左右的IBM 801,而第二个处理器可能是S-1(大约在 1976 年左右)。这些处理器的工程师可能独立提出了拆分设计的想法。
拆分缓存设计的优点
在接下来的二十年里,拆分缓存设计得到了广泛的研究。例如,参见this 极具影响力的论文的第 2.8 节。但很快就认识到,分离设计对于指令提取单元和内存访问单元物理位于芯片不同部分的流水线处理器很有用。采用统一设计,不可能同时靠近取指单元和内存单元放置高速缓存,导致一个或两个单元的高速缓存访问延迟很高。拆分设计使我们能够将指令高速缓存放置在靠近取指单元的位置,将数据高速缓存放置在靠近内存单元的位置,从而同时减少两者的延迟。 (参见this 文档的图 3 中 S-1 处理器的外观。)这是分体式设计相对于统一设计的主要优势。这也是两者之间的关键区别拆分设计和支持缓存分区的统一设计。这就是为什么需要拆分数据缓存的原因,正如一些研究工作中提出的那样,例如Cache resident data locality analysis 和Partitioned first-level cache design for clustered microarchitectures。
拆分设计的另一个优点是它允许指令和数据访问并行发生而不会发生争用。本质上,拆分缓存的带宽是统一缓存的两倍。这提高了流水线处理器的性能,因为指令和数据访问可以在流水线的不同阶段的同一周期中发生。或者,可以使用多个访问端口或多个存储体将统一高速缓存的带宽加倍或提高。实际上,使用两个端口为整个缓存提供了两倍的带宽(相比之下,在拆分设计中,带宽在指令缓存和数据缓存之间分成了一半),但是添加了另一个端口在面积和功率方面更昂贵,并且可能会影响延迟。提高带宽的第三种方法是向同一端口添加更多线路,以便可以在同一周期内访问更多位,但这可能仅限于同一高速缓存行(与其他两种方法相反)。如果缓存是片外的,那么将它连接到流水线的导线就变成了引脚,并且导线数量对面积、功率和延迟的影响变得更加显着。
此外,使用统一 (L1) 高速缓存的处理器通常包含仲裁逻辑,该逻辑将数据访问优先于指令访问;这种逻辑可以在拆分设计中消除。 (有关避免仲裁的统一设计,请参阅下面关于 Z80000 处理器的讨论。)类似地,如果有另一个缓存级别实现统一设计,则需要在 L2 统一缓存处设置仲裁逻辑。简单的仲裁策略可能会降低性能,而更好的策略可能会增加面积。 [TODO:添加策略示例。]
另一个潜在的优势是拆分设计允许我们对指令缓存和数据缓存采用不同的替换策略,这可能更适合每个缓存的访问模式。所有 Intel Itanium 处理器都使用 L1I 的 LRU 策略和 L1D 的 NRU 策略(我确定这适用于 Itanium 2 及更高版本,但我不确定第一个 Itanium)。此外,从 Itanium 9500 开始,L1 ITLB 使用 NRU,而 L1 DTLB 使用 LRU。英特尔没有透露他们为什么决定在这些处理器中使用不同的更换政策。一般来说,在我看来,L1I 和 L1D 使用不同的替换策略并不常见。我找不到一篇关于此的研究论文(所有关于替换策略的论文都只关注数据或统一缓存)。即使对于统一高速缓存,替换策略也可能有助于区分指令行和数据行。在拆分设计中,提取到数据高速缓存中的高速缓存行永远不会取代指令高速缓存中的行。类似地,填充到指令缓存中的行永远不会取代数据缓存中的行。但是,统一设计中可能会出现此问题。
section 在维基百科文章中关于修改后的哈佛架构与哈佛和冯诺依曼之间的差异的最后小节提到,Mark I 机器对指令和数据存储器使用不同的存储器技术。这让我想到这是否可以构成现代计算机系统中拆分设计的优势。以下是一些证明确实如此的论文:
所以我认为我们可以说拆分设计的一个优点是我们可以将不同的内存技术用于指令和数据缓存。
还有另外两个优点,稍后会在本答案中讨论。
拆分缓存设计的缺点
不过,分体式设计有其问题。首先,指令和数据高速缓存的组合空间可能没有得到有效利用。包含指令和数据的高速缓存行可能同时存在于两个高速缓存中。相比之下,在统一缓存中,缓存中仅存在行的单个副本。此外,指令高速缓存和/或数据高速缓存的大小对于所有应用程序或同一应用程序的不同阶段可能不是最佳的。模拟表明,总大小相同的统一缓存具有更高的命中率(参见后面讨论的 VSC 论文)。 这是拆分设计的主要缺点。(如果拆分设计中存在单个缓存集上的放置争用,则在统一设计中仍可能发生这种争用,并且可能会产生更严重的影响在性能方面。在这种情况下,拆分设计的整体未命中率会更低。)
其次,自修改代码会导致需要在微架构级别和/或软件级别考虑的一致性问题。 (可能允许两个高速缓存之间在少量周期内出现不一致,但如果 ISA 不允许观察到这种不一致,则必须在被修改的指令永久更改架构状态之前检测到它们。) 维护指令一致性需要更多的逻辑,并且在拆分设计中比统一设计具有更高的性能影响。
第三,与具有相同整体组织参数的单端口统一缓存、完全双端口统一缓存和双端口分组缓存相比,拆分缓存的设计和硬件复杂性是一个重要的考虑因素。根据CACTI 3.0: An Integrated Cache Timing, Power, and Area Model提出的缓存区域模型,全双端口设计的区域最大。无论两个端口的类型如何(独占读取、独占写入、读/写),这都是正确的。双端口分组缓存比单端口统一缓存具有更大的面积。这两个与拆分相比如何对我来说不太明显。我的理解是分体式设计比单口统一设计的面积要大【TODO: Explain why】。考虑缓存组织细节、缓存总线到流水线的长度以及处理技术可能很重要。这里需要注意的一点是,单端口指令缓存的缓存比单端口数据缓存或统一缓存低,因为指令缓存只需要一个独占读取端口,而其他指令缓存需要一个读/写端口。
真实处理器中的统一 L1 和拆分 L2 缓存
我不知道在过去 15 年中设计的任何处理器具有统一 (L1) 缓存。在现代处理器中,统一设计主要用于更高编号的缓存级别,这是有道理的,因为它们不直接连接到管道。 Intel Itanium 2 9000 处理器是 L2 高速缓存遵循拆分设计的一个有趣示例。该处理器具有 3 级缓存层次结构,其中 L1 和 L2 缓存都被拆分并为每个内核私有,而 L3 缓存统一并在所有内核之间共享。 L2D 和 L2I 缓存的大小分别为 256 KB 和 1 MB。后来的 Itanium 处理器将 L2I 大小减少到 512 KB。 Itanium 2 9000 手册解释了为什么要拆分 L2:
单独的指令和数据 L2 缓存提供更高效
与 Itanium 2 处理器相比,访问缓存
指令请求将与 L2 的数据访问竞争
针对数据访问的带宽并可能影响核心执行
以及 L2 吞吐量。
。
.
.
L3 接收来自两个
L2I 和 L2D,但在极少数情况下优先考虑 L2I 请求
冲突。从 Itanium 中的 L1-L2 移动仲裁点
2 处理器到 L2-L3 缓存大大减少了冲突,这要归功于
L2的命中率高。
(我认为“反对数据访问”被错误地写了两次。)
那句话的第二段提到了我之前错过的一个优势。拆分 L2 缓存将数据指令冲突点从 L2 移动到 L3。此外,在 L1 缓存中未命中的一些/许多请求可能会在 L2 中命中,从而降低 L3 争用的可能性。
顺便说一句,Itanium 2 9000 中的 L2I 和 L2D 都使用 NRU 更换策略。
统一的 L1 缓存分区
詹姆斯·贝尔等人。在他们 1974 年的论文中提到了在指令和数据之间划分统一缓存的想法。我所知道的唯一一篇提出并评估了这种设计的论文是Virtually Split Cache: An Efficient Mechanism to Distribute Instructions and Data,它发表于 2013 年。拆分设计的主要缺点是其中一个 L1 缓存可能未得到充分利用,而另一个可能会过度使用-利用。拆分缓存不允许一个缓存在需要时从另一个缓存中占用空间。这就是为什么统一设计的 L1 未命中率低于拆分缓存的总体未命中率的原因(如论文使用仿真所示)。然而,较高的延迟和较低的未命中率对性能的综合影响仍然使具有统一 L1 缓存的系统比具有拆分缓存的系统慢。
虚拟拆分缓存 (VSC) 设计是拆分和统一设计之间的中间点。 VSC 根据需求在指令和数据之间动态划分(方式)L1 高速缓存。这可以更好地利用 L1 缓存,类似于统一设计。然而,VSC 甚至具有很低的未命中率,因为分区减少了行保存和指令与保存数据的行之间的潜在空间冲突。根据实验结果(所有缓存设计的整体容量相同),即使VSC与统一缓存有相同的延迟,VSC在单核系统上的性能与分体式设计大致相同,并且具有更高的性能。多核系统上的性能,因为较低的未命中率导致访问共享 L2 缓存的争用较少。此外,在单核和多核系统配置中,VSC 由于较低的未命中率而降低了能耗。
VSC 的延迟可能低于统一缓存。虽然两者都是双端口的(与单端口拆分缓存具有相同的带宽),但在 VSC 设计中,只需要对接口进行双端口,因为缓存的任何部分都不能同时访问一次以上。 (论文并没有明确说明,但我认为 VSC 允许同一行存在于两个分区中,如果它同时保存指令和数据,因此它仍然存在拆分设计中存在的一致性问题。)假设缓存的每个bank代表一个缓存方式,那么每个bank在VSC中可以是单端口的。这导致了更简单的设计(请参阅:Fast quadratic increase of multiport-storage-cell area with port number)并可能允许减少延迟。此外,假设统一设计和拆分设计之间的延迟差异很小(因为拆分设计中的指令缓存和数据缓存在物理上彼此靠近),VSC 设计可以将指令和数据存储在物理上接近管道中需要它们的位置,并支持可变延迟访问,具体取决于为每个分配的银行数量。银行数量越多,延迟越高,直至统一设计的延迟。然而,这需要一种能够处理这种可变延迟缓存的管道设计。
我认为本文缺少的一件重要事情是评估具有更高访问延迟的 VSC 设计相对于拆分设计(不仅仅是 2 个周期与 3 个周期)。我认为即使只增加一个周期的延迟也会使 VSC 比拆分慢。
Z80000统一缓存案例
Zilog Z80000 处理器具有标量 6 级流水线,带有片上单端口统一缓存。高速缓存是 16 路完全关联和扇区化的。流水线的每个阶段至少需要两个时钟周期(缓存中未命中的加载和其他复杂指令可能需要更多周期)。每对连续的时钟周期构成一个处理器周期。 Z80000 的缓存设计具有许多我在其他任何地方都没有见过的独特属性:
- 在一个处理器周期内最多可以进行两次高速缓存访问,包括最多一次取指和一次数据访问。然而,尽管高速缓存是统一的和单端口的,但它的设计方式是在取指和数据访问之间没有争用。统一高速缓存具有单个时钟周期(等于半个处理器周期)的访问延迟。在每个处理器周期中,在第一个时钟周期中执行指令提取,在第二个时钟周期中执行数据访问。在这种情况下,拆分缓存没有延迟优势,对缓存的时分复用访问提供了相同的带宽,而且拆分设计的缺点也不存在。完整的关联性最大限度地减少了指令和数据线之间的空间争用。这种设计得益于较小的缓存大小和相对于缓存延迟相对较浅的流水线。
- 系统配置控制长字 (SCCL) 提供高速缓存指令 (CI) 和高速缓存数据 (CD) 控制位。如果 CI 为 1,则缓存中未命中的指令获取可以填充到缓存中。如果 CD 为 1,则缓存中未命中的数据加载可以填充到缓存中。缓存使用 write-no-allocate 策略,因此写入未命中永远不会在缓存中分配。如果 CI 和 CD 都设置为 1,则缓存有效地像统一缓存一样工作。如果只有一个标志为 1,则高速缓存有效地像仅数据或仅指令高速缓存一样工作。应用程序可以调整这些标志以提高性能。
- 此属性与问题无关,但我发现它很有趣。 SCCL 还提供高速缓存替换 (CR) 控制位。将此位设置为零将禁用未命中时的替换,因此永远不会替换行。如果集合中的所有条目都被占用,并且该集合中发生加载/提取未命中,则该行根本没有填充到缓存中。
R3000、80486、Pentium P5的案例
我在 SE Retrocomputing 上遇到了以下补充问题:Why did Intel abandon unified CPU cache?。关于该问题的公认答案存在许多问题。我将在这里解决这些问题,并解释为什么 80486 和 Pentium 缓存是根据 Intel 提供的信息设计的。
80386 确实有一个带有外部统一缓存的外部缓存控制器。然而,仅仅因为缓存是外部的并不一定意味着它很可能是统一的。考虑 R3000 处理器,它在 80386 三年后发布,与 80486 属于同一代。根据@987654346 的第 1.8 节,R3000 的设计者选择了大型外部缓存而不是小型片上缓存来提高性能@。 R3000 Software Reference Manual 第 1 章的第一节说,外部缓存使用拆分设计,以便它可以在同一“时钟相位”中执行取指和读取或写入数据访问。我不清楚这到底是如何工作的。我的理解是外部数据和地址总线在两个缓存之间共享,并且也与内存共享。 (另外,一些地址线用于为片上缓存控制器提供缓存行标签以进行标签匹配。)两个缓存都是直接映射的,可能是为了实现单周期访问延迟。具有相同带宽、关联性和容量的统一外部缓存设计要求缓存完全双端口,或者可以使用 VSC 设计,但 VSC 是在多年后发明的。这样一个统一的缓存会更昂贵,并且可能具有比保持流水线充满指令所需的单个周期更大的延迟。
Retro 的链接答案的另一个问题是,仅仅因为 80486 直接从 80386 演变而来并不一定意味着它也使用了统一设计。根据题为The i486 CPU: executing instructions in one clock cycle 的英特尔论文,英特尔评估了这两种设计,并特意选择了统一的片上设计。与同代 R3000 相比,两款处理器的频率范围相近,两款处理器的片外数据宽度均为 32 位。但是,80486 的统一缓存远小于 R3000 的总缓存容量(最高 16KB 对最高 256KB+256KB)。另一方面,片上使 80486 具有更宽的缓存总线更可行。具体来说,80486 高速缓存有一个 16 字节的指令提取总线、一个 4 字节的数据加载总线和一个 4 字节的数据加载/存储总线。两条数据总线可以同时用于在一次访问中加载单个 8 字节操作数(双精度 FP 操作数或段 desc)。 R3000 高速缓存共享一个 4 字节总线。 80486 缓存的相对较小的尺寸可能允许使其具有单周期延迟的 4 路关联。这意味着命中高速缓存的加载指令可以在下一个周期将数据提供给相关指令,而不会出现任何停顿。在 R3000 上,如果一条指令依赖于紧接在前的加载指令,在缓存命中的最佳情况下,它必须停顿一个周期。
80486 高速缓存是单端口的,但指令预取缓冲区和宽 16 字节指令取指总线有助于将指令取指和数据访问之间的争用降至最低。英特尔提到,仿真结果表明,统一设计提供的命中率高于拆分缓存,足以弥补带宽争用。
英特尔在另一篇名为Design of the Intel Pentium processor 的论文中解释了为什么他们决定将 Pentium 中的缓存更改为拆分。有两个原因:(1) 2 宽的超标量 Pentium 需要能够在单个周期内执行最多两次数据访问,以及 (2) 分支预测增加了缓存带宽需求。这篇论文没有提到英特尔是否考虑过使用三端口分组统一缓存,但他们可能确实考虑过,但当时发现它不可行,因此他们选择了带有双端口 8 分组数据缓存的拆分缓存和一个单端口指令缓存。以今天的晶圆厂技术,三端口统一设计可能会更好
后来的微架构中更宽的管道要求数据缓存具有更高的并行度。现在我们位于 Sunny Cove 的 4 个 64 字节端口。
回答问题的第二部分
有人提到缓存是一个拆分缓存,没有什么危险
这到底是什么意思?
这可能与保罗评论中提到的结构性危险有关。也就是当时的取指单元和内存单元不能访问统一的单端口缓存。