0

在释放内存之前,我正在从 CPU 缓存中清除内存范围。理想情况下,我只想放弃这些缓存行而不将它们保存到内存中。因为没有人会使用这些值,而谁再次获得该内存范围(在malloc()/ new/_mm_malloc()等之后)将首先用新值填充内存。正如这个问题所暗示的,目前似乎没有办法在 x86_64 上实现理想。

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

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

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

4

1 回答 1

1

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

如果您使用的是 NT 商店,他们将驱逐任何仍然很热的线路,因此不值得clflushopt先花费周期。

如果不是这样,你保证最坏的情况完全是在自取其辱。有关写入内存以及 RFO 与无 RFO 存储的更多信息, 请参阅增强型 REP MOVSB for memcpy 。(例如rep movsb,至少可以在 Intel 上进行无 RFO 存储,但仍将数据热留在缓存中。)请记住,L3 命中可以比进入 DRAM 更快地满足 RFO。

如果您要使用常规存储(将 RFO)写入缓冲区,您可能会prefetchw在准备好实际写入之前将其置于 L1D 中的独占状态。

(Cache-Line Write Back (without evicting))可能clwb在这里有用,但我认为prefetchw如果不是更好的话,至少会一样好(尤其是在 AMD 上,MOESI 缓存一致性可以在缓存之间传输脏线,所以你可以在你的 L1D 中插入一条仍然脏的线,并且能够在不将旧数据发送到 DRAM 的情况下替换该数据。)

理想情况下,malloc将为您提供在当前内核的 L1D 缓存中仍然很热的内存。如果你发现很多时候,你得到的缓冲区仍然很脏,并且在另一个内核上的 L1D 或 L2 中,然后查看具有每个线程池的 malloc 或某种类似 NUMA 的线程意识。

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

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

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

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


即使您谈论的是实际的 NT 商店,其他核心最终也会看到您的商店没有sfence. 您只需要sfence确保他们在看到一些后来的商店之前看到您的 NT 商店。我在使先前的内存存储对后续的内存加载可见中对此进行了解释

会发生不好的事情吗?

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

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

于 2017-09-01T17:30:12.097 回答