如果我不在_mm_clflushopt()之后发出_mm_sfence(),会发生什么(不好)?

时间:2017-09-01 16:32:49

标签: c++ concurrency x86-64 cpu-cache memory-fences

我在释放内存之前从CPU缓存中驱逐内存范围。理想情况下,我想放弃这些缓存行而不将它们保存到内存中。因为没有人会使用这些值,并且再次获得该内存范围的人(在malloc() / new / _mm_malloc()之后等)将首先使用新值填充内存。作为this question suggests,目前似乎无法在x86_64上实现理想。

因此,我正在做_mm_clflushopt()。据我所知,在_mm_clflushopt()之后,我需要调用_mm_sfence()以使其非临时存储对其他核心/处理器可见。但在这种特殊情况下,我不需要它的商店。

所以,如果我不打电话给_mm_sfence(),可能会发生什么不好的事情?例如。如果某个其他核心/处理器设法再次足够快地分配该内存范围,并开始用新数据填充它,是否会发生新数据被当前核心刷新的旧缓存同时覆盖?

编辑:快速的后续分配不太可能,我只是在描述这种情况,因为我也需要程序正确。

1 个答案:

答案 0 :(得分:1)

clflushopt对于这个用例来说是个糟糕的主意。在覆盖它们之前从缓存中清除行与您想要的相反。如果它们在缓存中很热,则可以避免RFO(读取所有权)。

如果你正在使用NT商店,它们会驱逐任何仍然很热的行,所以不值得花费首轮clflushopt

如果没有,你可以通过保证最坏的情况完全射击自己。有关写入内存,RFO与非RFO商店的更多信息,请参阅Enhanced REP MOVSB for memcpy。 (例如rep movsb至少可以在英特尔上进行无RFO存储,但仍然会将数据保留在高速缓存中。)请记住,L3命中可以比进入DRAM更快地满足RFO。

如果您要编写一个带有常规存储(即RFO)的缓冲区,您可以在它上面prefetchw使其在您的L1D中进入Exclusive状态,然后再准备好实际写入。

clwb(缓存行回写(没有驱逐))可能在这里有用,但我认为prefetchw总是至少和那个一样好,如果不是更好(特别是在AMD上,MOESI cache coherency可以在缓存之间传输脏线,这样你就可以在你的L1D中找到一条仍然很脏的线路,并且能够替换那些数据,而无需将旧数据发送到DRAM。)

理想情况下,malloc会为您提供在当前核心的L1D缓存中仍然很热的内存。如果你发现很多时候,你得到的是仍然很脏的缓冲区,而另一个核心上则是L1D或L2,那么会查看带有每个线程池或类似NUMA的malloc线索意识。

  

据我了解,在_mm_clflushopt()之后,我需要调用_mm_sfence()以使其非临时存储对其他核心/处理器可见。

不,不要将clflushopt视为商店。它不会使任何新数据全局可见,因此它不会与内存操作的全局排序交互。

sfence使您的线程的后续存储等待,直到刷新的数据一直刷新到DRAM或内存映射的非易失性存储。

如果您正在刷新由常规DRAM支持的行,则只需要sfence才能启动非连贯的DMA操作,该操作将读取DRAM内容而不检查缓存。由于其他CPU核心执行总是通过缓存,sfence对您来说没有用处或必要。 (即使clflushopt首先是一个好主意。)

即使你在谈论实际的NT商店,其他核心最终也会看到没有sfence的商店。您只需要sfence,如果您需要确保他们在之前看到您的NT商店,他们会看到一些以后的商店。我在Make previous memory stores visible to subsequent memory loads

中解释了这一点
  

会发生什么不好的事吗?

不,clflushopt不会影响缓存一致性。它只是触发回写(&驱逐),而不会让以后的存储/加载等待它。

您可以在不影响正确性的情况下分配和使用另一个线程clflushopt内存。