什么是_mm_prefetch()位置提示?

Ser*_*tch 15 c++ x86-64 prefetch intrinsics cpu-cache

内部函数导说,只有这么多关于void _mm_prefetch (char const* p, int i):

从包含地址p的内存中获取数据行到由locality hint i指定的缓存层次结构中的位置.

你能列出int i参数的可能值并解释它们的含义吗?

我发现_MM_HINT_T0,_MM_HINT_T1,_MM_HINT_T2,_MM_HINT_NTA_MM_HINT_ENTA,但我不知道这是否是一个详尽的列表和它们的含义.

如果特定于处理器,我想知道他们在Ryzen和最新的英特尔酷睿处理器上做了什么.

Mar*_*oom 17

有时,内在函数在它们所代表的指令方面被更好地理解,而不是在它们的描述中给出的抽象语义.


像今天一样,完整的局部常数集是

#define _MM_HINT_T0 1
#define _MM_HINT_T1 2
#define _MM_HINT_T2 3
#define _MM_HINT_NTA 0
#define _MM_HINT_ENTA 4
#define _MM_HINT_ET0 5
#define _MM_HINT_ET1 6
#define _MM_HINT_ET2 7
Run Code Online (Sandbox Code Playgroud)

本文所述,英特尔至强融核协处理器预取功能.

对于IA32/AMD处理器,该集合减少到

#define _MM_HINT_T0 1
#define _MM_HINT_T1 2
#define _MM_HINT_T2 3
#define _MM_HINT_NTA 0
#define _MM_HINT_ET1 6
Run Code Online (Sandbox Code Playgroud)

_mm_prefetch 根据体系结构和位置提示编译成不同的指令

    Hint              IA32/AMD          iMC
_MM_HINT_T0           prefetcht0     vprefetch0
_MM_HINT_T1           prefetcht1     vprefetch1
_MM_HINT_T2           prefetcht2     vprefetch2
_MM_HINT_NTA          prefetchtnta   vprefetchnta
_MM_HINT_ENTA              -         vprefetchenta
_MM_HINT_ET0               -         vprefetchet0
_MM_HINT_ET1          prefetchtwt1   vprefetchet1
_MM_HINT_ET2               -         vprefetchet2
Run Code Online (Sandbox Code Playgroud)

什么(v)prefetch指示做的,如果所有的要求得到满足,是将数据缓存行值得到由当地提示指定的缓存级别.
该指令只是一个提示,可能会被忽略.

当一行被预取到X级时,手册(Intel和AMD)都说它也进入了所有其他更高级别(但是对于X = 3的情况).
我不确定这是否真的是真的,我相信这条线是预先设置的 - 与缓存级别X相关,并且取决于更高级别的缓存策略(包括与非包含)它可能存在也可能不存在那里也是.

(v)prefetch指令的另一个属性是非时间属性.
非时态数据不太可能很快重用.
根据我的理解,NT数据存储在IA32架构1的"流加载缓冲区"中,而对于iMC架构,它存储在普通缓存中(使用硬件线程ID的方式),但具有最近使用替换策略(如果需要,它将成为下一个被驱逐的线路.
对于AMD,手册读取实际位置是依赖于实现的,从软件不可见缓冲区到专用非时态缓存.

(v)prefetch指令的最后一个属性是"intent"属性或"eviction"属性.
由于MESI和变体协议,必须进行所有权请求以使线路进入独占状态(以便对其进行修改).
RFO只是一个特殊的读取,所以用RFO预取它会直接进入Exclusive状态(否则它的第一个商店会因为需要"延迟"的RFO而取消预取的好处),我们知道我们会稍后写信给它.

由于非临时高速缓存级别是实现定义的方式,IA32和AMD体系结构不支持和排除非时态提示.
iMC架构允许使用位置代码_MM_HINT_ENTA.

1我理解为WC缓冲区.Peter Cordes在下面评论中澄清了这一点:如果预取USWC内存区域,prefetchnta仅使用Line-Fill缓冲区.否则它会预取到L1


这里参考是对所涉及的指令的描述

PREFETCHh

从包含源操作数指定的字节的内存中获取数据行到由locality提示指定的缓存层次结构中的位置:

•T0(时态数据) - 将数据预取到缓存层次结构的所有级别.
•T1(关于第一级缓存未命中的时间数据) - 将数据预取到级别2缓存和更高级别.
•T2(关于二级缓存未命中的时间数据) - 将数据预取到级别3缓存和更高级别,或特定于实现的选择.
•NTA(关于所有缓存级别的非时间数据) - 将数据预取到非临时缓存结构中并进入靠近处理器的位置,从而最大限度地减少缓存污染.

PREFETCHWT1

从包含源操作数指定的字节的内存中获取数据行到由写入提示的意图指定的缓存层次结构中的位置(以便通过请求所有权将数据置于"独占"状态)和位置暗示:

•T1(关于第一级缓存的时间数据) - 将数据预取到第二级缓存中.

VPREFETCHh

                Cache  Temporal    Exclusive state
                 Level
VPREFETCH0       L1     NO          NO
VPREFETCHNTA     L1     YES         NO
VPREFETCH1       L2     NO          NO
VPREFETCH2       L2     YES         NO
VPREFETCHE0      L1     NO          YES
VPREFETCHENTA    L1     YES         YES
VPREFETCHE1      L2     NO          YES
VPREFETCHE2      L2     YES         YES
Run Code Online (Sandbox Code Playgroud)

  • 如果预取USWC内存区域,`prefetchnta`仅使用Line-Fill缓冲区.否则它会预取到L1(和具有包含L3的CPU上的L3),绕过L2.(这是英特尔优化手册所说的).你不能从WB内存做弱排序的加载; 在WB上没有办法绕过缓存一致性. (2认同)
  • 哎呀,我之前的评论并不完全准确。NT *stores* 绕过 WB 内存上的缓存一致性。(弱排序类似于绕过一致性。从 WB 内存中弱排序加载是不可能的,但 prefetchNTA 据说可以减少缓存污染。哦,是的,英特尔的手册还说,如果 prefetchNTA 将数据放入 L3,它会进入在任何给定的集合中只有一种方式,所以它仍然可以减少那里的污染。我有一个半完成的答案,其中有更多关于这个的细节,我应该完成并发布......) (2认同)
  • _“否则,由于需要“延迟”的 RFO,它的第一个存储将取消预取的好处_”实际上,它通常没有那么糟糕。除非这条线实际上是共享的,否则它会以 E 状态进入内核,因此第一次写入必须进行 E -> M 转换,但这很便宜并且通常是“本地”的(即,内核只需要翻转一个位在它的一个私有缓存中,无论是 L1 还是 L2,所以它不像内存或共享缓存的未命中。从这个意义上说,初始请求是否被“正确”标记为 RFO 对于实际上是共享。 (2认同)