如何强制cpu内核刷新c中的存储缓冲区?

bar*_*hen 2 c multithreading cpu-architecture

我有一个具有2个线程的应用程序,与内核1关联的线程A和与内核2关联的线程B,内核1和内核2在同一x86套接字中。

线程A忙于整数x的旋转,线程B在某些情况下会增加x,当线程B决定增加x时,它将使x所在的缓存行无效,并根据x86 MESI协议,它将新的x存储到存储缓冲区在core2收到无效ack之前,然后在core2收到无效ack之后,core2刷新存储缓冲区。

我想知道,在core2收到无效ack之后,core2刷新是否立即存储缓冲区?我是否有可能迫使cpu用C语言执行刷新存储缓冲区?因为在我的情况下,core1旋转x的线程A应该尽早获得x新值。

Pet*_*des 5

内核总是尝试尽快将其存储缓冲区提交到L1d高速缓存(从而变得全局可见),以便为更多存储空间。

您可以使用屏障(如atomic_thread_fence(memory_order_seq_cst)使线程等待线程的存储在全局范围内可见,然后再执行其他加载或存储操作,但这可以通过阻塞此核心而不是通过加快刷新存储缓冲区的速度来实现。

显然,为了避免C11中的未定义行为,变量必须为_Atomic。如果只有一个tmp = atomic_load_explicit(&x, memory_order_relaxed)编写器,则可以使用和store_explicit tmp+1来避免使用更昂贵的seq_cst存储或原子RMW。acq / rel排序也可以,只要避免使用默认的seq_cst即可,atomic_fetch_add如果只有一个writer ,则避免使用RMW。

如果只有一个线程修改过RMW操作,而其他线程则以只读方式访问它,则不需要整个RMW操作都是原子操作。


在另一个内核可以读取您写入的数据之前,它必须先从将其写出的内核的L1d中的“已修改”状态转移到L3缓存,再从那里到达读取器内核的L1d。

您可能能够加快部分的速度,是在数据离开存储缓冲区之后发生的。但是您没有什么可以做的有用的事情。您不希望这样做clflush,这会完全回写+逐出高速缓存行,因此,如果另一个核心在某个过程中未尝试读取它,则另一个核心将不得不从DRAM中获取它(如果可能的话) )。

Ice Lake将clwb保留数据缓存并强制回写到DRAM。但这又迫使数据实际进入DRAM。(Skylake-Xeon也有。)

Tremont(Goldmont Plus的前身,atom / silvermont系列)具有_mm_cldemotecldemote)。就像SW预取相反。这是一个可选的性能提示,用于将高速缓存行写到L3,但不强制将其移至DRAM或其他任何设备。

除此之外,也许还有一些技巧,例如写入L8和L1d高速缓存中相同集合的其他8个位置,从而强制驱逐冲突。这将在写线程中花费额外的时间,但可能使数据更快地供其他想要读取的线程使用。