我在释放内存之前从CPU缓存中驱逐内存范围。理想情况下,我想放弃这些缓存行而不将它们保存到内存中。因为没有人会使用这些值,并且再次获得该内存范围的人(在malloc()
/ new
/ _mm_malloc()
之后等)将首先使用新值填充内存。作为this question suggests,目前似乎无法在x86_64上实现理想。
因此,我正在做_mm_clflushopt()
。据我所知,在_mm_clflushopt()
之后,我需要调用_mm_sfence()
以使其非临时存储对其他核心/处理器可见。但在这种特殊情况下,我不需要它的商店。
所以,如果我不打电话给_mm_sfence()
,可能会发生什么不好的事情?例如。如果某个其他核心/处理器设法再次足够快地分配该内存范围,并开始用新数据填充它,是否会发生新数据被当前核心刷新的旧缓存同时覆盖?
编辑:快速的后续分配不太可能,我只是在描述这种情况,因为我也需要程序正确。
答案 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
内存。