gpt4 book ai didi

performance - 哪个英特尔微体系结构引入了ADC reg,0单uop特殊情况?

转载 作者:行者123 更新时间:2023-12-04 14:38:27 25 4
gpt4 key购买 nike

Haswell和更早版本上的ADC通常为2 uops,具有2个周期的延迟,因为Intel uops传统上只能有2个输入(https://agner.org/optimize/)。在某些情况下,Haswell为FMA和micro-fusion of indexed addressing modes引入了3输入uops之后,Broadwell/Skylake和后来的版本具有单uup ADC/SBB/CMOV。

(但是BDW/SKL仍然对adc al, imm8短格式编码使用2 uops,或者对其他al/ax/eax/rax,imm8/16/32/32短格式使用无ModRM。我的答案中有更多细节。)

但是在Haswell上,立即数为0的 adc是特殊情况,只能解码为单个uop。 @BeeOnRope tested this,并在其uarch-bench中包括对此performance quirk的检查:https://github.com/travisdowns/uarch-bench。 Haswell服务器上CI的示例输出显示了adc reg,0adc reg,1adc reg,zeroed-reg之间的差异。

(但仅适用于32或64位操作数大小,而不适用于adc bl,0。因此,请使用32位when using adc on a setcc result将2个条件组合到一个分支中。)

与SBB相同。据我所知,对于具有相同立即值的等效编码,在任何CPU上ADC和SBB的性能之间都没有任何区别。

何时引入了针对imm=0的优化?

我在Core 21上进行了测试,发现adc eax,0延迟为2个周期,与adc eax,3相同。而且,对于03的吞吐量测试的一些变体,周期数是相同的,因此第一代Core 2(Conroe/Merom)不进行此优化。

回答此问题的最简单方法可能是在Sandybridge系统上使用下面的测试程序,并查看adc eax,0是否比adc eax,1更快。但是基于可靠文档的答案也可以。

脚注1 :我在运行Linux的Core 2 E6600(Conroe/Merom)上使用了此测试程序。

;; NASM / YASM
;; assemble / link this into a 32 or 64-bit static executable.

global _start
_start:
mov ebp, 100000000

align 32
.loop:

xor ebx,ebx ; avoid partial-flag stall but don't break the eax dependency
%rep 5
adc eax, 0 ; should decode in a 2+1+1+1 pattern
add eax, 0
add eax, 0
add eax, 0
%endrep

dec ebp ; I could have just used SUB here to avoid a partial-flag stall
jg .loop


%ifidn __OUTPUT_FORMAT__, elf32
;; 32-bit sys_exit would work in 64-bit executables on most systems, but not all. Some, notably Window's subsystem for Linux, disable IA32 compat
mov eax,1
xor ebx,ebx
int 0x80 ; sys_exit(0) 32-bit ABI
%else
xor edi,edi
mov eax,231 ; __NR_exit_group from /usr/include/asm/unistd_64.h
syscall ; sys_exit_group(0)
%endif

Linux perf在像Core 2这样的旧CPU上不能很好地工作(它不知道如何访问诸如uops之类的所有事件),但是它确实知道如何读取HW计数器的周期和指令。足够了。

我使用构建并对此进行了分析
 yasm -felf64 -gdwarf2 testloop.asm
ld -o testloop-adc+3xadd-eax,imm=0 testloop.o

# optional: taskset pins it to core 1 to avoid CPU migrations
taskset -c 1 perf stat -e task-clock,context-switches,cycles,instructions ./testloop-adc+3xadd-eax,imm=0

Performance counter stats for './testloop-adc+3xadd-eax,imm=0':

1061.697759 task-clock (msec) # 0.992 CPUs utilized
100 context-switches # 0.094 K/sec
2,545,252,377 cycles # 2.397 GHz
2,301,845,298 instructions # 0.90 insns per cycle

1.069743469 seconds time elapsed

0.9 IPC是有趣的数字。

这是关于我们希望通过2 uop/2c延迟 adc进行静态分析的期望:循环中的 (5*(1+3) + 3) = 23指令,延迟的 5*(2+3) = 25周期=每个循环迭代的周期。 23/25 = 0.92。

在Skylake上为1.15。 (5*(1+3) + 3) / (5*(1+3)) = 1.15,即额外的.15来自xor-zero和dec/jg,而adc/add链正好以每个时钟1 uop的速度运行,这使延迟成为瓶颈。我们也希望其他任何具有单周期等待时间 adc的uarch上的总体IPC为1.15,因为前端不是瓶颈。 (按顺序排列的Atom和P5 Pentium会稍低一些,但是xor和dec可以与adc配对或在P5上添加。)

在SKL上, uops_issued.any = instructions = 2.303G,确认 adc是单个uop(无论立即数具有什么值,它始终在SKL上)。偶然地, jg是新缓存行中的第一条指令,因此它不会与SKL上的 dec宏融合。使用 dec rbpsub ebp,1代替, uops_issued.any是预期的2.2G。

这是非常可重复的: perf stat -r5(运行5次并显示平均值+方差),并且多次运行,表明循环计数可重复至1000的1倍。 adc中的1c与2c延迟会产生更大的差异比起那个来说。

0以外的立即数重建可执行文件根本不会改变Core 2上的时间,这是一个没有特殊情况的有力信号。绝对值得测试。

我最初是在查看吞吐量(在每次循环迭代之前使用 xor eax,eax,让OoO exec重叠迭代),但是很难排除前端效果。我认为我终于通过添加单联 add指令避免了前端瓶颈。内部循环的吞吐量测试版本如下所示:
    xor  eax,eax  ; break the eax and CF dependency
%rep 5
adc eax, 0 ; should decode in a 2+1+1+1 pattern
add ebx, 0
add ecx, 0
add edx, 0
%endrep

这就是延迟测试版本看起来有点奇怪的原因。但是无论如何,请记住,Core2没有解码uop缓存,并且其循环缓冲区处于预解码阶段(在找到指令边界之后)。 4个解码器中只有1个可以解码多uop指令,因此 adc是前端的多uop瓶颈。我想我可以使用 times 5 adc eax, 0来实现这一点,因为管道的某些后期阶段不太可能能够在不执行该uop的情况下抛出该uop。

Nehalem的循环缓冲区可回收解码的微指令,并避免了背对背多微指令的解码瓶颈。

最佳答案

根据我的微基准测试,其结果可以在uops.info上找到,此优化是由Sandy Bridge(http://uops.info/html-tp/SNB/ADC_R64_I8-Measurements.html)引入的。 Westmere不执行此优化(http://uops.info/html-tp/WSM/ADC_R64_I8-Measurements.html)。数据是使用Core i7-2600和Core i5-650获得的。

此外,uops.info上的数据显示,如果使用8位寄存器(Sandy BridgeIvy BridgeHaswell),则不会执行优化。

关于performance - 哪个英特尔微体系结构引入了ADC reg,0单uop特殊情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51664369/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com