介绍
因为需要乱序执行指令以便减少数据冲突,需要采用动态调度的方法。动态调度可以通过软件或者硬件的方式进行实现。接下来介绍什么是动态规划以及其特点。
动态调度(dynamic scheduling)
动态调度是通过逐步获得的消息,重新安排指令的顺序。
个人理解这里逐步获得的消息指,在issue过程中得知不同指令的依赖。如果前部指令依赖未执行完的指令,动态调度就会选择别的没有依赖的指令进行issue。
动态调度的要点
*动态调度的池子(instruction window)需要比较大才能保证找到独立的指令。
*遇见中断能把乱序执行的指令回滚成顺序的状态。
*能迅速issue指令。(寄存器的依赖可以很快判断,但是涉及memory的依赖就需要时间并且更麻烦)
个人理解动态调度有软件优化和硬件的实现组成。
编译器需要对指令进行loop unrolling以提高找到独立指令的几率。(变相提高动态调度的池子)
例子(出现了WAW冲突,但是可以靠register renaming去除,之后详解)
这个例子不知道恰不恰当。(不太清楚j指令有没有依赖)
1 | #r2 = 1000 |
#改循环已经运行了一段时间
instruction | beq r1,r2,#2 | addf r1,r1,#1 | j loop | beq r1,r2,#2 | addf r1,r1,#1 | j loop |
---|---|---|---|---|---|---|
dependency | r1 | r1 | none | r1 | r1 | none |
如上述例子,因为beq和adddi有依赖的关系。当addf还在计算中,因为addi可以通过register forward不需要等待 ,但是浮点数的运算需要花更多的时间,所以后续的beq需要等待addf完成才能运算,尽管运用了乱序的动态调度。但是如果运用了loop unrooling。
1 | #r2 = 1000 |
instruction | beq r1,r2,#2 | addf r1,r1,#1 | addf r1,r1,#1 | addf r1,r1,#1 | addf r1,r1,#1 | j loop |
---|---|---|---|---|---|---|
dependency | r1 | r1 | WAW | WAW | WAW | none |
如上述例子就可以从软件上解决动态调度的问题,以上例子不太准确,可能有很多问题,但是大致思路是loop unrolling释放更多指令池,方便有依赖时调用独立的指令。
硬件则需要全部实现动态调度,因为少一些面向软件的接口,硬件能更快速,更节省占用面积。