原理篇-CPU

 

要点:

选择最合适的指令,调整指令布局使其符合流水线处理,尽可能地去除分支以及提高Data Cache的数据读写效率,减少因数据读写带来的流水线停顿,这些都是提高CPU使用性能的关键。

 

讨论:

现代CPU是多级流水线的超标量结构,每个时钟周期可以执行多个操作。CPU可以分为两个部分,一部分是指令控制单元(ICU),另一部分是执行单元(EU)。

ICU的取指单元从Instruction Cache中读取指令,译码单元翻译指令,将相关操作送到执行单元,执行单元从Data Cache加载数据,执行相关操作,再写回Data Cache。这个过程中,取指,译码,加载,执行,写回都可以由独立的硬件单元来执行,这就构成了一个5级流水线结构。流水线级数越多,单位时间执行的指令越多,微观上的并行性越强。但过多的级数又带来一个问题,就是分支的问题。在处理一个分支时,程序有两个可能的方向,一个是继续执行下条指令,一个是跳转到另一个指令。假如流水线是按代码顺序来操作,而这个分支没有跳转,那么一切都很完美。但如果不幸这个分支跳转了,那很不幸,流水线所有前期的工作都白费了,流水线被清空,取指单元重新开始取指,而译码,加载,执行,写回等所有单元要等待新的工作到来。用术语来说,就是流水线停顿了。所以现代CPU又引入了分支预测技术,根据局部性原理,80%的分支方向是可以统计出来的。但如果分支的两个方向的概率各为50%,那么分支预测的效率就大打折扣了。如果有频繁的分支,同时分支预测又频繁的出错,那流水线将频繁的停顿,这对性能的影响是巨大的。尤其是在内部循环里,频繁的分支预测出错常常成为代码低效的元凶。

       理解了流水线,汇编程序员的主要工作就是要调整指令布局,使得指令间的数据相关性

降到最低,这样就保证了流水线能顺畅的运转。另外选择合适的指令以及运用一些汇编程序的技巧可以减少指令的数量,以及提高单位时间内的计算的吞吐量。这一部份是CPU相关的,如ARMv4的乘法指令需要两个时钟,而ARMv5的乘法指令和加法一样只要一个时钟。又如在ARMv5E有饱和指令,ARMv6ARMv7上都有SIMD指令,这些都是程序员需要认真考虑的。

       最后非常重要的一点是Data Cache的读写问题。和分支一样,低效的Data Cache读写也会导致流水线停顿。这里不讨论Cache Miss,因为Cache Miss不是CPU这一级能够解决的。就读写而言,有几个原则要遵循。

1,设计时尽量减少读写,如果有预取指令,可以提早预取数据,以减少数据延迟。

2,尽量按CPUData Cache的总线带宽来读写,ARM的这部分带宽是32位,也就是按字(4 bytes)读写效率是最高的。

3,合并读写指令,连续的读或写可以提高总线的利用率。

你可能感兴趣的:(原理篇-CPU)