计算机组成原理:超长流水线的缺陷

CPU流水线技术通过把一条指令的操作切分成更细的多个步骤,避免CPU“浪费”。每一个细分的流水线步骤都很简单,所以我们的单个时钟周期的时间就可以设置得更短。这也变相的让CPU的主频提升得很快。

但是,如果流水线的深度太长,在同主频下,其实是降低了CPU的性能。因为一个Pipeline Stage,就需要一个时钟周期。那么我们把任务拆分成31个阶段,就需要31个时钟周期才能完整一个任务;而把任务拆分成11个节点,就只需要11个时钟周期就能完成任务。在这种情况下,31个Stage的3GHz主频的CPU,其实和11个Stage的1GHz主频的CPU,性能是差不多的。事实上,因为每个Stage都需要有对应的Pipeline寄存器的开销,这个时候,更深的流水线性能可能还会更差一点。

另外,流水线并不能缩短单条指令的响应时间这个性能指标,但是可以增加在运行很多条指令时候的吞吐率。因为不同的指令,实际执行需要的时间是不同的。举个例子,我们顺序执行这样三条指令

  • 一条整数的加法,需要 200ps。
  • 一条整数的乘法,需要 300ps。
  • 一条浮点数的乘法,需要 600ps。

如果我们是在单指令周期的CPU上运行,最复杂的指令是一条浮点数乘法,那就需要600ps。那么三条指令都需要600ps,因此三条指令的执行时间就需要1800ps。

如果我们采用的是6级流水线CPU,每一个Pipeline的Stage都只需要100ps。那么,在这三条指令的执行过程中,在指令1的第一个100ps的Stage结束之后,第二条指令就开始执行了。在第二条指令的第一个100ps的Stage结束之后,第三条指令就开始执行了。这种情况下,这三天指令顺序执行所需要的总时间,就是800ps。那么在1800ps内,使用流水线的CPU比单指令周期的CPU就可以多执行一倍以上的指令数。

虽然每一条指令从开始到结束拿到结果的时间并没有变化,也就是响应时间没有变化。但是同样时间内,完成的指令数增多了,也就是吞吐率上升了。
在这里插入图片描述

在这里插入图片描述
看起来很好,但是却也带来了极大的缺陷:
(1)第一个就是功耗问题

  • 提升流水线深度,必须要和提升CPU主频同时进行。因为在单个Pipeline Stage能够执行的功能变简单了,也就意味着单个时钟周期内能够完成的事情变少了。所以,只有提升时钟周期,CPU在指令的响应时间这个指标上才能保持和原来相同的性能。
  • 同时,由于流水线深度的增加,我们需要的电路数量变多了,也就是我们所使用的晶体管也就变多了。
  • 主频的提升和晶体管数量的增加都使得我们 CPU 的功耗变大了,将会导致耗电和散热严重。这就导致了即使性能再好,但是别人的笔记本可以用上 2 小时,你的只能用 30 分钟

(2)上面说的流水线技术带来的性能提升,是一个理想情况。在实际的程序执行中,并不一定都能做到

  • 比如说,下面三条指令:
int a = 10 + 5; // 指令 1
int b = a * 2; // 指令 2
float c = b * 1.0f; // 指令 3
  • 我们会发现,指令2,不能在指令1的第一个Stage执行完成之后进行。因为指令2,依赖指令1的计算结果。同样的,指令3也要依赖指令2的计算结果。这样,即使我们采用了流水线技术,这三条指令完成的时间,也是200 + 300 + 600 = 1100 ps,而不是之前说的 800ps。而如果指令 1 和 2 都是浮点数运算,需要 600ps。那这个依赖关系会导致我们需要的时间变成 1800ps,和单指令周期 CPU 所要花费的时间是一样的。
  • 这个依赖问题,就是我们在计算机组成里面所说的冒险(Hazard)问题。这里是数据冒险,在实际应用中,还会有结构冒险、控制冒险等其他的依赖问题。
  • 对于这些冒险问题,我们可以有乱序执行、分支预测等响应的解决方案

但是,流水线越长,这个冒险的问题就越难解决。这是因为,同一时间同时在运行的指令太多了。如果我们只有三级流水线,我们可以把后面没有依赖关系的指令放到前面来执行。这个就是我们说的乱序执行的技术。

比方说,我们可以扩展一下上面的 3 行代码,再加上几行代码。

int a = 10 + 5; // 指令 1
int b = a * 2; // 指令 2
float c = b * 1.0f; // 指令 3
int x = 10 + 5; // 指令 4
int y = a * 2; // 指令 5
float z = b * 1.0f; // 指令 6
int o = 10 + 5; // 指令 7
int p = a * 2; // 指令 8
float q = b * 1.0f; // 指令 9

  • 我们可以不先执行 1、2、3 这三条指令,而是在流水线里,先执行 1、4、7 三条指令。这三条指令之间是没有依赖关系的。然后再执行 2、5、8 以及 3、6、9。这样,我们又能够充分利用 CPU 的计算能力了。
  • 但是,如果我们有30级流水线,就意味着我们要确保这20条指令之间没有依赖关系。这个挑战一下子就变大了很多。

总结

流水线技术和其他技术一样,都讲究一个“折衷”。一个合理的流水线深度,会提升我们CPU执行计算机指令的吞吐率。我们一般用IPC(Instruction Per Cycle)来衡量CPU执行指令的效率。

IPC,就是CPI(Cycle Per Instruction)的倒数。也就是说, IPC = 3 对应着 CPI = 0.33

过深的流水线,不仅不能提升计算机指令的吞吐率,还会加大计算的功耗和散热问题。而流水线带来的吞吐率提升,只是一个理想情况下的理论值。在实际的应用过程中,还需要解决指令之间的相互依赖问题。这个使得我们的流水线,特别是超长的流水线的执行效率变得很低。要想解决好冒险的依赖关系问题,我们需要引入乱序执行、分支预测等技术

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值