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

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

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

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

最佳答案

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

如果您使用的是NT商店,它们将驱逐所有仍很热的行,因此不值得花时间先做clflushopt

如果没有,那么您将通过保证最坏的情况来彻底射击自己。有关写入内存以及RFO与无RFO存储的更多信息,请参见Enhanced REP MOVSB for memcpy。 (例如,rep movsb至少可以在Intel上不进行RFO存储,但仍将数据保留在高速缓存中。)请记住,L3命中可以满足RFO的需求,而比去DRAM更快。

如果您要编写一个带有常规存储(将为RFO)的缓冲区,则可以在其上prefetchw使其在L1D中进入独占状态,然后再准备进行实际写入。

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的商店。仅在需要确保他们在以后看到某些存储之前先看到它们的NT存储时,才需要sfence。我在Make previous memory stores visible to subsequent memory loads中对此进行了解释


  会发生不好的事情吗?


不,clflushopt不会影响缓存一致性。它仅触发回写(&逐出),而无需稍后进行存储/加载来等待它。

您可以clflushopt由另一个线程分配和使用的内存,而不会影响正确性。

07-24 22:15