【发布时间】:2017-08-06 19:17:05
【问题描述】:
众所周知,x86 架构由于使用了写缓冲区而没有实现顺序一致性内存模型,因此可以发生存储->加载重新排序(可以提交稍后的加载,而早期的存储仍然驻留在写缓冲区中等待提交到 L1 缓存)。
在A Primer on Memory Consistency and Coherence 中,我们可以了解 Total Store Order(TSO) 内存一致性模型(应该与 x86 非常相似)中的 Read-Modify-Write(RMW) 操作:
...我们认为 RMW 作为负载,紧随其后的是存储。负载部分 由于 TSO 的订购规则,RMW 无法通过较早的负载。它 乍一看,RMW 的负载部分可能 在写入缓冲区中传递较早的存储,但这是不合法的。如果 RMW 的加载部分通过较早的存储,然后是存储 部分 RMW 也必须通过较早的商店 因为RMW是一个原子对。但是因为商店没有 允许在TSO中互相通过,RMW的负载部分不能 也可以通过较早的商店。
好的,原子操作必须是原子的,即RMW访问的内存位置在RMW操作期间不能被其他线程/内核访问,但是,如果较早的存储通过原子操作的加载部分不是与RMW访问的内存位置有关?假设我们有以下几条指令(伪代码):
store int32 value in 0x00000000 location
atomic increment int32 value in 0x10000000 location
第一个存储被添加到写入缓冲区并等待轮到它。同时,原子操作从另一个位置(甚至在另一个缓存行)加载值,传递第一个存储,并在第一个存储之后将存储添加到写入缓冲区中。在全局内存顺序中,我们将看到以下顺序:
加载(原子的一部分)-> 存储(序数)-> 存储(原子的一部分)
是的,从性能的角度来看,这可能不是最佳解决方案,因为我们需要将原子操作的缓存线保持在读写状态,直到写入缓冲区中的所有先前存储都被提交,但是,除了性能考虑之外,是否存在违反 TSO 内存一致性模型的情况,我们是否允许 RMW 操作的加载部分将较早的存储传递到不相关的位置?
【问题讨论】:
-
如果您使用指令对(加载链接存储条件)来实现原子增量操作,我看不出您建议的顺序有什么问题。但是,如果是单条指令,那是不可能的,因为 atomic 的加载部分变成了微操作,我们正在尝试混合操作和微操作,可能不是一个好主意。
-
@IsuruH 在 x86 上它是一条指令。但是这种混合有什么问题呢?微加载操作不等待之前的存储并从缓存中获取值,而微存储操作只是将结果放入写入缓冲区。
-
@IsuruH 在 x86 上,RMW 操作使用
lock前缀实现,除其他外,它可以在原子指令执行期间将高速缓存行保持在 M 状态。一旦指令退出,锁就会被释放,所以,是的,将 RMW 操作的存储部分放在写缓冲区中可能会违反操作的原子性,因为从存储被放置到它被写入缓存的时间其他核心可以访问旧值。所以它特别给出了我的问题的答案,尽管它是一个实现细节而不是 TSO 的概念限制。 -
谢谢!!您的评论和@Leeor 回答解释了为什么不能这样做。但是在我看来,从技术上讲,您可以允许在原子操作的读取和写入之间耗尽存储到不同的缓存行。我对微操作的了解有限,所以我不确定您将如何重新排序指令的某些部分,对我来说,重新排序发生在指令级别。
-
@IsuruH AFAIK,即使没有 CPU 对指令进行实际重新排序,这种“重新排序”也可能发生。即使您有一个带有单个管道和按顺序提交的标量 CPU,您只需要立即从缓存或写入缓冲区加载值(如果它包含到所需位置的最近存储),但是将存储推送到写入缓冲区,从而延迟他们。在这种情况下,即使是微操作,Store->Load memory 操作的全局顺序也会改变。
标签: x86 atomic cpu-architecture memory-barriers memory-model