在释放内存之前,我要从 CPU 缓存中逐出内存范围。理想情况下,我只想放弃这些缓存行而不将它们保存到内存中。因为没有人会使用这些值,无论谁再次获得该内存范围(在 malloc()
/new
/_mm_malloc()
等之后)。 ) 将首先用新值填充内存。作为this question suggests ,目前似乎没有办法在x86_64上实现理想。
因此我正在执行 _mm_clflushopt()
。据我了解,在 _mm_clflushopt()
之后,我需要调用 _mm_sfence()
以使其非临时存储对其他内核/处理器可见。但在这种特定情况下,我不需要它的商店。
所以如果我不调用 _mm_sfence()
,会不会有什么不好的事情发生?例如。如果其他一些核心/处理器设法足够快地再次分配该内存范围,并开始用新数据填充它,是否会发生新数据被当前核心刷新的旧缓存同时覆盖的情况?
编辑:快速后续分配不太可能,我只是描述这种情况,因为我也需要程序在那里是正确的。
最佳答案
clflushopt
对于这个用例来说是个糟糕的主意。在覆盖它们之前从缓存中逐出行与您想要的相反。如果它们在高速缓存中很热,您可以避免 RFO(读取所有权)。
如果您使用的是 NT 商店,它们会驱逐所有仍然很热的线路,因此不值得花费周期先执行 clflushopt
。
如果不是,您通过保证最坏的情况完全搬起石头砸自己的脚。参见Enhanced REP MOVSB for memcpy有关写入内存以及 RFO 与无 RFO 存储的更多信息。 (例如,rep movsb
至少可以在 Intel 上执行无 RFO 存储,但仍将数据保留在高速缓存中。)请记住,L3 命中可以比进入 DRAM 更快地满足 RFO。
如果您要编写一个带有常规存储的缓冲区(这将是 RFO),您可以在准备好实际写入之前对其进行 prefetchw
以使其在 L1D 中进入独占状态.
clwb
(Cache-Line Write Back (without evicting))可能在这里很有用,但我认为 prefetchw
至少总是和它一样好,如果不是更好的话(特别是在 AMD 上,MOESI cache coherency 可以在缓存之间传输脏行,因此您可以将仍然脏的行放入 L1D,并且能够替换该数据而无需将旧数据发送到 DRAM。)
理想情况下,malloc
将为您提供当前内核的 L1D 缓存中仍然热的内存。如果你发现很多时候,你得到的缓冲区仍然是脏的,并且在另一个核心上的 L1D 或 L2 中,然后查看带有每个线程池或某种类似 NUMA 的 malloc线程感知。
As I understood, after
_mm_clflushopt()
I need to call_mm_sfence()
to make its non-temporal stores visible to other cores/processors.
不,不要将clflushopt
视为一家商店。它不会使任何新数据全局可见,因此它不会与内存操作的全局顺序交互。
sfence
让您的线程的后续存储等待,直到刷新的数据一直刷新到 DRAM 或内存映射的非 volatile 存储。
如果您要刷新由常规 DRAM 支持的行,您只需要在存储前使用 sfence
即可启动非相干 DMA 操作,该操作将读取 DRAM 内容而不检查缓存。由于其他 CPU 内核确实总是通过缓存,因此 sfence
对您没有用处或不必要。 (即使 clflushopt
一开始是个好主意。)
即使您谈论的是实际的 NT 商店,其他核心最终也会在没有 sfence
的情况下看到您的商店。如果您需要确保他们在看到您的 NT 商店之前他们看到一些后来的商店,您只需要sfence
。我在 Make previous memory stores visible to subsequent memory loads 中对此进行了解释
can something bad happen?
不,clflushopt
不会影响缓存一致性。它只是触发回写(和驱逐),而不会让以后的存储/加载等待它。
您可以clflushopt
分配内存并由另一个线程使用,而不会影响正确性。
关于c++ - 如果我在 _mm_clflushopt() 之后不发出 _mm_sfence() 会发生什么(不好的)事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46004527/