CPU如何在每个周期提供多条指令?

电器工程 微处理器 中央处理器 计算机架构
2022-01-10 04:23:48

Wikipedia 的每秒指令说明说 i7 3630QM 在 3.2 GHz 的频率下可提供约 110,000 MIPS;这将是(110/3.2 指令)/4 核心 = 每个核心每周期约 8.6 条指令?!单核如何在每个周期提供多条指令?

据我了解,管道应该每个时钟只能提供一个结果。

这些是我的想法:

  • 内部频率实际上高于 3.2 GHz
  • CPU的某些部分是异步的,像我这样卑微的人无法理解
  • 每个核心有多个并发管道
  • 一个流水线可以在每个时钟交付更多的结果,一条指令可以跳过流水线阶段,并且有多个预取器来跟上
  • 我错过了一些东西
4个回答

首先,正如Keelan 的评论Turbo J 的回答所指出的,测量结果是 113,093 Dhrystone MIPS,而不是原生MIPS。

i7 3630QM 的 Ivy Bridge 微架构每个周期只能提交 4 个融合微操作,但它可以开始每个周期执行 6 个微操作。(一条代码中融合的微操作数大致等于指令的数量;一些复杂的指令被解码成多个不融合的微操作,而一些指令对可以融合成一个微操作,例如立即比较然后是条件跳转。)

您关于如何在单个周期内执行多条指令的两个推测非常有效,并且已在实际处理器中使用。您的第一个猜测是使用更快的内部时钟,用于原始 Pentium 4 的“火球”ALU。这些 ALU 的时钟频率是内核其余部分的两倍,这已经相对较高了。

(这是通过使用交错 ALU 实现的,其中加法的下半部分在一个周期中完成,允许相关操作在下一个周期中使用结果的下半部分。对于加法、异或或左移等操作它只需要操作数的下半部分来产生完整的下半部分结果,这种交错(也称为宽度流水线)允许单周期结果延迟和单周期吞吐量。)

HyperSPARC 使用了一种相关的技术,即级联 ALU。HyperSPARC 将两个 ALU 的结果输入第三个 ALU。这允许在单个周期中执行两个独立的和第三个相关的操作。

您对“每个核心有多个并发管道”的推测是另一种已使用的技术。这种类型的设计称为超标量,是迄今为止增加在单个周期中执行的操作数量的最常用方法。

还有一些其他的指令执行可能值得注意。一些操作可以在普通执行单元之外更有效地执行。移动消除技术利用乱序处理器中的寄存器重命名来在寄存器重命名期间执行移动操作;移动只是将物理寄存器编号从重命名表(称为寄存器别名表)中的一个位置复制到另一个位置。这不仅有效地增加了执行宽度,而且还消除了依赖性。该技术早期用于基于堆栈的 x87,但现在广泛用于英特尔的高性能 x86 处理器。(在 x86 中使用破坏性的双操作数指令使得移动消除比在典型的 RISC 中更有帮助。)

一种类似于移动消除的技术是在重命名期间处理寄存器归零指令。通过提供提供零值的寄存器名称,寄存器清除指令(如 xor 或减法,两个操作数是相同的寄存器)可以简单地将该名称插入重命名表 (RAT)。

一些 x86 处理器使用的另一种技术降低了推送和弹出操作的成本。通常,使用堆栈指针的指令必须等待一个完整的周期以等待先前的推送或弹出来更新堆栈指针的值。通过认识到 push 和 pop 仅向堆栈指针添加或减去一个小值,可以并行计算多个加法/减法的结果。加法的主要延迟是进位传播,但是对于较小的值,基值的更高有效位(在本例中为堆栈指针)将最多只有一个进位。这允许将类似于进位选择加法器的优化应用于小值的多次加法。此外,由于堆栈指针通常仅由常量更新,

也可以将指令合并成一个更复杂的操作。虽然将指令拆分为多个更简单的操作的反向过程是一项古老的技术,但合并指令(英特尔将其称为宏操作融合)可以允许实现支持比指令集中公开的操作更复杂的操作。

在理论方面,已经提出了其他技术。RAT 可以支持除零以外的小常数,并且可以及早处理一些使用或可靠产生如此小的值的简单操作。(“Physical Register Inlining”,Mikko H. Lipasti 等人,2004 年,建议使用 RAT 作为减少寄存器数量的一种手段,但这个想法可以扩展到支持加载小的立即数和对小数的简单操作。)

