提问者:小点点

缓存行更新一致性,用于原子更新整个缓存行?


我有以下场景,请寻找建议:

需要在两个线程之间共享数据,A和B各自运行在同一处理器的不同内核中,其中线程A写入数据结构S的实例,B线程读取它。我需要S的共享尽可能一致和快速。

struct alignas(64) S 
{ 
  char cacheline [64]; 
};

计划利用缓存行的一致性,作为原子更新对其他内核可见。因此让线程A尽可能快地写入S(*1),以便更新是一致的(从可见性的角度来看是原子的),然后将缓存行降级(CLDEMOTE指令)到共享缓存,以便线程B可以尽可能快地读取它。

注意1:它需要快速发生的原因是,当核心运行线程A开始写入缓存行时,它可以完全更新其所有内容,然后核心使其在L1中可见(更新发生在核心存储缓冲区中),否则,如果更新缓存行的“中间状态”需要太长时间,可能会被推到L1,从而导致不必要的无效信号(MESI)处罚(因为它需要再次执行其余操作),以及线程B中最糟糕的不一致状态。

有没有更好的方法来实现这一点?

谢谢!


共1个答案

匿名用户

是的,存储然后cldemote是一个很好的计划。它在不支持它的CPU上作为nope运行,因此您可以乐观地使用它。(不过,测试它是否真的有助于您在不是nope的CPU上的程序,以防您在阅读该行之前不小心降级。)

你真的需要原子性,还是只是有一些时间很好?如果你需要原子性,你不能使用单独的存储指令。存储缓冲区中的合并不能保证;对于L1d命中,它可能只在冰湖上有时发生。并且中断可以在任何时候发生(除非中断被禁用,但SMI和NMI不能被禁用)。包括你希望一起提交的两个存储之间。

不能保证32字节AVX对齐的加载和存储是原子的,但实际上它们可能在Haswell及更高版本上(其中加载/存储单元为32字节宽)。

同样,64字节的AVX-512加载和存储不能保证是原子的,在Zen4上很可能不会实践,因为它们是在两个32字节的一半中完成的。但是如果你想做一些测试并找到一些在你关心的实际机器上没有任何撕裂的“实际工作”功能,它们可能在配备AVX-512的Intel CPU上。

在具有AVX功能标志的英特尔CPU上,16字节的加载/存储保证是原子的。(多年来一直如此,幸运的是,使用现有的功能位进行了追溯。)AMD还没有记录这一点,但对于具有AVX的AMDCPU来说可能也是如此。

相关:https://rigtorp.se/isatomic//SSE说明:哪些CPU可以进行原子16B内存操作?

movdir64b将提供有保证的64字节写入原子性,但仅限于NT语义学:一路驱逐缓存行以DRAM。它也不提供64字节的原子读取,因此读取端需要检查序列号或其他东西,例如SeqLock。

Intel TSX(事务性内存)可以让您将更改作为单个原子事务提交到整个缓存行(或更多)。但Intel一直通过微码更新禁用它。HLE部分(乐观锁添加处理)完全消失了,但RTM部分(xstart/xend)仍然可以在某些CPU上启用,我认为。

对于这样一个线程只写的用例,您可以考虑SeqLock,使用缓存行的4个字节作为序列号。在固定不同CPU的2个线程之间传递一些变量的最佳方法/如何使用c 11原子库实现seqlock锁

编写者可以加载序列号,存储seq 1(使用普通mov存储,不需要lock inc),将有效负载存储在常规存储中,或者SIMD方便的话,然后存储seq 2

不幸的是,如果不能保证向量加载/存储的原子性,或者在它的各个部分之间排序,你不能让阅读器一次加载整个缓存行,你需要3个单独的加载。(序列号,整行,然后又是序列号。)

但是如果你想使用32字节的原子性,这在Haswell和Zen2及更高版本的实践中似乎是正确的,也许在缓存行的每32字节的一半中放一个序列号,这样读者就可以使用vpcmpeqd/vpmovmskps/test al,1来检查第一个dword元素(序列号)是否在两半之间匹配。或者把它们放在向量中的其他地方,以使重新组装有效负载更便宜。

这会占用两个序列号的空间来节省阅读器中的负载,但在将数据拖入/移出向量时可能会花费更多开销。我想使用vmovdqua[rdi 28]、ymm1/vmovdqu[rdi]、ymm0存储可能会给您留下60个有用的字节,从rdi 4开始,覆盖ymm1开头的4字节序列号。从[rdi 4]存储转发到32字节的负载会停止,但不跨越两个早期存储之间边界的较窄负载甚至也可以。

相关Q

  • CPU缓存抑制
  • x86 MESI使缓存行延迟问题无效
  • 为什么x86没有实现直接的核心到核心消息传递程序集/cpu指令?-蓝宝石急流有UIPI用于用户空间中断处理特殊的处理器间中断。所以如果你想要低延迟通知,这很有趣。如果你只想读取共享数据结构的当前状态,SeqLock或RCU很好。