内存屏障会阻止分支预测吗?

Do memory barriers prevent branch prediction?

本题不假设任何特定架构。 假设我们有一个具有高速缓存一致性、乱序执行和分支预测逻辑的多核处理器。我们还假设存储到内存中严格按照程序顺序。

我们有两个线程 运行 并行,每个都在一个单独的核心上。

以下是线程的伪代码。 dataflag 初始为 0。

线程 #1 代码:

data=10;
flag=1;

线程 #2 代码:

while(!flag);
print data;

通过适当的同步,线程 #2 最终会打印 1。但是,分支预测器可能会预测未进入循环,从而执行对 data 的推测性读取,其中当时包含 0 (在线程 #1 设置 data 之前)。预测是正确的,即“flag”最终设置为 1。在这种情况下,print data 指令可以退出,但它打印出不正确的值 0。

问题是内存屏障是否会以某种方式阻止 data 的推测读取,并导致 cpu 正确执行忙等待。另一种解决方案可能是让分支预测器完成它的工作,但监听另一个核心完成的写入,如果检测到对 data 的写入,我们可以使用 ROB 撤消过早读取(和它的相关指令),然后使用正确的数据重新执行。

也欢迎特定于 Arch 的答案。

不,b运行ch 预测 + 推测执行在具有内存屏障的 ISA 中很好,只要错误推测被正确杀死。

thus perform a speculative read of data, which contains 0 at that time

当 CPU 检测到错误预测时,将丢弃来自错误推测的执行路径的指令,以及它们对体系结构寄存器的影响。

当正确的执行路径最终退出循环时,然后内存屏障将运行(再次),然后 data 的负载将 运行(再次)。事实上,他们早些时候 运行 在错误预测的 b运行ch 的阴影下没有影响。

您的伪代码汇编不是很清楚,因为它使 print data 看起来像一个单一的操作。事实上,它将涉及加载到寄存器中,然后是 call print 指令。

data 在正确的路径上加载 运行 时,它将不得不重做从缓存中读取值的工作,并且 缓存在核心之间是一致的。错误推测的负载是否将缓存行带入该核心的 L1d 缓存并不重要;另一个核心的商店必须先使其无效,然后该商店才能变得全局可见。

看到exit!=0后循环退出;之后的障碍确保以后的加载还没有发生,为 exit 的加载提供 acquire 语义(假设它包括阻塞 LoadLoad 重新排序)。

在正确路径上执行的屏障确保该核心等待失效而不是使用早期加载。

编写器中的存储/释放屏障确保新的 data 值在 exit = 1 对任何内核上的任何其他线程可见之前是全局可见的。