我在NASM文档中遇到了以下说明,但我无法对它们做出正面或反面。遗憾的是,英特尔关于这些说明的文档也有些缺乏。
PREFETCHNTA m8 ; 0F 18 /0 [KATMAI]
PREFETCHT0 m8 ; 0F 18 /1 [KATMAI]
PREFETCHT1 m8 ; 0F 18 /2 [KATMAI]
PREFETCHT2 m8 ; 0F 18 /3 [KATMAI]
任何人都可以提供一个简明的指令示例,比如在给定地址缓存256个字节吗?提前谢谢!
答案 0 :(得分:6)
这些说明是用于暗示CPU尝试将缓存行预取到缓存中的提示。因为它们是提示,所以CPU可以完全忽略它们。
如果CPU确实支持它们,那么CPU将尝试预取但是如果涉及TLB未命中则将放弃(并且不会预取)。这是大多数人弄错的地方(例如,无法执行“预加载”,您插入虚拟读取以强制TLB加载,以便不会阻止预取工作)。
预取的数据量为32个字节或更多,具体取决于CPU等。您可以使用CPUID确定实际大小(CPUID函数0x00000004,EBX位0到31中返回的“系统一致性行大小”)。
如果预读得太晚,它就没有用,如果你过早预取,数据可以在使用之前从缓存中逐出(这也没有帮助)。英特尔的“IA-32英特尔架构优化参考手册”中有一个附录,描述了如何计算预取时间,称为“预取调度距离数学”,您应该阅读它。
另外不要忘记预取可能会降低性能(例如导致需要被驱逐的数据以腾出空间),如果你没有预取任何内容,那么CPU有一个硬件预取器,无论如何都可能为你做这件事。 。您可能还应该阅读此硬件预取器的工作原理(以及何时不工作)。例如,对于顺序读取(例如memcmp()
),硬件预取器会为您执行此操作,并且使用显式预取主要是浪费时间。对于CPU的硬件预取器无法/不会预测的“随机”(非顺序)访问的显式预取,可能只值得打扰。
答案 1 :(得分:1)
在筛选了大量优化的memcmp函数等的一些示例之后,我已经找到了如何有效地使用这些指令(有些)。
这些指令意味着32字节的缓存“行”,这是我最初错过的。因此,要将256字节缓冲区缓存到L1和L2中,可以使用以下指令集:
prefetcht1 [buffer]
prefetcht1 [buffer+32]
prefetcht1 [buffer+64]
prefetcht1 [buffer+96]
prefetcht1 [buffer+128]
prefetcht1 [buffer+160]
prefetcht1 [buffer+192]
prefetcht1 [buffer+224]
t0后缀指示CPU将其预取到整个缓存层次结构中。
t1指示将数据缓存到L1,L2等中。
t2继续这种趋势,预取到L2等等。
“nta”后缀更令人困惑,因为它告诉CPU将数据直接写入内存(理想情况下),而不是读取/写入缓存行。在数据结构非常庞大的情况下,这实际上非常有用,因为可以避免缓存污染,并且可以缓存更多相关数据。