对于跟踪缓存(在特定的控制流假设下存储指令序列),可能有机会合并由分支分隔的操作并删除在跟踪中产生未使用结果的操作。跟踪缓存中的优化缓存还可以鼓励执行优化,例如指令合并,如果每次提取指令流时都必须完成这些优化,则可能不值得。

值预测可用于通过消除依赖关系来增加可以并行执行的操作数量。基于步幅的值预测器类似于前面提到的专用堆栈引擎的弹出/推送优化。它可以大部分并行计算多个加法,消除序列化。值预测的一般思想是,有了预测值,相关操作就可以毫无延迟地进行。(分支方向和目标预测实际上只是一种非常有限的值预测形式,允许获取依赖于分支的“值”(是否采用)和下一条指令地址的后续指令,另一个值。)

现代处理器内部发生了一些黑魔法,但你的想法绝对是正确的。

理解现代处理器效率的关键是认识到它们是超标量的。来自维基百科(强调我的):

超标量 CPU 架构在单个处理器中实现了一种称为指令级并行的并行形式。因此,它允许比在给定时钟速率下可能实现的更快的 CPU 吞吐量。

正如您所猜测的那样,这些现代处理器的每个内核都有多个执行单元。 考虑超线程很有趣,管道的某些部分是重复的,但有些不是。

乱序执行也很有趣,但不能直接回答您的问题。不过,它确实减少了“浪费”的 CPU 周期数。

效率还受到许多其他可能导致处理器内部停顿的因素的影响,包括(但绝对不限于):

  • 先前指令的结果不可用。
  • 缓存未命中。
  • 代码分支,这将使已经获取的指令无效(阅读此处此处的分支预测)。

现代编译器试图帮助处理上述许多项目,然后处理器接管。作为一个很好的例子,请参阅Stackexchange 上的其他地方的这个问题,它强调了可以做同样事情的两条指令之间的重要区别(在某些情况下)。但是,由于正在使用的执行单元,在某些处理器上,一个可能比另一个“更快”。

有关现代 CPU 管道的人类可读解释,请参阅 CPU 管道之旅有关更多技术性的解释,请参阅 Agner Fog 的Microarchitecture论文。

你认为发生了什么:英特尔、AMD 和 IBM 的所有工程师都读到管道每个周期只能提供一个结果,他们说“哦,好吧,那就这样,不能让这些处理器更快”。还是他们读到这个并说:“每个周期不能提供超过一个结果?我们会看到的!”。

例如,对于 Haswell 架构的一个很好的介绍,您可以点击这个链接http://www.realworldtech.com/haswell-cpu/或者您可以直接访问英特尔网站,在那里您会找到一些文档。

Haswell 处理器的每个内核都有大量的执行单元,它们可以相互独立地执行操作,因此可以并行执行多个操作。其次,Haswell 处理器有几个执行单元,可以处理高达 256 位大小的向量运算。例如,一个向量运算可以在一个向量运算中执行四个双精度浮点运算或八个单精度浮点运算。最后,Haswell 处理器支持“融合乘加”,这意味着计算 a 乘以 b 加 c 只是一个操作。

由于 Haswell 有两个能够融合乘加的单元,因此理论上的最大值是每个周期两次融合乘加运算,每个运算执行 8 次单精度乘法加加,或 32 次单精度浮点运算。

3630 处理器不在英特尔最新的价格表中,但也有像 3740QM 这样的四核型号。因此,每个时钟周期可以获得 128 个浮点运算,而不是 32 个。这是理论上的最大值。在现实生活中实现其中的一半是一项挑战,但对于合适的任务来说并非不可能。还有其他处理器可提供多达 15 个内核(即使是最狂热的游戏狂热者也不会支付的价格)。

所以你有几个乘数的组合:

  1. 每个处理器多个内核。
  2. (超线程,之前没有提到,可以让你更接近理论极限)
  3. 融合乘加运算执行两个算术运算,仅计数为一个。
  4. 256 位向量执行 8 次操作,仅计为 1 次。
  5. 两个能够处理融合乘加的向量执行单元。

每个周期 8.6 次操作并不难实现。即使每个内核每个周期执行 8.6 次操作也不是太困难。

Drystone 基准是从 1984 年开始的,相应的标称 1 MIPS VAX 机器在现代术语中并不是很有效。即使是 Cortex M3 也能提供 1,25 DMPIS / MHz。

英特尔酷睿架构处理器确实可以在单个内核中并行运行多条指令,因为存在多个计算单元。