`_mm_clevict` 内在和对应的 clevict0、clevict1 指令的目的是什么?

What is the purpose of `_mm_clevict` intrinsic and corresponding clevict0, clevict1 instructions?

Intel® Intrinsics Guide 说 _mm_clevict:

void _mm_clevict (const void * ptr, int level)
#include <immintrin.h>
Instruction: clevict0 m8
             clevict1 m8
CPUID Flags: KNCNI

Evicts the cache line containing the address ptr from cache level level (can be either 0 or 1).

这个操作的目的是什么?它与_mm_cldemote有什么不同吗?

请注意,这是 KNCNI,Knight's Corner New Instructions,所以那是 first-gen Xeon Phi compute cards,在 Knight's Landing 之前。它是从 GPU 演变而来的,因此拥有缓存控制指令可能并不奇怪。

可能也与主机系统接口相关,因为计算卡的缓存与主机系统 CPU 一致。尽管它们可能与 PCIe 对设备内存的访问保持一致,就像 x86 通常具有高速缓存一致的 DMA 一样。 (此外,如果外部缓存不包含在内,仅从一个缓存级别逐出可能仍会在另一个缓存级别中留下脏数据。如果在主机读取设备内存之前需要任何手动一致性,则更有可能 clflush 或其他内容将被使用。)

我不知道为什么 KNC 拥有它,但没有理由期望它会出现在主流 x86 CPU 中。甚至 KNL 也没有 KNCNI; KNL 改为 AVX-512F + ER + PFKNCNI 是完全死胡同的指令集扩展,在任何后来的 CPU 中都不存在


当用于脏数据时,它可能与 cldemote 的想法类似,但是对于干净的数据,它会让您在读完数据后丢弃数据. (回想一下,KNC 是完全有序的,基于 P54C(奔腾)双发布有序微体系结构,所以当您完成访问缓存行时,您实际上可以根据程序顺序知道。与 KNL 不同的是基于 Silvermont。)

通过手动逐出您知道不再需要读取的数据来管理缓存是我的最佳猜测。

据我所知,这些指令已添加到第一代 Xeon Phi(Knights Corner,KNC)处理器中,以帮助处理缓存层次结构中数据移动的一些非常具体的性能问题。自从我查看详细信息以来已经有一段时间了,但我的回忆是存在一些与缓存受害者相关的性能问题,如果在缓存未命中之前将不再需要的行从缓存中逐出,则吞吐量会有所提高那会导致驱逐。

想法(1):这可能是由于脏驱逐的内存库冲突。例如,考虑一下如果地址映射使得正在加载的新项目很可能位于与受害者冲突的 DRAM 库中而被丢弃,会发生什么情况。如果内存控制器上没有足够的写入缓冲区,则可能必须先将回写提交给 DRAM,然后 DRAM 才能切换存储体以服务于读取。 (较新的处理器在内存控制器中有很多很多写缓冲区,所以这不是问题,但这对 KNC 来说可能是个问题。)

想法 (2):另一种可能性是,由于重复标记目录 (DTD) 中的序列化,缓存受害者处理可能会延迟新值的读取。一致性协议显然有点“hack”(因此英特尔可以使用现有的 P54C 进行最小的更改),但英特尔提供的高级文档不足以理解某些实现细节的性能影响。

CLEVICT 指令是“本地”指令——只有执行该指令的核心执行驱逐。脏缓存行将被写出并在本地失效,但失效请求不会传输到其他内核。指令集体系结构文档没有评论 CLEVICT 指令是否导致从内核到 DTD 的更新消息。 (这对于想法 (2) 进行任何性能更改都是必要的。)

CLDEMOTE 指令似乎旨在减少生产者-消费者情况下缓存到缓存传输的延迟。从指令描述: “这可能会加速同一相干域中其他内核对该行的后续访问,特别是如果该行是由降级该行的内核编写的。” 这和我的专利非常相似https://patents.google.com/patent/US8099557B2/ "Push 用于共享说明”(我在 AMD 时开​​发的)。