assembly 为什么x86位字符串操作指令在内存目标上运行缓慢?(BTS、BTR、BTC)

jfewjypa  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(102)

例如,x86位操作指令(btr、bts、btc、no lock)应用于内存操作数比其他读-修改-写指令(如add、xor等)在大多数支持它们的处理器上要慢。为什么会这样呢?这些指令看起来很容易实现。
这是因为实际加载的地址与内存操作数指定的地址不同,而这混淆了一些跟踪内存访问的前端机制吗?这似乎是合理的,但我不认为它会影响吞吐量(至少不会影响这么多);只有等待时间。

8dtrkrch

8dtrkrch1#

是因为实际加载的地址与内存操作数指定的地址不同吗
是的,很明显,这就是它与记忆-目的地转移的区别。
reg-reg版本在Intel上是具有1个周期延迟的1个uop,例如在Intel Haswell和更高版本上运行在执行端口0或6上,与移位相同。(将索引解码为1-hot掩码比一般移位器便宜,但由于存在移位单元,推测Intel只使用这些移位单元。)
AMD由于某种原因运行bts reg,reg为2 uops,比简单的移位慢。IDK为什么,也许是关于标志设置的东西。
bts mem, imm8也很正常,Intel上有3个前端uop。xor mem, imm8只有2个前端uop,但这是因为它可以微融合加载+xor。not mem有3个前端uop,仅微融合存储地址和存储uop指令。
这会混淆跟踪内存访问的前端机制吗
不,前端不跟踪内存访问,那是后端。
它之所以慢,部分原因是因为它是作为多个微指令实现的;即使你执行一个被不同指令包围的任务也会很痛苦。在IntelHaswell和桤木(可能都在两者之间)上,bts mem, r32需要10个前端微操作,而bts mem, imm8需要3个
因为它不能直接使用通常的地址生成硬件,所以它在微码中实现为多个uop,大概类似于从正常寻址模式到临时地址的莱亚,并向其添加(bit_index>>6) * 4,以便通过dword或类似的方式进行索引。哦,它是10个uop的原因可能是它总是希望访问包含该位的 aligned dword,而不仅仅是从X1 M7 N1 X寻址模式中的地址偏移4的倍数,用于类似X1 M8 N1 X的东西。
在正常情况下,手动执行此操作效率更高,因为您知道位字符串的开头是对齐的,因此可以shr位索引以获取用于load /bts reg,reg的双字索引(1uop)/ store。这比bts [mem], reg占用更少的uop。注意,bts reg,reg截断/ Package 位索引,所以如果你正确地安排事情,模是免费的。例如埃拉托塞尼的筛子。也可以是 * How can memory destination BTS be significantly slower than load / BTS reg,reg / store? *
但是Agner Fog和https://uops.info/都在Haswell /桤木Lake P核上测量了5个周期的吞吐量,大大低于前端瓶颈(或任何每端口后端瓶颈)。

实际的加载和存储微操作应该是正常的,输入来自内部临时寄存器,但就存储缓冲区和加载缓冲区中的地址而言,仍然是正常的加载微操作和存储微操作(英特尔称之为内存顺序缓冲区= MOB)。

我并不认为这是内存依赖预测的特例,因为这是在加载微操作执行时发生的(还有一些存储地址微操作尚未执行,因此一些先前存储的地址仍然未知)。
TODO:运行一些实验,看看是否有任何其他指令与bts mem,reg混合在一起会降低它的速度,争夺它瓶颈所在的任何资源。
这看起来不像是https://uops.info/方面的基准测试错误(例如,每次使用相同的地址,并停止存储转发延迟)。他们的测试包括一些使用不同偏移量的展开序列。例如,Haswell throughput testing for bts m64, r64每次使用相同的地址测量6.02或6.0周期吞吐量(bts qword ptr [r14], r8),或者当展开像bts [r14],r8的重复序列时每个BTS平均5.0个周期;bts [r14+0x8],r8 ;即使对于覆盖两个相邻高速缓冲存储器线的16个独立指令的序列,其每迭代仍为相同的5个循环。

相关问题