介绍
这篇博文将介绍顺序流水线及其特点和弊端,同时引入乱序流水线。
什么是流水线
标准的流水线为Fetch,Decode,Execute,Memory,Write Back,五个阶段。通过把一个完整的指令分解成五个部分后,一个指令的超长的关键路径(critical path)分割成五个较短的模块。
流水线的频率就能提高:
通常这个系统能跑多快取决于这个关键路径的长度,因为关键路径越长,延时就会变长导致高频率的系统无法正常工作。但是当绝对路径被拆分成五个阶段了以后,频率就能提高约五倍。
增加吞吐量(throughput):
因为运用了流水线,系统可以不需要处理完一条指令后才能执行下一条。以五个模块为单位,当信号走过第一个模块后,下一个指令就可以被执行。所以虽然单指令的延迟(latency)变长了,但是吞吐量会大幅度变大。
顺序流水线特点
以上的流水线为顺序的流水线,顺序流水线比较简单,但是有不少问题影响效率。
1: 数据冲突(RAW)
当写入寄存器还没完成的时候,读取该寄存器的值会是错误的,所以整个流水线必须等写入指令完成了才能继续。浪费时间。
2:结构冲突(structure hazard)
当之前的模块还在计算运行的时候,之后的指令必须等模块闲置了才能继续。浪费时间。
举例:
1 | ld f2,x{ro} |
周期 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
F | D | E | M1 | M2 | M3 | W | |||
F | D | d* | d* | d* | E | W | |||
F | p* | p* | p* | p* | E | W |
上述流水线显示d*表示f2数据还没有从内存中读取出来,所以f2+f3的操作需要暂停,直到f2数据准备好。这是数据冲突中的一种:写后读(read after write)。
上述流水线显示p*表示decode译码单元还在忙碌,所以需要等待译码单元结束,后续指令才能继续。
小总结
一些冲突的出现会让剩下的指令全部进入等待的状态,所以如果有一个乱序的流水线,在一个指令进入冲突的时候,启动其他独立的指令提高效率。
乱序流水线大致长什么样
因为需要乱序的流水线,所以乱序流水线需要具备以下功能
动态调度(dynamic scheduling)需要在指令被暂停时,优先执行那些独立的指令最大化效率。
寄存器重命名(register renaming)需要在乱序运行中把register destination重新命名。防止乱序运算中的WAW,WAR数据冲突。
精准中断(precise interrupt)需要在中断生效的时候,把乱序运算的一些跳跃的指令回滚到正确的位置。
乱序流水线较为复杂,所以今天暂时做一个介绍,接下来慢慢介绍各个部分及产生的原因。