clwb+sfence,如果写入是缓存行对齐的,我们可以删除 sfence 吗?

问题描述

根据 clwb 订购信息 (link),

"CLWB 指令仅由 store-fencing 操作排序。例如,软件可以使用 SFENCE、MFENCE、XCHG 或 LOCK 前缀指令来确保先前的存储包含在回写中。CLWB指令不需要由另一个 CLWB 或 CLFLUSHOPT 指令排序。CLWB 是隐式排序的,逻辑处理器执行旧存储到相同的地址。"

如果在 Intel X86-64 上的操作集如下,我是否可以删除围栏”并仍然确保正确性如果写入 (A) 和写入 (B)缓存行对齐

我问这个是因为在英特尔 Write(A) 和 write(B) 是有序的 (TSO) 和 write(A)->clwb(A)write(B)->clwb(B) 按照上面引用的 clwb

描述进行排序
write(A)
clwb(A)
sfence()
write(B)
clwb(B)

我做出以下假设

  1. 编译器不会对这些操作重新排序
  2. clwb() 指令将脏行回写到持久域,所以 write(A)->clwb(A) 对确保 A 的修改值在持久域中

请说明删除围栏是否会破坏正确性?如果是,在什么情况下 谢谢

解决方法

对于位于 相同 缓存行内的 WB 内存的正常存储:是的持久性顺序匹配 x86-TSO 全局可观察性顺序,请参阅 Is clflush or clflushopt atomic when system crash?。否则无法保证。

您的意思似乎是 A 完全包含在一个缓存行中,而 B 完全包含在一个单独的缓存行中。

如果没有 SFENCE,崩溃后可能会看到 B 的效果,但看不到 A。clwb 不是有序的,所以后者可以先使其存储持久化.这就是手册所指出的 clwb 没有订购 wrt。普通商店。

因此根据 TSO write(B) 发生意味着 write(A) 发生(可能是在存储缓冲区中)。

不,x86-TSO 排序是关于从存储缓冲区到 L1d(全局可观察性指针)的提交顺序。这当然与最终回写(通过驱逐或 clwb)到 DRAM 完全分开。存储 uops 可以以任何顺序执行(将它们的地址+数据写入存储缓冲区),但在退休后(即当它们是 non-speculative 时)才能提交。此外,该提交仅限于按程序顺序发生,即在发布/重命名/分配期间分配存储缓冲区条目的顺序。

意思是write(A)->write(B)是有序的,write(B)->clwb(B)是有序的,那么clwb(B)如何绕过write(B)[从而违反了manual的顺序约束] 并且发生在 clwb(A) 之前,从而导致 clwb(B) 的影响在崩溃后可见而不是 clwb(A)?

不,“与旧商店隐式订购...到相同地址”规则仅保证 store + clwb 到同一地址将回写包含该行的版本存储数据。否则,当最新的存储仍在存储缓冲区中或什至没有执行时,它可能会写回该行的副本。这并不意味着整个回写必须完成,然后再存储!

崩溃后产生 B 但不可见 A 的操作顺序如下:

  • A 和 B 以某种顺序执行
  • 一旦 A 和 B 拥有各自线路的 MESI 独家所有权,A 和 B 就会提交到 L1d 缓存,从而对其他核心全局可见。
  • clwb 指令在某个时刻执行,请求在存储提交后的某个时刻将缓存行写回 DRAM。
  • A 行的回写在它提交到 L1d 后的某个时间点开始,B 行也是如此。它们可以以任一顺序开始,因为 clwb 的顺序不能保证写入。其他行的其他 clwb 操作,尽管实际上它们可能开始在程序中。
  • clwb-B 完成持久化
  • 机器在飞行中的 clwb-A 进入持久域之前断电。您没有要求订购 clwb 操作。彼此,所以这是允许的。

就asm指令重排序而言,允许如下重排序:

 store A
 store B
 clwb  B
 clwb  A     ; not ordered wrt. store B or clwb B

当然,至少在理论上,执行顺序与到达存储缓冲区的末尾与实际的持久提交都是不同的事情,但是如果您想将其简化为一条指令的所有步骤发生在另一个指令的任何影响之前指令,这种重新排序仍然与所有规则兼容。

我认为您缺少的关键是 clwb A 是独立于商店 A 的操作,它不会一直坚持下去。允许 clwb 在其他后来的商店之后“发生”。商店 B 位于不同的地址,因此它不会订购 clwb A。

SFENCE 可以防止这种情况发生。