MIPS pipeline:
理想形式: 每一个周期执行一条指令
问题:控制冒险
IFU每次需要等待IDU解码后确定下一条,相当于两个周期才执行一条指令.
“Every instruction takes two cycles ”
缺陷:2个周期执行一条指令太保守了,浪费周期。
(1) simple prediction: next PC = PC +4
大多数程序中:跳转指令20% (其中70%taken,30%not taken)
50%的forward taken :if-then-else……
90%的backword taken:loop……
缺陷:Acc = 0.8 + 0.2*0.3 = 0.86,所以simple prediction有14%的错误率,出错的时候需要冲刷指令。如果在EX阶段发现:需要冲刷IFU和IDU的两条指令,这样就损失了两个时钟周期。在ID阶段发现冲刷IFU,损失一个时钟周期。(冲刷时遇见了数据冒险被阻塞的数据怎么办?如果是超标量处理器错误代价如何?)
如果基于simple pre,如何提升性能?
Approach 1:(不改变跳转指令数量)
-software:编译器改变指令的顺序(要求编译器尝试运行代码)
-hardware:cache保留指令执行历史纪录,遇到相同指令按照上次经验跳转(trace cache)
Approach 2:减少跳转指令
融合编译条件(缺点:类似 && 的短路无法使用,需要考虑全部判定条件。但是C语言的编译规定了必须一个个执行判断条件,如果编写代码时使用了短路,那么程序可能出错)
将branch指令转换为顺序执行指令,但是是否执行取决于当时环境(如数据依赖)
如C语言的 ?:条件赋值,指令CMOV就有相似功能(需要ISA支持):如果其condition不满足,则相当于noop,不影响CPU执行。
if(a == 10)
b = 1
else
b = 7
使用CMOV语句,可以看见没有跳转语句(性能有区别吗?)
CMPEQ condition, a, 10#condition = (a == 10)
CMOV condition, b<-1
CMOV !condition, b<-7
代表处理器:
(1)Intel Itanium(有点失败?)
+64-bit predicted register
+每一条指令前面都有一个谓词(6 bit,用来指示以p register哪一位作为condition判断)进行条件执行,保证顺序执行指令。
(2)ARM处理器
ARM指令集每一条指令前都有四位condition code,能进行谓词执行。具体实现为向指令添加后缀
如:ADDEQ 为cond满足时执行,cond用来判断提前置位的flag位
谓词执行优点: branch很少,指令顺序执行,进而也给了编译器更大的代码调整空间
谓词执行缺点: condtion 始终要执行,浪费计算资源(相当于把所有条件都判断了,所以性能不一定优于分支预测,而需要ISA的支持,指令格式必须设计好:如cond位)
将branch指令后面填充一定会执行的指令(delay slot : MIPS使用)
问题: 如何找到能被填充的指令?+ 如何确保这些指令和跳转相互独立?
delay slot来源:
(1)From Before: safe
(2) From target: 如果没有跳转,那么需要消除执行该指令的影响
(3) From fall-through:如果跳转了,需要消除影响
需要编译器挑选合适的指令作为delay slot
优点: 可以让流水线利用更充分,本来被冲刷的周期用来执行。
缺点: 难以控制delayed slot的数量,可能有一个或者多个,数量多了难以去找足够多的无关指令,增加编译器难度。(ISA一般规定了delay slot数量,但是也将微架构固定了,同时也将处理器对slot的处理暴露给了程序员)
代表处理器:SPARC——Delayed branch with squashing(压缩)(比较老的处理器喜欢用delay slot)
没有采用delayed的循环跳转代码
采用后,branch指令的下一条变为跳转目标指令A’。当跳转发生,delayed slot A’ 为A;当跳转不发生,A’为nop
多个线程同时在处理器执行,降低数据与控制的依赖性。
经典处理器:CDC 6600——在外设IO中使用该技术
需要多个PC与GPR对应执行的多个线程,并设置相应的选择器记录工作线程序号(单独开一条数据线传送线程序号,随指令流水)
代表处理器:SUN-Niagara 使用该技术,也增加了cache和instruction的buffer
同时便需要Thread Scheduling:
(1)固定分配周期
(2)软件(software)控制分配:如果给某线程分配的多,那么仍然可能发生冒险
(3)硬件(hardware)控制分配:相对于软件分配,更了解线程执行状况,发生冒险的可能更低。
优点: 理想中没有控制,数据冒险,不需要bubble,吞吐量上去了
缺点: 需要更多硬件支持(GPR,线程选择逻辑);单线程性能下降(原来不需要插入其他线程),latency上升,其他线程也会占用cache,memory等内存资源;不同线程指令不相关只是理论上的,线程是共享一块地址空间的,还是有一定相关性的。
有条件跳转两条路径一块儿执行,哪条不执行扔掉就可以了。
优点: 不会预测错误,只需要增加两路执行的相关设置,比较简单
缺点: 路径数量会指数级增长,浪费资源(每条路径需要自己的PC,GPR等,直到发现执行错误)
通常不如谓词执行(谓词执行在merge后就不会重复执行了)和预测执行。
在超标量处理器或者大规模并行(GPU)才可能考虑多路径执行。