好吧,这个问题看起来太简单了,但我在两个都看了几个 ppts 后才问。
这两种方法都增加了指令吞吐量。Superscaling 几乎总是使用流水线。超级缩放有多个执行单元,流水线也是如此,还是我错了?
好吧,这个问题看起来太简单了,但我在两个都看了几个 ppts 后才问。
这两种方法都增加了指令吞吐量。Superscaling 几乎总是使用流水线。超级缩放有多个执行单元,流水线也是如此,还是我错了?
超标量设计涉及处理器能够在单个时钟中发出多条指令,并具有执行指令的冗余设施。请注意,我们谈论的是单核——多核处理是不同的。
流水线将一条指令分成多个步骤,并且由于每个步骤都在处理器的不同部分执行,因此多个指令可以在每个时钟处于不同的“阶段”。
它们几乎总是一起使用。这张来自 Wikipedia 的图片显示了这两个概念的使用,因为这些概念最好以图形方式解释:
在这里,两条指令在五级流水线中一次执行。
鉴于您最近的编辑,进一步分解它:
在上面的示例中,一条指令要经过 5 个阶段才能“执行”。它们是 IF(指令获取)、ID(指令解码)、EX(执行)、MEM(更新内存)、WB(写回缓存)。
在一个非常简单的处理器设计中,每个时钟都会完成一个不同的阶段,因此我们将拥有:
它将在五个时钟内执行一条指令。如果我们然后添加一个冗余执行单元并引入超标量设计,我们将拥有两条指令 A 和 B:
五个时钟中的两条指令——理论上最大增益为 100%。
流水线允许部分同时执行,所以我们最终会得到类似的东西(对于十条指令 A 到 J):
在九个时钟中,我们执行了十条指令——你可以看到流水线真正在哪里移动。这是对示例图形的解释,而不是它在现场的实际实现方式(那是黑魔法)。
很久以前,CPU一次只执行一条机器指令。只有当它完全完成时,CPU 才会从内存(或稍后的指令缓存)中获取下一条指令。
最终,有人注意到这意味着一个 CPU 大部分时间什么都不做,因为有几个执行子单元(例如指令解码器、整数运算单元和 FP 运算单元等),并且执行一条指令一直保持一次只有他们一个忙。
因此,“简单”流水线诞生了:一旦一条指令完成解码并继续执行下一个执行子单元,为什么不获取并解码下一条指令呢?如果你有 10 个这样的“阶段”,那么通过让每个阶段处理不同的指令,理论上你可以在不增加 CPU 时钟的情况下将指令吞吐量提高十倍!当然,这只有在代码中没有条件跳转时才能完美运行(这导致了很多额外的工作来专门处理条件跳转)。
后来,随着摩尔定律持续正确的时间比预期的要长,CPU 制造商发现自己有越来越多的晶体管可供使用,并想“为什么每个执行子单元只有一个?”。因此,具有多个执行子单元能够并行执行相同操作的超标量CPU诞生了,CPU 设计变得非常复杂,要在这些完全并行的单元之间分配指令,同时确保结果与指令执行时的结果相同依次。
一个比喻:洗衣服
想象一家干洗店有以下设施:挂脏衣服或干净衣服的架子、洗衣机和烘干机(每台可以一次洗一件衣服)、折叠桌和熨衣板。
负责所有实际洗涤和烘干的服务员相当愚蠢,因此接受干洗订单的店主特别小心,非常仔细和明确地写下每条指令。
在典型的一天,这些说明可能类似于以下内容:
服务员遵循这些指示到发球台,非常小心不要做任何不正常的事情。可以想象,洗完一天的衣服需要很长时间,因为要彻底清洗、晾干和折叠每一件衣物需要很长时间,而且必须一次完成一件。
然而,有一天服务员辞职了,聘请了一位新的、更聪明的服务员,他注意到大部分设备在白天的任何特定时间都处于闲置状态。当裤子在烘干时,熨衣板和洗衣机都没有使用。所以他决定更好地利用他的时间。因此,他将执行以下操作,而不是上述一系列步骤:
这是流水线。对不相关的活动进行排序,以便它们同时使用不同的组件。通过同时保持尽可能多的不同组件处于活动状态,您可以最大限度地提高效率并加快执行时间,在这种情况下,将 16 个“周期”减少到 9 个,加速超过 40%。
现在,小干洗店开始赚更多的钱,因为他们可以工作得更快,所以老板买了一个额外的洗衣机、烘干机、熨衣板、折叠台,甚至还雇了一个服务员。现在事情变得更快了,而不是上面的,你有:
这是超标量设计。多个子组件能够同时执行相同的任务,但由处理器决定如何执行。在这种情况下,它导致了近 50% 的速度提升(在 18 个“周期”中,新架构可以运行该“程序”的 3 次迭代,而之前的架构只能运行 2 次)。
较旧的处理器,例如 386 或 486,是简单的标量处理器,它们一次执行一条指令,其顺序与接收指令的顺序完全相同。自 PowerPC/Pentium 以来的现代消费类处理器是流水线和超标量的。Core2 CPU 能够运行为 486 编译的相同代码,同时仍然利用指令级并行性,因为它包含自己的内部逻辑,可以分析机器代码并确定如何重新排序和运行它(可以并行运行的,什么不能,等等)这就是超标量设计的精髓,也是为什么它如此实用。
相比之下,向量并行处理器一次对多条数据(向量)执行操作。因此,向量处理器不只是添加 x 和 ya,而是将 x0,x1,x2 添加到 y0,y1,y2(导致 z0,z1,z2)。这种设计的问题在于它与处理器的特定并行度紧密耦合。如果您在矢量处理器上运行标量代码(假设可以),您将看不到矢量并行化的优势,因为它需要明确使用,同样如果您想利用具有更多并行处理单元的更新矢量处理器(例如能够添加 12 个数字的向量,而不仅仅是 3) 你需要重新编译你的代码。
超标量处理器还可以具有执行推测执行的能力。与其让处理单元空闲并在分支处理器之前等待代码路径完成执行,不如在先前的代码完成处理之前做出最佳猜测并开始执行越过分支的代码。当先前代码的执行赶上分支点时,处理器可以将实际分支与分支猜测进行比较,如果猜测正确则继续(已经远远领先于它本来应该等待的位置)或者它可以使推测执行的结果无效并运行正确分支的代码。
流水线是汽车公司在制造汽车时所做的事情。他们将组装汽车的过程分解为多个阶段,并在由不同人员完成的装配线上的不同点执行不同的阶段。最终结果是,汽车仅以最慢阶段的速度制造。
在 CPU 中,流水线过程完全相同。一条“指令”被分解为不同的执行阶段,通常类似于 1. 获取指令,2. 获取操作数(读取的寄存器或内存值),2. 执行计算,3. 写入结果(到内存或寄存器) . 其中最慢的可能是计算部分,在这种情况下,通过此管道的指令的整体吞吐速度只是计算部分的速度(就好像其他部分是“免费的”一样。)
微处理器中的超标量是指从单个执行流中同时并行运行多个指令的能力。因此,如果一家汽车公司经营两条装配线,那么显然他们可以生产两倍的汽车。但如果给汽车打序列号的过程是在最后阶段,必须由一个人完成,那么他们将不得不在两条管道之间交替,并保证他们可以在一半的时间内完成。最慢的阶段,以免自己成为最慢的阶段。
微处理器中的超标量是类似的,但通常有更多的限制。因此,取指令阶段通常会在其阶段产生多条指令——这就是微处理器中超标量的原因。然后将有两个提取阶段、两个执行阶段和两个写回阶段。这显然可以推广到不止两个管道。
这一切都很好,但从声音执行的角度来看,如果盲目地执行这两种技术,可能会导致问题。为了程序的正确执行,假设指令是按顺序一个接一个地完整执行的。如果两条顺序指令具有相互依赖的计算或使用相同的寄存器,则可能会出现问题,后面的指令需要等待前一条指令的回写完成才能执行操作数获取阶段。因此,您需要在执行第二条指令之前将其暂停两个阶段,这首先违背了这些技术所获得的目的。
有许多技术可以用来减少需要停顿的问题,描述起来有点复杂,但我会列出它们:1. 寄存器转发,(也存储到负载转发)2. 寄存器重命名,3. 记分板,4 . 乱序执行。5. 带有回滚(和退役)的推测执行 所有现代 CPU 几乎都使用所有这些技术来实现超标量和流水线。然而,在停顿不可避免之前,这些技术的收益往往会随着处理器中的流水线数量而递减。实际上,没有 CPU 制造商在单个内核中制造超过 4 条流水线。
多核与任何这些技术无关。这基本上是将两个微处理器组合在一起以在单个芯片上实现对称多处理,并仅共享那些有意义的组件(通常是 L3 缓存和 I/O)。然而,英特尔称之为“超线程”的技术是一种尝试在单核的超标量框架内虚拟实现多核语义的方法。因此,单个微架构包含两个(或更多)虚拟内核的寄存器,并从两个(或更多)不同的执行流中获取指令,但从一个通用的超标量系统执行。这个想法是,因为寄存器不能相互干扰,所以往往会有更多的并行性导致更少的停顿。因此,与其简单地以一半的速度执行两个虚拟核心执行流,不如整体减少停顿更好。这似乎表明英特尔可以增加流水线的数量。然而,已发现该技术在实际实现中有些欠缺。不过,由于它是超标量技术不可或缺的一部分,所以无论如何我都提到了它。
流水线是在同一周期同时执行多条指令的不同阶段。它基于将指令处理分成多个阶段,每个阶段都有专门的单元和用于存储中间结果的寄存器。
超缩放是向 CPU 中存在的多个执行单元分派多条指令(或微指令)。因此,它基于 CPU 中的冗余单元。
当然,这些方法可以相互补充。