'Split' 缓存是什么意思。它有什么用(如果有用的话)?

What does a 'Split' cache means. And how is it useful(if it is)?

我在做一个关于计算机体系结构的问题,其中提到缓存是一个拆分缓存,没有危险这到底是什么意思?

可以在以下位置找到摘要和附加讨论:L1 caches usually have split design, but L2, L3 caches have unified design, why?

简介

拆分缓存是由两个物理上分开的部分组成的缓存,其中一部分称为指令缓存,专用于保存指令,另一部分称为数据缓存,专用于保存数据(即指令内存操作数)。指令缓存和数据缓存都在逻辑上被认为是一个缓存,描述为分离缓存,因为两者都是hardware-managed相同物理地址的缓存space 在内存层次结构的同一级别。取指令请求仅由指令缓存处理,内存操作数读写请求仅由数据缓存处理。不拆分的缓存称为统一缓存。

Harvard vs. von Neumann architecture distinction originally applies to main memory. However, most modern computer systems implement the modified Harvard architecture whereby the L1 cache implements the Harvard architecture and the rest of the memory hierarchy implements the von Neumann architecture. Therefore, in modern systems, the Harvard vs. von Neumann distinction mostly applies to the L1 cache design. That's why the split cache design is also called the Harvard cache design and the unified cache design is also called von Neumann. The Wikipedia article on the modified Harvard architecture discusses three variants of the architecture,其中一个是split cache设计

据我所知,split cache 设计的思想最早是由 James Bell、David Casasent 和 C. Cordon Bell 在他们题为 An Investigation of Alternative Cache Organizations, which was published in 1974 in the IEEE TC journal (the IEEE version 的论文中提出并评估的,比较清晰)。作者发现,使用模拟器,对于研究中考虑的几乎所有缓存容量,均等分割会产生最佳性能(参见图 5)。来自论文:

Typically, the best performance occurs with half of the cache devoted to instructions and half to data.

他们还提供了与相同容量的统一缓存设计的比较,他们的初步结论是分离设计与统一设计相比没有优势。

As shown in Fig. 6, the performance of the best dedicated cache CUXD (half allotted to instructions and half to data) in general is quite similar to that of a homogeneous cache (CUX); the extra complexity of a dedicated cache control is thus not justifiable.

实际上我不清楚这篇论文评估的是拆分设计还是在指令和数据之间分区的缓存。一段说:

Thus far, the cache memory has been assumed to be composed of homogeneous cells. But conceivably a functionally specialized partitioning of the cache could give higher performance. For example, perhaps a cache devoted exactly half to instructions and half to data would be more effective than a homogeneous one; alternatively, one that holds just instructions could be better than one holding just data. To test these hypotheses, the effects of dividing the cache into sections dedicated to specific uses were investigated.

