最近在回答另一个问题时,我进行了一些关于不同prefetch
类型的测试,并得出以下结论:
使用prefetchnta
的结果与Skylake客户端上的以下实现一致:
prefetchnta
将值加载到L1
和L3
,但不是L2
(实际上,如果该行已经在L2
中,则似乎该行可能被逐出)。
- 它似乎以“正常”的方式将值加载到L1中,但在L3中以更弱的方式加载,使其更快地被逐出(例如,只在集合中的单个路线中加载,或者将其LRU标志设置为下一个受害者)。
- 像所有其他预取指令一样,
prefetchnta
使用LFB条目,因此它们并不能真正帮助你获得额外的并行性:但NTA提示可以在避免L2和L3污染方面很有用。
当前的优化手册(248966-038)在几个地方声称,
prefetchnta
确实将数据引入L2,但仅在组中的一个路上。例如,在
7.6.2.1视频编码器中:
针对视频编码器实施的预取缓存管理可降低内存访问量。防止单次使用的视频帧数据进入第二级缓存可确保减少第二级缓存的污染。使用非临时PREFETCH(PREFETCHNTA)指令只将数据引入第二级缓存的一个路,从而降低了第二级缓存的污染。
这与我在Skylake上的测试结果不一致。在64 KiB区域内进行跨步操作,并使用
prefetchnta
,性能表现几乎完全与从L3获取数据相同(每次加载约4个周期,MLP系数为10,L3延迟约40个周期):
Cycles ns
64-KiB parallel loads 1.00 0.39
64-KiB parallel prefetcht0 2.00 0.77
64-KiB parallel prefetcht1 1.21 0.47
64-KiB parallel prefetcht2 1.30 0.50
64-KiB parallel prefetchnta 3.96 1.53
由于Skylake的L2是4路的,如果数据被加载到其中一路,则应该刚好停留在L2缓存中(其中一路覆盖64 KiB),但上面的结果表明它没有。
您可以使用我的uarch-bench程序在Linux上在自己的硬件上运行这些测试。旧系统的结果尤其有趣。
Skylake服务器(SKLX)
Skylake服务器上prefetchnta
的报告行为与Skylake客户端有different L3缓存架构,存在显着差异。特别是,用户Mysticial reports that使用prefetchnta
获取的行在任何缓存级别中都不可用,一旦它们从L1中驱逐出去,就必须从DRAM中重新读取。
最有可能的解释是,由于
prefetchnta
的存在,它们根本没有进入L3 - 这很可能是因为在Skylake服务器中,L3是专用L2缓存的非包容性共享受害者缓存,因此使用
prefetchnta
绕过L2缓存的行很可能永远没有机会进入L3。这使得
prefetchnta
功能更加纯粹:较少的缓存级别被
prefetchnta
请求污染,但也更加脆弱:在L1中未能读取
nta
行并在其被驱逐之前意味着另一个完整的往返内存:由
prefetchnta
触发的初始请求完全被浪费。
prefetchnta
,但我忘记了关于这种情况的阅读内容。 - Peter Cordesprefetchnta
仅将数据拉入L1缓存,而不是所有缓存。话虽如此,我不知道它如何与硬件预取器交互。在内存访问足够“随机”以使硬件预取器失败但“连续”以使用完整缓存行的情况下(这是许多缓存阻塞优化的情况),我发现在没有超线程的情况下,软件预取可以产生巨大的差异。(约10%)但我没有看到prefetcht0
和prefetchnta
之间有任何可观察的区别。 - Mysticialprefetchnta
是在多核CPU之前的PIII时代引入的。我不会感到惊讶,如果它与当前设计上的prefetch0
完全相同,就像lddqu
现在与movdqu
相同一样。也许prefetchnta
使缓存行更有可能被快速地逐出。 - Peter Cordes