如何通过微体系结构实现障碍/栅栏以及获取,释放语义?

Rag*_*ghu 5 x86 x86-64 cpu-architecture memory-barriers micro-architecture

因此还有很多问题,例如https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2018.12.08a.pdf和Preshing的文章如https:/ /preshing.com/20120710/memory-barriers-are-like-source-control-operations/及其整个系列文章就不同的障碍类型提供的排序和可见性保证方面抽象地讨论了内存排序。我的问题是,如何在x86和ARM微体系结构上实现这些障碍和内存排序语义?

对于商店-商店壁垒,好像在x86上,商店缓冲区保持商店的程序顺序并将它们提交到L1D(因此使它们以相同的顺序在全局可见)。如果存储缓冲区未排序,即未按程序顺序维护它们,那么如何实现存储障碍?它只是以这样的方式“标记”存储缓冲区,即在屏障提交之前将存储提交到缓存一致性域,然后在屏障之后提交?还是存储屏障实际上刷新了存储缓冲区并暂停了所有指令,直到刷新完成?可以同时实现吗?

对于负载障碍,如何防止负载重新排序?很难相信x86将按顺序执行所有加载!我假设加载可以乱序执行,但是可以按顺序提交/退出。如果是这样,如果一个cpu在2个不同的位置执行2次加载,那么一个加载如何确保它从T100中得到一个值,而下一个加载在T100上或之后得到它?如果第一个负载未命中高速缓存并正在等待数据,而第二个负载命中并获取其值,该怎么办。当负载1获得其值时,如何确保它获得的值不是来自该负载2的值的较新商店?如果负载可以无序执行,如何检测到违反内存排序的情况?

类似地,如何实现负载存储屏障(在x86的所有负载中都是隐含的)以及如何实现存储负载屏障(例如mfence)?即dmb ld / st和dmb指令在ARM上是如何微体系结构的?每个负载和每个存储区以及mfence指令在x86上如何进行微体系结构,以确保内存排序?

Pet*_*des 5

其他问答中已经涵盖了其中的大部分内容,但我将在此处进行总结。(并寻找要添加的链接)。不过,好问题,将所有这些都收集在一个地方很有用。


在 x86 上,每个 asm 负载都是一个 Acquire-load。为了有效地实现这一点,现代 x86 硬件比允许的更早地推测加载,然后检查该推测。(可能会导致内存顺序错误推测管道核弹。)为了跟踪这一点,英特尔将加载和存储缓冲区的组合称为“内存顺序缓冲区”。

弱序 ISA 不必推测,它们可以按任何顺序加载。


x86 存储排序是通过仅让存储按程序顺序从存储缓冲区提交到 L1d 来维护的。

至少在 Intel CPU 上,当它发出时(从前端到 ROB + RS)为存储分配一个存储缓冲区条目。所有 uops 都需要为它们分配一个 ROB 条目,但一些 uops 还需要分配其他资源,例如加载或存储缓冲区条目、它们读/写的寄存器的 RAT 条目等。

所以我认为存储缓冲区本身有序的。当存储地址或存储数据 uop 执行时,它只是将地址或数据写入其已分配的存储缓冲区条目。由于提交(释放 SB 条目)和分配都是按程序顺序进行的,我假设它在物理上是一个带有头和尾的循环缓冲区,就像 ROB。(与 RS 不同)。


避免 LoadStore 基本上是免费的:加载在执行之前不能退出(从缓存中获取数据)。商店退休才能提交。按顺序停用意味着所有先前的加载都在存储“毕业”并准备好提交之前完成。

一个可以在实践中进行加载存储重新排序的弱排序 uarch 可能会记分板加载:让它们在它们不是无故障的但在数据到达之前退休。

这在有序内核上似乎更有可能,但 IDK。因此,您可能有一个已停用的负载,但如果在数据实际到达之前有任何尝试读取它,则寄存器目的地仍将停止。我们知道,有序内核在实践中以这种方式工作,不需要在后面的指令可以执行之前完成加载。(这就是为什么使用大量寄存器的软件流水线在此类内核上如此有价值,例如实现 memcpy。在有序内核上立即读取加载结果会破坏内存并行性。)

如何通过有序提交实现加载-> 存储重新排序?更深入地讨论这一点,对于有序与无序。


屏障说明

对常规存储执行任何操作的唯一屏障指令mfence实际上是停止内存操作(或整个管道),直到耗尽存储缓冲区。 加载和存储是唯一被重新排序的指令吗?也涵盖了 Skylake-with-updated-microcode 行为lfence

lfence主要是为了阻止后续指令发出的微体系结构效应,直到所有先前的指令都离开乱序后端(退休)。用于lfence内存排序的用例几乎不存在。

有关的:

  • @Raghu:是的,我想是的。就像我说的,对于有序核心来说,在检查它们没有故障后加载记分板很容易。(即肯定会发生,类似于位于存储缓冲区中等待提交的退役存储)。只要没有指令尝试读取目标寄存器,加载就可以在等待高速缓存未命中时延迟任意长的时间。x86 具有强排序内存模型(并且需要加载-加载排序),因此 x86 不会尝试此操作,但弱排序核心可能被设计为这样做。也许甚至还有OoO。我必须用谷歌搜索真实的例子。 (2认同)

归档时间:

查看次数:

72 次

最近记录:

5 年,11 月 前