上节课学习了指令集体系结构,实际上是软件和硬件间的接口,可以分为两类,即精简集和指令集。在复杂集的发展过程中,逐渐吸收了精简集的思想,虽然外部输入的是复杂集体系接口,但会在内部分解为微指令。
流水线技术的设计思想
- 单周期处理器:一个指令周期内只能完成一条指令的执行。单周期处理器的六个阶段是串行工作,在某一时刻只有一部分硬件工作,硬件利用率低。
- 为此,我们采用了流水线技术,流水线既是一种思路,又是一种处理器处理结构,按照此思想设计出来的处理器结构称为流水线结构
以洗车为例理解流水线的思想
洗车行相当于处理器,车相当于指令。
- 当洗车行只有一个人时,相当于单周期处理器
- 若三个人同时洗一辆车,相当于并行计算机的多核处理器。由于在洗车过程中有些工序相互干扰,如洗外边的与洗里边的不能同时洗,所以花费时间并不会由于投入人多而成倍减少。这种方式称为全并行
- 若采用了流水线作业,把洗车分为三道工序,每人只负责一道工序。假设洗一辆车需要30分钟,从微观(单辆车)看,全并行至少需要10分钟(三人互不干扰前提下),流水线责任至少需要30分钟,还不算转工序的时间;但是从宏观(车络绎不绝)看,只需10分钟就一辆车。
- 所以,在处理器设计时,我们采用了组合逻辑电路优化单周期处理器。组合逻辑电路分为运算和储存部分,时钟周期不能小于运算与存储的时间之和(300+20=320ps)。我们采用流水线思想进一步优化,将运算部分均分为三个阶段,前一阶段的输出等于后一阶段的输入,并在每一阶段后插入储存部件,将上一级计算结果存储到存储部件中。当时钟周期处于上升边沿时,数据才能存储到存储部件并传入下一阶段中。
- 我们以上边所述的三阶段流水线为例,一条指令从执行到结束需要3个时钟周期。尽管存储器会有时间开销(20ps),但是时钟周期仅有120ps。这样从微观上看,一条指令执行需要360ps,多于300ps;但是当流水作业时,只需一个时钟周期120ps就可以完成一条指令,更快。而且全并行一个时间点上只有一部分部件工作,流水线则源源不断工作,提高了硬件利用率。
- 因此流水线就是把一个时钟周期只能执行一条指令,改为可以多个时钟周期执行一个指令。从而降低了时钟周期,提高处理速度
流水线设计中遇到的挑战
非均匀划分
- 在实际处理器设计中,很难将处理器等分成三份。因为每部分功能不同,无法保证每部分完成功能消耗时间相同。而时钟周期要保证每个部件能正确完成结果的计算,就要以最慢的部分为准。因此,提高最慢部分的速度对于提升整体性能最为关键,提升快的部分是不管用的
流水线划分的越细,是否就会收益越高
- 若各部分是均分的,性能确实会一直提高,但是性价比到后期会降低。如将三阶段再细分为6阶段,中间需要插入5个储存电路。从单周期到3阶段,性能提升两倍多;而从3阶段到6阶段却只提升了一倍多。因此确实性能提升,但提升的会越来越慢。而且有效计算时间比会越来越低,存储时间开销占比会越来越大(引入的存储部件过多)。伴随着储存部件加的越来越多,成本提高,且对于单条指令的执行而言,时间变长。因此我们要有trade-off折中概念:在成本和性能间找到一个平衡点。
- 若各部分不均分,则不一定性能提升提高。需要看进一步细分的是哪个部分,如果是最慢的部分,性能会提高;如果是快的部分,性能不会提高。
一般流水线处理器包括5个阶段:取址、译码、执行、访存、写回
- 与指令执行的6个阶段不同,程序计数器的更新合并到了取址当中。因为取址和程序计数器的更新计算量非常小,就算合并到一起,仍然比最慢的阶段快。
- 执行、访存是最慢的阶段。因为执行的运算逻辑比较复杂,而访存需要访问内存,比较慢
- 后来,又对较为复杂的执行和访存阶段做了进一步划分,以缩短时钟周期。
现代处理器设计中遇到的挑战:理想情况下指令的执行是非常罕见的
数据依赖问题
- 指令与指令间的数据有依赖。前边指令运算得到的值在后边指令中会用到,这在单周期处理器中完全没有问题,但在多周期处理器中,若第一条指令还没执行完,就到了第二条指令需要用到数据的阶段,就会出现问题
- 针对这种问题,有两种解决方式。一是在指令中插入延迟,如指令2的B阶段要用到指令1的计算结果,就在b阶段前插入一个气泡,使处理器空一拍(所有指令都滞后一拍),先让指令1算完。即通过插入气泡,把某些并型指令串行化。但是在流水线中气泡插多了性能会下降,而这种情况又是非常常见的。
- 二是现代处理器常用的一种解决方式:乱序执行。在不影响流水线性能的前提下,打乱执行顺序(但不改变最终逻辑)。对于指令顺序的重新安排由硬件完成,将指令加载到指令池中,分析依赖关系,重新组织顺序,再送入流水线,使其满负荷运行。
控制依赖问题
- 流水线执行时,若有跳转指令,后边加载的指令是哪条不好说。只有等跳转指令的结果计算出来,即跳转指令执行完后,才知道执行哪条指令。若发生跳转,原本后边执行的指令就需要抛弃掉,引起改变的还需要复原。这也导致了流水线的清空,效率降低
- 目前主要采用分支预测方式解决这类问题,即先猜一下会不会跳转,或者跳转到那里去。
- 动态分支预测:根据经验猜测。如for循环第一次在某条指令跳到某个地址,后边处理器到那条指令就会自动往那个地址跳,这样最后只有两次会出错,一个是第一次,一个是最后一次。现代处理器中,动态分支预测技术成功率已经到达90%以上。联想到rep:ret,rep是空指令,啥都不做,只是因为前边有跳转指令,两个跳转指令不能连续使用,因此用rep空指令隔开。这是由于动态分支预测的局限,不能预测连续的两次跳转目标。因此虽然插入空指令,但效率提升。尽管浪费了一个节拍,但避免了流水线清空
- 静态分支预测:不是由处理器实现,而是由编译器实现。如在gcc编译器中就内置了 函数。根据可能性大小决定将哪个分支放在跳转指令紧后边,使得下边执行的指令就是逻辑执行的指令
- 也可以采用条件数据传输解决,即先算出来
未来处理器的发展趋势
- 超标量技术。将执行阶段细分,设计了4个算数运算部件,还设计了一些数据加载、数据储存部件。相当于将执行阶段看做多个并行,前边的取址阶段是串行。这样将执行阶段并行,从宏观上看缩短了单条指令的执行时间。可比作银行先排队取票,后多个窗口服务。即在单核处理器中,使局部某些指令实现全并行的效果
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。