为什么存储负载障碍被认为是昂贵的



大多数CPU架构会重新排序存储加载操作,但我的问题是为什么?我对存储负载障碍的解释如下所示:

x = 50;
store_load_barrier;
y = z;

此外,与发布和获取语义相比,我不认为这种障碍在无锁编程中有多大用处。

简短回答:存储负载屏障可防止处理器推测性地执行存储负载屏障之后的 LOAD,直到所有以前的存储都完成。

详情

存储负载屏障昂贵的原因是它阻止了跨屏障的 LOAD 和 STORE 操作的重新排序。

假设您有一个如下所示的指令序列:

...             ;; long latency operation to compute r1
ST r1, [ADDR1]  ;; store value in r1 to memory location referenced by ADDR1
LD r3, [ADDR2]  ;; load r3 with value in memory location ADDR2
...             ;; instructions that use result in r3

当执行此序列时,r1的值将是需要很长时间才能完成的操作的结果。 指令ST r1, [ADDR1]必须停止,直到读取r1 同时,如果LD r3, [ADDR2]和其他指令独立于较早的存储,则无序处理器可以推测性地执行它们。 在提交存储之前,它们实际上不会提交,但通过推测性地执行大部分工作,可以将结果保存在重新排序缓冲区中,并准备好更快地提交。

这适用于单处理器系统,因为 CPU 可以检查 ADDR1 和 ADDR2 之间是否存在依赖关系。 但在多处理器系统中,多个CPU可以独立执行加载和存储。 可能有多个处理器正在执行 ST 到 ADDR1 和 LD 到 ADDR2。 如果 CPU 能够推测性地执行这些似乎没有依赖关系的指令,则不同的 CPU 可能会看到不同的结果。 我认为下面的博客文章很好地解释了这是如何发生的(我认为这不是我可以在这个答案中简洁总结的东西(。

现在考虑具有存储加载屏障的代码序列:

...             ;; long latency operation to compute r1
ST r1, [ADDR1]  ;; store value in r1 to memory location referenced by ADDR1
ST_LD_BARRIER   ;; store-load barrier
LD r3, [ADDR2]  ;; load r3 with value in memory location ADDR2
...             ;; instructions that use result in r3

这将防止在上一个存储指令完成之前推测执行LD r3, [ADDR2]指令和后续从属指令。这可能会降低 CPU 性能,因为整个 CPU 管道在等待 ST 指令完成时可能不得不停止,即使在 CPU 本身中,LD 和 ST 之间没有依赖关系。

可以做一些事情来限制 CPU 必须停止的数量。 但最重要的是,存储-负载屏障在负载和存储之间创建了额外的依赖关系,这限制了 CPU 可以执行的推理执行量。

相关内容

  • 没有找到相关文章

最新更新