4.4 多道向量处理器
向量指令集的一个最大的优点是它能够允许软件传递大量的并行任务给硬件,而只需要一条很短的指令即可。一条向量指令可以包括数十上百个独立的操作,但是仍然和通常的标量指令一样译码为相同的长度。向量指令的并行语义使得执行这些元素操作有两种方法。第一是使用深度流水化的功能单元,就像我们研究的 VMIPS 一样;或者通过一组并行的功能单元,或者是并行单元和流水化单元的组合。图 F.11 展示了如何通过使用并行流水线执行向量 add 指令来提升向量性能。
图 F.11 使用多个功能单元来改进 add 向量指令C = A + B 的性能。(a)中的机器有一条 add 流水线,可以在每个周期完成一次加法。(b)中的机器有四个加法流水线,并且在每个周期可以完成 4 个加法才做。一个向量加法操作涉及到的那些元素被分散分布在四条流水线上。一起通过这些流水线的那组元素被称为元素组(element group)。
VMIPS 指令集设计的特点是所有的向量指令只允许一个向量寄存器的 N 个元素和另一个向量寄存器的 N 个元素参与运算。这极大地简化了可被组织成多个并行道(lane)的高度并行的向量单元的设计。就像一个高速公路一样,我们可以通过增加更多的 lane 来提升一个向量单元的峰值吞吐率,如图 F.12 所示。
图 F.12 一个包含有 4 个道的向量单元的结构。向量寄存器的存储被分布在各 lane 之间,每个 lane 包含有每个向量寄存器的 4 个元素。图中展示了 3 个向量功能单元,一个浮点加法单元,一个浮点乘法单元,以及一个 L/S 单元。每个向量算术单元包含有 4 个执行流水线,每个 lane 一个。他们协同共组去完成每一条向量指令。注意向量寄存器的每一个部分是如何只需要提供本地的 lane 访问的足够端口即可的。这极大减少了提供多端口的开销。提供向量-标量指令(vector-scalar instruction)中标量操作数的通路并没有在这张图中显示出来,但是标量值必须被广播到所有的 lane 中。
每一个 lane 包含了向量寄存器文件的一部分以及每个向量功能单元中的一条流水线。每个向量功能单元通过多个流水线(每个 lane 一个)以每个周期一个 element group 的速率来执行向量指令。第一个 lane 包含有所有向量寄存器的第一个元素,因此任何有关第一个元素的向量指令的源操作数和目的操作数都在第一个 lane 中。这使得一个算术运算的流水线的操作能在一个 lane 内部完成而不需要和其他 lane 通信。Lane 间互联只是在访存的时候才需要。缺少 lane 间通信能够降低互联导线开销和用于高度并行执行单元的寄存器文件的端口,并且解释了为什么当前的超级计算机可以在每个周期完成至多 64 个操作(16 个 lane,每个有 2 个算术单元和 2 个 L/S 单元)。
增加多个 lane 是一种很通用的提升向量性能的技术,因为它只需要很小的控制复杂度上的靠小,并且不需要改动现有的代码。有一些向量超级计算机以 lane 数目可变的系列方式进行销售。这使得用户能够自行权衡价格和峰值性能。Cray SV1 和 X1 允许 4 个 2 道的向量 CPU 组合在一起形成一个单个更大的 8 道 CPU,具体在第七小节讨论。
4.5 流水化指令的启动
增加多条道能够提升峰值性能,但是却不能改变启动延迟,所以通过允许一条向量指令的开始与之前一条指令的完成想重合来降低启动开销就变得很关键了。最简单的情形是当两个向量指令访问不同的向量寄存器的时候。比如,在下面的代码段中:
ADDV.D V1, V2, V3
ADDV.D V4, V5, V6
一种实现方式是允许第二条指令中的第一个元素紧跟着第一条指令的最后一个元素在浮点加法流水线中执行。为了减少控制逻辑的复杂度,有些向量机器在分发(dispatch)到同一向量单元上的两条向量指令之间需要一些恢复时间(recovery time)或死时间(dead time)图 F.13 展示了一条流水线的启动延迟和死时间。
图 F.13 一条向量流水线的启动延迟和死时间。每个元素操作有 5 个周期的延迟:1 个周期去读向量寄存器文件,3 个执行周期,然后一个周期写回寄存器文件。同一个向量指令中的元素可以连续在流水线中执行,但是这个机器在两个向量指令之间插入了 4 个周期的 dead time。这个 dead time 可以利用更复杂的控制逻辑来减少。
下面的例子展示了死时间对于向量处理器性能的影响。
_____________________________________________________
例题:Cray C90 有两个 lane,但是在任何同一个功能单元上执行的两个向量指令之间需要 4 个周期的 dead time,即使他们之间没有数据依赖。对于最大向量长度为 128 的情形而言,由 dead time 导致的峰值性能的减少是多少?如果 lane 的数目增加到 16,那性能折扣又是多少?
解答:最多 128 个元素被划分到 2 个道上,并且占据一个向量功能单元 64 个时钟周期。Dead time 另外增加了 4 个周期的占用,使得峰值性能降为没有 dead time 的 64/(64 + 4) = 94.1%。如果 lane 的数目增加为 16,那么 128 个元素占用一个功能单元的时间只需要 128/16 = 8 个周期,这样 dead time 会导致 8/(8 + 4) = 66.6% 的峰值性能降低。在第二种情况下,向量单元永远不会有超过 2/3 的忙碌时间。
_____________________________________________________
流水化指令的启动在多条指令可以读写同一个向量寄存器或者一些指令不可预期地停顿比如 load 指令遇到 bank conflict 的时候变得更复杂了。但是,因为 lane 的数目和流水线的延迟增加了,现在完全流水化指令的启动时间变得越来越重要了。