存储转发地址与数据:英特尔优化指南中STD和STA有什么区别?

驯龙5788

我想知道是否有任何英特尔专家可以告诉我STD和STA在英特尔Skylake内核方面的区别。

在英特尔优化指南中,有一张图片描述了英特尔酷睿的“超标量端口”。

这是PDF图片在第40页上。

这是相关图形的图片

这是第78页的另一张图片,该图片描述了“存储地址”和“存储数据”:

  1. 使用存储的数据地址准备存储转发和存储退出逻辑。

  2. 准备存储转发和存储退出逻辑以及要存储的数据。

考虑到Skylake可以在每个时钟周期执行一次#1 3x,但在每个时钟周期只能执行一次#2,我很好奇这两者之间的区别。

在我看来,将存储转发到数据地址是“自然的”。但是我无法理解何时进行数据存储转发(又名:STD /端口4)。是否有任何组装/优化专家可以帮助我准确了解STD和STA之间的区别?

彼得·科德斯

自从第一个P6系列微体系结构Pentium Pro以来,英特尔CPU就一直将存储分为存储地址和存储数据。

但是存储地址和存储数据的微指令可以微融合到一个融合域的微指令中。在Sandy / IvyBridge上,索引寻址模式是未分层的,如英特尔的优化手册中所述。但是Haswell和更高版本甚至可以在ROB中使它们保持微融合,因此它们并不是未分层的。请参阅微融合和寻址模式(英特尔没有提到这一点,昂纳雾还没有来得及测试为广泛的Haswell / SKYLAKE微架构,以便他平时好microarch PDF甚至没有在所有提及未贴合,但你还是应该肯定阅读学习有关uops如何工作以及如何对指令进行解码以及如何通过管道的更多信息。另请参见 标签wiki中的其他x86性能链接


考虑到Skylake可以在每个时钟周期执行#1 3x,但是在每个时钟周期只能执行#2 3次

端口2和3也可以在其AGU上运行负载操作,而在该周期中不使用端口的负载数据部分。Port7仅具有专用于存储AGU的简单寻址模式。

带索引寄存器的存储寻址模式不能使用端口7,只能使用p2 / p3。但是,如果对存储使用“简单”寻址模式,则峰值吞吐量为每个时钟2个负载+ 1个存储。


在Nehalem及更早版本(P6系列)上,p2是唯一的加载端口,p3是存储地址端口,而p4是存储数据。

在IvyBridge / Sandybridge上,没有用于存储地址的单独端口,它们始终仅在加载端口(p23)中的AGU(地址生成单元)上运行。对于256b的加载/存储,仅每隔一个周期就需要AGU(256b的加载或存储uup占用加载或存储数据端口2个周期,但是加载端口在第二个周期内可以接受存储地址uop)。所以2负载/ 1每个时钟店是在SandyBridge的理论可持续的,但只有当大部分是与AVX 256位向量加载/存储运行的两个128位半。

Haswell在端口7上添加了专用的store-AGU,并将加载/存储执行单元扩展到256b,因为如果负载稳定,那么当加载端口不需要其AGU时就没有空闲周期。


存储地址uop将地址(我猜是宽度)写到存储缓冲区(即Intel术语中的内存顺序缓冲区)中。分别发生这种情况,并且可能在要存储的数据准备就绪之前,可以使以后的加载(按程序顺序)检测它们是否与存储区重叠。

当存在地址未知的挂起存储时,乱序执行加载是有问题的:错误的猜测意味着必须回滚管道。(我认为machine_clears.memory_orderingperf计数器事件包括这一点。可以从单线程代码中获得非零计数,但是我忘记了我是否有确凿的证据表明Skylake有时会推测性地猜测负载不会与未知地址存储区重叠)。

正如David Kanter在他的Haswell微架构文章中指出的那样,加载uop还需要探测存储缓冲区以检查转发/冲突,因此仅运行存储地址uops的执行单元的构建成本较低。

无论如何,我不确定如果英特尔重新设计了东西,以便port7拥有一个完整的AGU,它也可以处理索引寻址模式,并且使存储地址uops仅在p7上运行,而不能在p2 / p3上运行,将会对性能产生什么影响

这将阻止“窃取” p23的存储地址,这确实发生了,并且将最大持续L1D带宽从96字节/周期(2加载+ 1个32字节YMM向量存储)降低到Skylake的〜81字节/周期根据英特尔优化手册中的表格。但是在适当的情况下,Skylake可以在每个时钟4字节操作数承受2个负载+1个存储,因此也许81字节/周期数受其他一些微体系结构限制。峰值为96B /时钟,但显然不可能无限期地背靠背发生。

阻止在p23上运行存储地址oups的一个缺点是,需要更长的时间才能知道存储地址,可能会延迟更多的加载。

我无法理解何时进行数据存储转发(又名:STD /端口4)。

存储/重新加载可以使加载从存储缓冲区中获取数据,而不是等待它提交到L1D并从那里读取数据。

当函数在调用函数之前溢出一些寄存器时,可能会发生存储/重载,这是在堆栈上传递args的一部分(尤其是在cr脚的stack-args调用约定中传递了堆栈上的所有args)。或通过引用非内联函数传递某些内容。或在直方图中,如果重复命中相同的bin,则基本上是在循环中进行内存目标增量。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章