# 2.5 贯穿各层的问题：存储层次结构设计
<!-- source: p0156 -->

本节讨论五个在其他章节中涉及、又对存储层次结构至关重要的主题。

## 独立的取指单元

许多乱序执行处理器，甚至一些只是流水线较深的处理器，都会用单独的取指单元将取指，有时还包括初步译码，与后续执行过程解耦（见第 3 章）。取指单元通常从指令缓存取回整个块，再将其译码为单条指令。这种方法对于可变长度指令尤其有用；对于每个时钟周期能够发射不止一条指令的处理器，则是必需的。

由于访问指令缓存时以块为单位，其未命中率就不再适合与每条指令都访问一次指令缓存的处理器直接比较。此外，取指单元可能向 L1 预取块。正如前文所见，预取可能增加未命中次数，却实际降低了总的未命中开销。许多处理器还支持数据预取，同样可能一方面提高数据缓存未命中率，另一方面降低数据缓存的总未命中开销。

## 专用指令缓存

提供足够的指令带宽，是超标量处理器面临的最大挑战之一。对于将指令转换为微操作的设计，例如最新的 Arm 和 i7 处理器，可以用一个小型缓存保存近期已转换的指令，从而降低指令带宽需求和分支预测错误的开销。下一章将更深入地讨论这项技术。

## 推测执行与内存访问

高级流水线的一项主要技术是**推测执行（speculation）**：处理器尚不知道一条指令是否确实需要执行，就先尝试执行它。

<!-- source: p0157 -->

这类技术依赖分支预测；如果预测错误，就必须从流水线中清除推测执行的指令。支持推测执行的存储系统面临两个不同问题：保护和性能。推测执行可能产生一些最终不会被使用的内存访问，因为相应指令来自错误的推测。如果执行这些访问，就可能引发保护异常。显然，只有指令确实需要执行时，这类异常才应生效。下一章将介绍如何处理这种“推测产生的异常”。

推测执行处理器可能访问指令缓存和数据缓存，随后却不使用访问结果，因此推测执行可能提高缓存未命中率。但与预取一样，它也可能降低总的缓存未命中开销。使用推测执行后，即使指令集体系结构（ISA）和缓存结构完全相同，将其未命中率与没有推测执行的处理器比较，也会产生误导。最后，推测执行还是能够显著提高侧信道攻击泄露速率的一项能力。

## 缓存数据的一致性

数据可能同时存在于内存和缓存中。只要处理器是唯一读写数据的部件，而且缓存位于处理器与内存之间，处理器读到旧副本或过期副本的风险就很小。我们将看到，多个处理器以及 I/O 设备都可能使数据副本不一致，导致读到错误副本。

多处理器与 I/O 面临缓存一致性问题的频率不同。对于 I/O，出现多个数据副本是少见情形，应尽量避免；但在多个处理器上运行的程序，却希望在多个缓存中拥有同一数据的副本。多处理器程序的性能取决于系统共享数据时的性能。共享数据的一致性和性能，是第 5 章的重要主题。

I/O 缓存一致性的问题是：计算机中的 I/O 应该发生在什么位置，是 I/O 设备与缓存之间，还是 I/O 设备与主存之间？如果输入将数据写入缓存，输出从缓存读取数据，那么 I/O 和处理器看到的就是同一份数据。困难在于，这种做法会干扰处理器，并可能让处理器为 I/O 而停顿。此外，输入的新数据可能短期内不会被访问，却将原有信息挤出缓存，造成缓存干扰。

带缓存的计算机，其 I/O 系统的目标是在避免过期数据问题的同时，尽量减少干扰。因此，许多系统倾向于让 I/O 直接访问主存，把主存作为 I/O 缓冲区。如果采用直写缓存，主存中的信息副本就是最新的，输出也就没有过期数据问题。这一优点正是处理器曾采用直写的原因。不过，今天直写通常只见于一级数据缓存，其后还有采用写回的 L2 缓存。

<!-- source: p0158 -->

写缓冲区和写合并给内存映射 I/O 带来了额外复杂性。例如，I/O 寄存器地址**不能**允许写合并，因为彼此独立的 I/O 寄存器不一定像内存中的字数组那样工作。它们可能要求为每个 I/O 寄存器分别提供一个地址和一个数据字，而不能用一个地址发起多字写入。通常的处理办法，是将这些页面标记为要求缓存采用不可合并的直写方式。

I/O 输入还需要额外注意。软件解决办法是保证输入缓冲区中的任何块都不在缓存中。可以把缓冲区所在的页面标记为不可缓存，让操作系统始终向这类页面输入数据；也可以由操作系统在输入发生前，从缓存中清除缓冲区对应的地址。硬件解决办法是在输入时检查 I/O 地址是否位于缓存中；若匹配，就使相应缓存项失效，避免使用过期数据。对于采用写回缓存的输出，这些办法同样适用。为了在数据中心实现高性能，可能还需要其他办法，将 I/O 融入存储层次结构。第 6 章将探讨这一主题。

## 通过虚拟机实施保护

**虚拟机（virtual machine，VM）**与虚拟内存有关，而且几乎同样古老。它最初出现于 20 世纪 60 年代末，多年来一直是大型机计算的重要组成部分。虚拟机让共享一台计算机的程序运行各自独立的操作系统版本，从而提供更高层次的程序间保护。虚拟机是当今大型数据中心的关键技术，第 6 章将详细介绍。

虚拟机往往引入影子页表，这会增加 TLB 未命中的代价，因为查找正确地址映射需要经过更复杂的过程。如附录 L 所述，设计者可以加入专用硬件，处理 TLB 未命中时这些更复杂的步骤。
