当前位置: 首页 > 知识库问答 >
问题:

了解CPU管道阶段与指令吞吐量

孔鹤龄
2023-03-14

我错过了一些基本的东西。CPU管道:在基本层面上,为什么指令需要不同数量的时钟周期才能完成,为什么一些指令在多级CPU中只需要1个周期?

除了明显的“不同的指令需要不同的工作量来完成”,听我说完...

考虑具有大约14级流水线的i7。这需要14个时钟周期才能完成一次运行。AFAIK,这应该意味着整个流水线的延迟为14个时钟。然而事实并非如此。

XOR在1个周期内完成,延迟为1个周期,这表明它没有经历所有14个阶段。BSR的延迟为3个周期,但每个周期的吞吐量为1。AAM的延迟为20个周期(大于阶段计数),吞吐量为8(在常春藤网桥上)。

有些html" target="_blank">指令不能在每个时钟发出,但需要不到14个时钟才能完成。

我知道多个执行单元。我不明白指令的延迟和吞吐量与管道阶段的数量有什么关系。

共有2个答案

怀飞掣
2023-03-14

我错过了一些基本的东西。CPU管道:在基本层面上,为什么指令需要不同数量的时钟周期才能完成,为什么一些指令在多级CPU中只需要1个周期?

因为我们感兴趣的是指令之间的速度,而不是单个指令的开始到结束时间。

除了明显的“不同的指令需要不同的工作量来完成”,听我说完...

这就是为什么不同的指令有不同的延迟的关键答案。

考虑具有大约14级流水线的i7。这需要14个时钟周期才能完成一次运行。AFAIK,这应该意味着整个流水线的延迟为14个时钟。然而事实并非如此。

这是正确的,尽管这不是一个特别有意义的数字。例如,为什么我们关心CPU完全处理一条指令需要多长时间?这基本上没有效果。

XOR在1个周期内完成,延迟为1个周期,这表明它没有经历所有14个阶段。BSR的延迟为3个周期,但每个周期的吞吐量为1。AAM的延迟为20个周期(大于阶段计数),吞吐量为8(在常春藤网桥上)。

这只是一堆误解。XOR在依赖链中引入一个延迟周期。也就是说,如果我执行12条指令,每条指令修改前一条指令的值,然后添加一个异或作为第13条指令,那么它将再花费一个周期。这就是延迟的含义。

有些指令不能在每个时钟发出,但需要不到14个时钟才能完成。

正当所以

我知道多个执行单元。我不明白指令的延迟和吞吐量与管道阶段的数量有什么关系。

他们没有。为什么会有任何联系?假设在管道的开始有14个额外的阶段。为什么这会影响延迟或吞吐量?这意味着所有事情都会在14个时钟周期之后发生,但速率仍然相同。(尽管这可能会影响预测失误分支机构的成本和其他事项。)

梁明辉
2023-03-14

我认为现有答案中缺少的是“绕过”或“转发”数据路径的存在。为了简单起见,让我们继续使用MIPS 5级管道。每个指令从出生到死亡需要5个周期——提取、解码、执行、内存、写回。这就是处理一条指令所需的时间。

您想知道的是,一条指令将其结果传递给从属指令需要多长时间。假设您有两条连续的ADD指令,并且通过R1存在依赖关系:

ADD R1, R2, R3
ADD R4, R1, R5

如果没有转发路径,我们将不得不将第二条指令停顿多个周期(2或3取决于写回的工作方式),以便第一条指令可以将其结果存储到寄存器文件中,然后第二条指令将其作为输入读取在解码阶段。

但是,有一些转发路径允许从管道中挑选出有效结果(但尚未写回的结果)。假设第一个ADD从decode中的寄存器文件获取所有输入。第二个将从寄存器文件中取出R5,但在执行阶段之后将从管道寄存器中取出R1。换句话说,我们在一个周期后将ALU的输出路由回其输入。

乱序处理器普遍使用转发。它们将有许多不同的功能单元,具有许多不同的延迟。例如,ADD和AND通常需要一个周期(TO DO THE MATH,将之前和之后的所有管道阶段放在一边),MUL将需要大约4个,浮点运算将需要大量周期,内存访问具有可变延迟(由于缓存未命中)等。

通过使用转发,我们可以将指令的关键路径限制为仅执行单元的延迟,而其他一切(提取、解码、退役)都不在关键路径内。指令被解码并转储到指令队列中,等待其他执行指令生成其输入。当指令的依赖关系得到满足时,它就可以开始执行了。

让我们考虑一下这个例子

MUL R1,R5,R6
ADD R2,R1,R3
AND R7,R2,R8

我将尝试绘制一个时间表,显示这些指令在管道中的流程。

MUL  FDIXXXXWR
ADD   FDIIIIXWR
AND    FDIIIIXWR

密钥:

F - Fetch
D - Decode
I - Instruction queue (IQ)
X - execute
W - writeback/forward/bypass
R - retire

如您所见,乘法指令的总生存期为9个周期。但是在MUL和ADD的执行中存在重叠,因为处理器是流水线的。当ADD进入IQ时,它必须等待其输入(R1),同样,and也需要等待,这取决于ADD的结果(R2)。我们关心的不是MUL的总寿命,而是任何依赖指令必须等待多长时间。这就是它的有效延迟,即4个周期。如您所见,一旦ADD执行,依赖项和可以在下一个周期执行,这也是由于转发。

 类似资料:
  • 在大数据存储中,IOPS和吞吐量之间的关键区别是什么

  • 我正在寻找一种公式/方法来衡量一条指令的速度,或者更具体地说,按CPU周期给每条指令一个“分数”。 以下面的汇编程序为例, 以及以下Intel Skylake信息: mov r,m:吞吐量=0.5延迟=2 Mov m, r:吞吐量=1延迟=2 nop:吞吐量=0.25延迟=非 inc:吞吐量=0.25延迟=1 我知道程序中的指令顺序在这里很重要,但我希望创建一些不需要“精确到单个周期”的通用指令

  • 我正在编写一个Groovy脚本,其中包含部署terraform的作业。我正在使用作业DSL并使种子作业由JCasC实现,一切正常。然后我有一个包含作业的Groovy文件的存储库。 如果我将Groovy文件保持为单个作业,它就可以正常工作。 然而,我希望能够构建具有构建阶段的管道。我知道我可以把管道写在詹金斯文件中 我有这个作为开始: 但是,我看到了这个错误: 我已经尝试了各种方法,并阅读了一堆文档

  • 来自AWS Lambda常见问题解答: Q: 我一次可以执行的AWS Lambda函数的数量是否有限制? 不需要。AWS Lambda旨在并行运行多个函数实例。然而,AWS Lambda的默认安全限制为每个区域每个帐户100次并发执行。如果您希望提交请求以增加100次并发执行的限制,您可以访问我们的支持中心,单击“打开新案例”,然后提交服务限制增加请求。 Q: 如果我的帐户超过并发执行的默认限制,

  • 我找不到任何关于agner.orgRDRAND指令的延迟或吞吐量的信息。但是,这个处理器存在,所以信息必须在那里。 编辑:实际上,最新的优化手册中提到了此说明。记录如下:

  • 我希望能够在Jenkins中包装一个“阶段”,这样我就可以在一个阶段的开始和结束时执行自定义代码,比如: 我想我可以通过使用元类来做到这一点: 但是Groovy脚本本身似乎是一个绑定,它没有元类: 我还在学习Groovy和Jenkins管道是如何工作的,所以也许我只是错过了一些东西。