我们首先来解释一下什么是内存混淆问题:采用乱序执行方式的处理器在面对多个load和store操作的时候也可以进行乱序执行,但是首先需要保证程序进行load和store操作的正确性。直观上这个问题与缓存一致性问题类似。下图是一个内存混淆现象的例子:第2个store操作与第9个load操作针对的是同样的内存地址,因此第9个操作不能移动到第2个操作之前执行,否则程序会得到错误的结果。但是很明显,第9个操作可以移动到第8个操作之前执行,因为它们针对的是不同的内存地址。然后,因为不知道第5个操作针对的内存地址,所以也就不能确定第9个操作是否可以移动到第5个操作之前执行。
内存混淆问题示例
判断2个内存操作(通常是一个load操作与一个store操作)是否针对同一个内存地址的过程,也就是判断是否会发生内存混淆现象的过程,称为内存相关性预测(Memory
Disambiguation)。如果这2个操作针对不同的内存地址,那么它们就可以乱序执行。看似很简单,但是问题在于:为了对1个load操作的相关性进行预测,存储单元需要把它与缓冲区内所有的store操作进行比较,代价十分昂贵。
在古老的 P6
微架构中,这个问题是这样解决的:把store操作分成2步,首先计算内存地址,然后再真正存储数据。这样,store操作的内存地址就可以提前获得,从而可以比较容易的检测内存混淆问题。P6
微架构的内存乱序缓冲区(Memory Reorder
Buffer,简称MOB)采用如下的规则:如果在乱序执行窗口中存在与某load操作内存地址相同的store操作,则该load操作不能提前执行;如果在乱序执行窗口中存在内存地址未知的store操作,则任何load操作不能提前执行;某store操作不能提前到另外一个store操作之前执行。
这样的规则虽然可以保证程序进行load和store操作的正确性,但是也丧失了一些本来可以提高执行效率的机会:比如当某load操作之前存在某内存地址未知的store操作的时候,很可能内存地址是不同的,因此该load操作本来可以提前执行的。研究表明,实际发生内存混淆现象的概率非常小。所以,一个更加合理的做法是:假设所有的load操作与store操作之间都不发生内存混淆现象,而当错误发生的时候再进行恢复。这样做显然会有更高的效率。
Core 微架构正是采用了这种更加高效的做法:P6 微架构和 NetBurst 微架构中采用的保守的规则被丢弃了,load
操作可以在内存地址未知的store操作之前执行。这样的话,当有错误发生的时候,处理器流水线将不得不暂停运转。然而就像前面讲到的,这种情况并不多见。为了最大限度的避免这种情况的出现,Core
微架构加入了一个动态的内存相关性预测器,根据历史信息来预测load操作的移动是否可行。据有关人员透露,该预测器的预测正确率达到90%以上。
下图的例子说明了Core 微架构的这种工作方式在多数情况下会带来的性能提升:P6 微架构需要9个时钟周期才能执行完的操作,Core
微架构只需要5个时钟周期。
Core 微架构的内存相关性预测
为了使读者真正认识到内存相关性预测和Core
微架构在内存相关性预测方面的改进的重要意义,我们举另外一组数据来说明。实际的X86程序中,一般有1/6左右的操作是store操作,1/3左右的操作是load操作。Core
微架构的乱序执行窗口能容纳96个操作,假如没有内存解疑技术,那么,占据乱序执行窗口一半左右的40~60个操作将只能顺序执行,这肯定将造成极大的资源浪费。这个时候,效率良好的内存相关性预测功能将带来本质上的性能提升。
(责任编辑:刘伟) |