(本段由https://www.textfixer.com/tools/remove-white-spaces.php自动格式化)

在我看来,作者正在谈论拆分和分区设计。但不清楚模拟器中实现了什么设计以及模拟器是如何配置评估的。

请注意,本文没有讨论为什么拆分设计可能比统一设计具有更好或更差的性能。还要注意作者如何使用术语“专用缓存”和“同类缓存”。 “分裂”和“统一”这两个词出现在后来的作品中,我相信这是艾伦·杰伊·史密斯在 Directions for memory hierarchies and their components: research and development in 1978. But I'm not sure because the way Alan used these terms gives the impression that they are already well-known. It appears to me from Alan's paper that the first processor that used the split cache design was the IBM 801 around 1975 and probably the second processor was the S-1(1976 年左右)中首先使用的。有可能是这些处理器的工程师独立提出了分体式的设计思路。

拆分缓存设计的优势

在接下来的二十年里,拆分缓存设计被广泛研究。例如,参见 this highly influential paper. But it was quickly recognized that the split design is useful for pipelined processors where the instruction fetch unit and the memory access unit are physically located in different parts of the chip. With the unified design, it is impossible to place the cache simultaneously close to the instruction fetch unit and the memory unit, resulting in high cache access latency from one or both units. The split design enables us to place the instruction cache close to the instruction fetch unit and the data cache close to the memory unit, thereby simultaneously reducing the latencies of both. (See what it looks like in the S-1 processor in Figure 3 of this document.) This is the primary advantage of the split design over the unified design. This is also the crucial difference between the split design and the unified design that supports cache partitioning. That's why it makes to have a split data cache, as proposed in several research works, such as Cache resident data locality analysis and Partitioned first-level cache design for clustered microarchitectures.

的第 2.8 节

拆分设计的另一个优点是它允许指令和数据访问并行发生而不会发生争用。本质上,拆分缓存的带宽可以是统一缓存的两倍。这提高了流水线处理器的性能,因为指令和数据访问可以发生在流水线不同阶段的同一周期中。或者,可以使用多个访问端口或多个存储体将统一缓存的带宽加倍或提高。事实上,使用两个端口可为 整个缓存 提供两倍的带宽(相比之下,在拆分设计中,带宽在指令缓存和数据缓存之间被分成两半),但是添加另一个端口在面积和功率方面的成本更高,并且可能会影响延迟。提高带宽的第三种替代方法是向同一端口添加更多线路,以便在同一周期内可以访问更多位,但这可能仅限于同一缓存行(与其他两种方法相反)。如果缓存是 off-chip,那么将它连接到管道的电线就变成了引脚,电线数量对面积、功耗和延迟的影响就变得更加显着。

此外,使用统一 (L1) 高速缓存的处理器通常包含仲裁逻辑,该逻辑将数据访问的优先级置于指令访问之上;这种逻辑可以在拆分设计中消除。 (避免仲裁的统一设计参见下面关于Z80000处理器的讨论。)同样,如果有另一个缓存级别实现统一设计,那么L2统一缓存将需要一个仲裁逻辑。简单的仲裁策略可能会降低性能,更好的策略可能会增加面积。 [TODO:添加策略示例。]

另一个潜在的优势是,分体设计允许我们对指令缓存和数据缓存采用不同的替换策略,这可能更适合每个缓存的访问模式。所有 Intel Itanium 处理器都对 L1I 使用 LRU 策略,对 L1D 使用 NRU 策略(我确信这适用于 Itanium 2 及更高版本,但我不确定第一个 Itanium)。此外,从 Itanium 9500 开始,L1 ITLB 使用 NRU,而 L1 DTLB 使用 LRU。英特尔没有透露他们为什么决定在这些产品中使用不同的更换政策处理器。一般来说,在我看来,L1I 和 L1D 使用不同的替换策略并不常见。我找不到这方面的研究论文(所有关于替换策略的论文都只关注数据或统一缓存)。即使对于统一缓存,区分指令行和数据行对于替换策略也是有用的。在拆分设计中,提取到数据缓存中的缓存行永远不会取代指令缓存中的行。类似地,填充到指令高速缓存中的一行永远不能取代数据高速缓存中的一行。但是,统一设计中可能会出现此问题。

section的最后sub-section维基百科文章中关于修改后的哈佛架构与哈佛和冯诺依曼之间的差异提到Mark I机器使用不同的内存技术进行指令和数据存储器。这让我思考这是否可以构成现代计算机系统中拆分设计的优势。以下是一些表明情况确实如此的论文:

  • LASIC: Loop-Aware Sleepy Instruction Caches Based on STT-RAM Technology:指令缓存大部分是read-only,除非有未命中,在这种情况下必须取行并填充到缓存中。这意味着,当使用 STT-RAM(或任何其他 NVRAM 技术)时,与对数据缓存使用 STT-RAM 相比,昂贵的写入操作发生的频率较低。该论文表明,通过使用 SRAM 循环缓存(如 Intel 处理器中的 LSD)和 STT-RAM 指令缓存,可以显着降低能耗,尤其是在执行完全适合循环缓存的循环时。 STT-RAM 的 non-volatile 属性 使作者能够完全 power-gate 指令缓存而不丢失其内容。相比之下,使用 SRAM 指令缓存,静态能量消耗要大得多,并且 power-gating 会导致其内容丢失。然而,所提出的设计存在性能损失(与纯 SRAM 缓存层次结构相比)。
  • Feasibility exploration of NVM based I-cache through MSHR enhancements:本文还提出指令缓存使用STT-RAM,而数据缓存和二级缓存仍然基于SRAM。这里没有循环缓存。相反,本文针对 STT-RAM 的高写入延迟问题,这是在缓存中填充一行时引起的。这个想法是,当从 L2 缓存接收到请求的行时,L1 缓存首先在为其请求分配的 MSHR 中缓冲该行。 MSHR 仍然是 SRAM-based。然后指令高速缓存行可以直接从 MSHR 送入流水线,而不必潜在地停止,直到它被写入 STT-RAM 高速缓存。与之前的工作类似,所提出的架构以降低性能为代价提高了能耗。
  • System level exploration of a STT-MRAM based level 1 data-cache:建议对 L1 数据缓存使用 STT-RAM,同时保留所有其他缓存 SRAM-based。这减少了面积开销和能源消耗,但性能受到影响。
  • Loop optimization in presence of STT-MRAM caches: A study of performance-energy tradeoffs:比较纯(仅SRAM或仅STT-RAM)和混合(L2和指令缓存基于STT-RAM)层次结构的能耗和性能。混合缓存层次结构是介于纯 SRAM 和纯 STT-RAM 层次结构之间的 performance-energy 权衡。

所以我认为我们可以说拆分设计的一个优点是我们可以为指令和数据缓存使用不同的内存技术。

还有另外两个优点,将在本回答后面讨论。

拆分缓存设计的缺点

不过,拆分设计有其问题。首先,指令和数据高速缓存的组合 space 可能没有得到有效利用。包含指令和数据的缓存行可能同时存在于两个缓存中。相反,在统一缓存中,缓存中只会存在该行的一个副本。此外,指令缓存 and/or 数据缓存的大小对于所有应用程序或同一应用程序的不同阶段可能不是最佳的。仿真表明,相同总大小的统一缓存具有更高的命中率(参见后面讨论的 VSC 论文)。 这是拆分设计的主要缺点。(如果在拆分设计中存在对单个缓存集的放置争用,则这种争用在统一设计中仍可能发生,并且可能有对性能的影响更差。在这种情况下,拆分设计的整体未命中率会更低。)

其次,self-modifying代码导致的一致性问题需要在microarchitecture-leveland/orsoftware-level处考虑。 (在少量周期内两个高速缓存之间可能允许不一致,但如果 ISA 不允许观察到此类不一致,则必须在被修改的指令永久更改体系结构状态之前检测到它们。)维护指令一致性需要更多逻辑并且在 spli 中具有更高的性能影响比统一的设计。

第三,拆分缓存的设计和硬件复杂性与 single-ported 统一缓存、完全 dual-ported 统一缓存和同一整体组织的 dual-ported 银行缓存相比参数是一个重要的考虑因素。根据CACTI 3.0: An Integrated Cache Timing, Power, and Area Model提出的缓存区模型,fullydual-ported的设计面积最大。这与两个端口的类型无关(exclusive-read、exclusive-write、read/write)。 dual-ported 分库缓存比 single-ported 统一缓存有更大的面积。这两个与分裂相比如何对我来说不太明显。我的理解是拆分设计比 single-ported 统一设计具有更高的面积 [TODO: Explain why]。考虑缓存组织细节、缓存总线到管道的长度以及处理技术可能很重要。这里要注意的一件事是 single-ported 指令缓存比 single-ported 数据缓存或统一缓存低,因为指令缓存只需要一个 exclusive-read 端口,而其他需要 read/write端口。

真实处理器中的统一 L1 和拆分 L2 缓存

我不知道过去 15 年设计的任何处理器都具有统一 (L1) 缓存。在现代处理器中,统一设计主要用于 higher-numbered 缓存级别,这是有道理的,因为它们不直接连接到管道。一个 L2 缓存遵循拆分设计的有趣示例是 Intel Itanium 2 9000 处理器。该处理器具有 3 级缓存层次结构,其中 L1 和 L2 缓存被拆分并专用于每个内核,而 L3 缓存统一并在所有内核之间共享。 L2D 和 L2I 缓存的大小分别为 256 KB 和 1 MB。后来的 Itanium 处理器将 L2I 大小减少到 512 KB。 Itanium 2 9000 手册解释了 L2 拆分的原因:

The separate instruction and data L2 caches provide more efficient access to the caches compared to Itanium 2 processors where instruction requests would contend against data accesses for L2 bandwidth against data accesses and potentially impact core execution as well as L2 throughput.

. . .

The L3 receives requests from both the L2I and L2D but gives priority to the L2I request in the rare case of a conflict. Moving the arbitration point from the L1-L2 in the Itanium 2 processor to the L2-L3 cache greatly reduces conflicts thanks to the high hit rates of the L2.

(我认为“反对数据访问”写错了两次。)

该引文的第二段提到了我之前忽略的一个优势。拆分 L2 缓存将 data-instruction 冲突点从 L2 移动到 L3。此外,some/many 在 L1 缓存中未命中的请求可能会在 L2 中命中,从而降低在 L3 中发生争用的可能性。

对了,Itanium 2 9000中的L2I和L2D都采用了NRU替换策略

统一的 L1 缓存分区

詹姆斯·贝尔等人。在他们 1974 年的论文中提到了在指令和数据之间划分统一缓存的想法。据我所知,唯一一篇提出并评估了这种设计的论文是 Virtually Split Cache: An Efficient Mechanism to Distribute Instructions and Data,发表于 2013 年。拆分设计的主要缺点是其中一个 L1 缓存可能未得到充分利用,而另一个可能是 over-utilized。拆分缓存不允许一个缓存在需要时从另一个缓存中获取 space。这就是为什么统一设计的 L1 未命中率低于拆分缓存的整体未命中率的原因(正如论文使用模拟显示的那样)。然而,更高的延迟和更低的未命中率对性能的综合影响仍然使具有统一 L1 缓存的系统比具有拆分缓存的系统慢。

Virtually Split Cache (VSC) 设计是分离设计和统一设计之间的中间点。 VSC 根据需要在指令和数据之间动态划分 (way-wise) L1 缓存。这样可以更好地利用 L1 缓存,类似于统一设计。但是,VSC 的未命中率甚至很低,因为分区减少了行保存和指令与行保存数据之间潜在的 space 冲突。根据实验结果(所有缓存设计的整体容量相同),即使VSC与统一缓存具有相同的延迟,VSC在single-core系统上的性能与拆分设计大致相同,并且具有multi-core 系统上的性能更高,因为较低的未命中率导致访问共享 L2 缓存的争用较少。此外,在 single-core 和 multi-core 系统配置中,VSC 由于较低的未命中率而降低了能耗。

VSC 的延迟可能低于统一缓存。虽然两者都是双端口的(与 single-ported 拆分缓存具有相同的带宽),但在 VSC 设计中,只有接口需要双端口,因为缓存的任何部分都不能同时访问超过一次时间。 (论文没有明确说明,但我认为如果 VSC 同时保存指令和数据,则允许同一行出现在两个分区中,因此它仍然存在拆分设计中存在的一致性问题。)假设cache的每个bank代表一个cache way,那么每个bank在VSC中可以是single-ported。这导致更简单的设计(参见:Fast quadratic increase of multiport-storage-cell area with port number)并且可以减少延迟。此外,假设统一设计和拆分设计之间的延迟差异很小(因为拆分d中的指令缓存和数据缓存符号在物理上彼此靠近),VSC 设计可以将指令和数据存储在物理上靠近管道中所需位置的库中,并支持 variable-latency 访问,具体取决于为每个库分配的库数。 Bank数量越多,latency越高,达到统一设计的latency。然而,这将需要一种可以处理这种可变延迟缓存的管道设计。

我认为本文遗漏的一件重要事情是评估具有较高访问延迟的 VSC 设计相对于拆分设计(不仅仅是 2 个周期与 3 个周期)。我认为即使只增加一个周期的延迟也会使 VSC 比拆分慢。

Z80000统一缓存案例

Zilog Z80000 处理器有一个带有 on-chip single-ported 统一缓存的标量 6 级流水线。高速缓存是 16 路完全关联和扇区的。流水线的每个阶段至少需要两个时钟周期(缓存中未命中的加载和其他复杂指令可能需要更多周期)。每对连续的时钟周期构成一个处理器周期。 Z80000 的缓存设计有许多我在其他地方没有见过的独特属性:

  • 在一个处理器周期内最多可以有两次缓存访问,包括最多一次指令获取和最多一次数据访问。然而,尽管缓存是统一的 single-ported,但它的设计方式使得指令获取和数据访问之间没有争用。统一缓存具有单个时钟周期(等于半个处理器周期)的访问延迟。在每个处理器周期中,指令提取在第一个时钟周期执行,数据访问在第二个时钟周期执行。在这种情况下,拆分缓存没有延迟优势,并且 time-multiplexing 访问缓存提供相同的带宽,而且拆分设计的缺点也不存在。完全关联性最大限度地减少了指令和数据线之间的 space 争用。这种设计是通过较小的缓存大小和相对于缓存延迟的相对较浅的管道实现的。
  • 系统配置控制长字 (SCCL) 提供高速缓存指令 (CI) 和高速缓存数据 (CD) 控制位。如果CI为1,缓存中未命中的取指令可以填充到缓存中。如果 CD 为 1,则可以将缓存中未命中的数据加载到缓存中。缓存使用 write-no-allocate 策略,因此写入未命中永远不会在缓存中分配。如果 CI 和 CD 都设置为 1,则缓存有效地像统一缓存一样工作。如果只有一个标志为 1,则缓存有效地像 data-only 或 instruction-only 缓存一样工作。应用程序可以调整这些标志以提高性能。
  • 这个属性与问题无关,但我觉得很有趣。 SCCL 还提供高速缓存替换 (CR) 控制位。将此位设置为零会禁用未命中时的替换,因此永远不会替换行。如果一个集合中的所有条目都被占用并且该集合中发生 load/fetch 未命中,则该行根本不会填充到缓存中。

R3000、80486、奔腾P5机箱

我在 SE Retrocomputing 上遇到了以下补充问题:Why did Intel abandon unified CPU cache?。该问题的公认答案存在许多问题。我将在这里解决这些问题,并解释为什么 80486 和 Pentium 缓存是根据 Intel 的信息设计成那样的。

80386 确实有一个外部缓存控制器,具有外部统一缓存。然而,仅仅因为缓存是外部的并不一定意味着它很可能是统一的。考虑 R3000 处理器,它在 80386 之后三年发布,与 80486 属于同一代。R3000 的设计者根据第 1.8 节选择了一个大的外部缓存而不是一个小的 on-chip 缓存来提高性能PaceMips R3000 32-Bit, 25 MHz RISC CPU with Integrated Memory Management Unit. The first section of Chapter 1 of the R3000 Software Reference Manual 表示外部缓存采用分离式设计,因此它可以在同一“时钟相位”中执行取指令和读取或写入数据访问。我不清楚这到底是如何工作的。我的理解是外部数据和地址总线在两个缓存之间共享,也与内存共享。 (另外,一些地址线用于向 on-chip 缓存控制器提供缓存行标签以进行标签匹配。)两个缓存都是 direct-mapped,可能是为了实现 single-cycle 的访问延迟。具有相同带宽、关联性和容量的统一外部缓存设计要求缓存完全 dual-ported,或者可以使用 VSC 设计,但 VSC 是多年后发明的。这样的统一缓存会更昂贵,并且可能具有比保持流水线充满指令所需的单个周期更长的延迟。

Retro 链接答案的另一个问题是,仅仅因为 80486 直接从 80386 演变而来并不一定意味着它也使用了 th统一设计。根据题为 The i486 CPU: executing instructions in one clock cycle 的英特尔论文,英特尔评估了这两种设计并有意选择了统一的 on-chip 设计。与 same-gen R3000 相比,两个处理器具有相似的频率范围,off-chip 数据宽度在两个处理器中都是 32 位。然而,80486 的统一缓存比 R3000 的总缓存容量小得多(最多 16KB vs. 最多 256KB+256KB)。另一方面,on-chip 使 80486 具有更宽的高速缓存总线变得更加可行。特别是,80486 缓存有一个 16 字节的取指令总线、一个 4 字节的数据加载总线和一个 4 字节的数据 load/store 总线。两条数据总线可同时用于在一次访问中加载单个 8 字节操作数(double-precision FP 操作数或段描述符)。 R3000 高速缓存共享一个 4 字节总线。 80486 高速缓存的相对较小的大小可能允许使其具有 single-cycle 延迟的 4 路关联。这意味着命中高速缓存的加载指令可以在下一个周期中将数据提供给相关指令,而不会出现任何停顿。在 R3000 上,如果一条指令依赖于紧接在前的加载指令,则它必须在缓存命中的 best-case 场景中停止一个周期。

80486 缓存是 single-ported,但指令预取缓冲区和宽 16 字节指令获取总线有助于将指令获取和数据访问之间的争用降至最低。 Intel提到仿真结果显示统一设计提供了比分离缓存更高的命中率足以补偿带宽争用。

Intel 在另一篇题为 Design of the Intel Pentium processor 的论文中解释了为什么他们决定将 Pentium 中的高速缓存更改为拆分。有两个原因:(1) 2-wide 超标量 Pentium 需要在一个周期内执行最多两次数据访问的能力,以及 (2) 分支预测增加了缓存带宽需求。这篇论文没有提到英特尔是否考虑过使用 triple-ported banked unified cache,但他们可能考虑过并发现当时不可行,所以他们选择了 dual-ported 8 的拆分缓存-banked 数据缓存和 single-ported 指令缓存。以现在的fab技术,triple-ported统一设计可能更好

后来的微体系结构中更宽的管道需要在数据缓存中有更高的并行度。现在我们位于 Sunny Cove 的 4 个 64 字节端口。

回答问题的第二部分

it was mentioned that the cache is a split cache, and no hazard what does this exactly means?

这可能是关于保罗评论中提到的结构性危险。即取指单元和内存单元当时无法访问统一的single-ported缓存