指令级并行
参考
《程序性能优化理论与方法》
先进编译实验室
指令流水
指令可以分为取指、译码、执行、访存、写回五个阶段
处理器内部的流水线超过5至6级以上就可以称为超级流水线,又叫做深度流水线。
超级流水线对提升处理器的主频有帮助,但流水线级数越多,同一时刻重叠执行的指令就越多,可能会导致存在相关性的指令间发生冲突,造成处理器的高频低能。
指令相关包括数据相关、结构相关和控制相关
数据相关
如果指令A产生的结果会被指令B用到,则说指令B对指令A存在数据相关性。可以通过相关性分析,在保持指令相关性不变的情况下改变指令顺序,将不相关指令插入停顿周期以解决流水线停顿的问题
结构相关
结构相关性是指两条指令使用相同名字的寄存器或者储存单元,并且两条指令之间不存在数据的传递。结构相关性包括反相关性和输出相关性
![结构相关性](./ProgramPerformanceOptimization/结构相关性.png)
控制相关
控制相关使得指令的执行顺序不确定,因此会造成流水线的停顿。
当指令流水线上出现控制相关时,有两种处理方法。
- 等流水线上的指令执行结束后,根据分支指令的执行结果进行跳转,但会造成指令流水线的停顿
- 预测分支指令执行的结果,选择某一条分支的指令填入流水线以避免流水线的停顿,如果分支预测正确流水线即可顺利运行,若分支预测错误,则需要清空流水线丢弃已经执行的结果,并执行正确的分支重新填充流水线。核心代码内含有较多的分支语句,将严重影响程序性能。Intel极力优化分支预测器的性能,ARM和主流GPU的设计中没有过多地考虑分支预测。
主流的编译器中会尝试破除指令的控制相关,但是一般仅对最内层循环中的简单控制流结构,对程序中形式复杂的控制相关语句则无能为力
处理方法
-
控制结构语句外提
-
控制转换
将控制相关转换为数据相关。if转换需要借助三元操作实现,形式为dst=cond?src1:src2,转换后产生的新语句由本身的逻辑表达式控制,语句之间没有控制关系。转换后还可以观察条件语句是否可以合并
指令多发射
程序的执行由一系列指令操作组成,为了节省程序的执行时间,发射单元可以一次发射多条指令,这就是指令的多发射并行。多发射处理器支持指令级并行,每个周期可以发射多条指令,一般为2-4条,这样可以使处理器每个时钟周期的指令数倍增,从而提高处理器的执行速度。
多发射处理器能对多条指令进行译码,将可以并行执行的指令送往不同的执行部件,因此处理器必须提供多套硬件资源,包括多套译码器和多套算术逻辑单元等。多发射处理器的每个发射部件上同样可以进行指令流水
指令多发射的方法有超标量(Superscalar)和超长指令字(Very Long Instruction Word,VLIW)两种,它们的不同之处在于并行发射指令的指定时间不一样。
超长指令字在编译阶段由编译器指定并行发射的指令,而超标量在执行阶段由处理器指定并行发射的指令。
超标量的硬件复杂性更高,超长指令字硬件复杂性较低。采用超标量技术的典型代表为x86处理器,x86处理器都含有乱序执行功能;采用超长指令字的典型代表为ARM和德州仪器TI,但是部分处理器也可能会采用超标量
超标量
超标量通常会配合乱序执行来提高并行性
超长指令字
超长指令字处理器的每一条超长指令装有多条常规的指令,并于同一时刻被发射出去。
超长指令字结构广泛应用于精简指令集(Reduced Instruction Set Computer,RISC)的处理器上,典型代表为(Digital Signal Process,DSP)数字信号处理器。
以德州仪器TI的C6000系列数字信号处理器为例。图中处理器有8个功能部件,理论上每个时钟周期处理器可以同时并行执行8条指令,这8条指令被看成是一个包。
超长指令字的并行指令执行由编译器来完成,因此编译器的优化能力直接影响到程序在超长指令字处理器上的性能。为了在超长指令字机器上获得更好的程序性能,优化人员可以通过修改汇编代码,指定每个多发射的超长指令。
如下面的汇编代码所示。指令2、指令3、指令4前面的“‖”,表示这条指令和上条指令在同一个周期执行,如果没有“‖”,则表示这条指令在下一个周期执行。
add R1, R2, R3 #指令1
‖ sub R1, R2, R6 #指令2
‖ mul R3, R4, R5 #指令3
‖ and R8, R6, R7 #指令4
超长指令字理想情况下在一个周期内将所有的部件利用起来,充分发挥处理器的指令级并行优势。
实际程序中受限于指令间的相关性以及指令的数量不足,往往不能充分发挥处理器提供的指令级并行优势。此时可以利用循环展开进行优化,发掘程序指令级并行性。