问题描述
我正在尝试将Peter Cordes在his answer中提到的方法与‘将CPU寄存器中的所有位设置为1’的问题进行比较。
因此,我编写了一个基准测试,将所有13个寄存器设置为除e/rsp
、e/rbp
和e/rcx
之外的所有位1。
代码如下。times 32 nop
用于避免DSB和LSD影响。
mov ecx, 100000000
Align 32
.test3:
times 32 nop
mov rax,-1
mov rbx,-1
;mov ecx,-1
mov rdx,-1
mov rdi,-1
mov rsi,-1
mov r8,-1
mov r9,-1
mov r10,-1
mov r11,-1
mov r12,-1
mov r13,-1
mov r14,-1
mov r15,-1
dec ecx
jge .test3
jmp .out
我测试了他提到的以下方法,Full code in here
mov e/rax, -1
xor eax, eax
dec e/rax
xor ecx, ecx
lea e/rax, [rcx-1]
or e/rax, -1
为了使问题更简洁,我将使用group1 a (g1a)
替换下表中的mov eax,-1
。
第1组a | 移动传真,-1 | 测试7 |
组1 b | mov rax,-1 | 测试3 |
组2 a | 异或eax、eax/dec eax | 测试6 |
组2 b | xor eax,eax/dec rax | 测试2 |
组3 a | 异或ECX、ECX/Lea eax、[RCX-1] | 测试0 |
组3 b | XOR ECX、ECX/Lea Rax、[RCX-1] | test-1(测试00) |
组4 a | 或eax,-1 | 测试5 |
组4 b | 或RAX,-1 | 测试1 |
下表显示,从组1到组3,使用64位寄存器时,每个循环多1个周期。
IDQ_UOPS_NOT_DELIVERED也增加了,这可能解释了周期数增加的原因。但这能否解释每个循环多1个周期的确切原因?
g1a | 1300,903,705 | 1,300,104,496 | 800,055,137 | 601,487,115 |
g1b | 1,400,852,931 | 1,400,092,325 | 800,049,313 | 1,001,524,712 |
g2a | 1600,920,156 | 1,600,113,480 | 1300,061,359 | 501,522,554 |
G2B | 1700,834,769 | 1700,108,688 | 1300,057,576 | 901,467,008 |
g3a | 1,701,971,425 | 1700,093,298 | 1300,111,482 | 902,327,493 |
g3b | 1,800,891,861 | 1800,110,096 | 1300,059,338 | 1,301,497,001 |
g4a | 1,201,164,208 | 1,200,122,275 | 1100,049,081 | 201,592,292 |
g4b | 1,200,553,577 | 1200,074,422 | 1100,031,729 | 200,772,985 |
此外,g2a和g2b的端口分布不同,不同于g1a和g1b(g1a和g1b端口分布相同),也不同于g3a和g3b。
如果我评论times 32 nop
,这种现象就会消失。与尘螨有关吗?
g1a | 299,868,019 | 300,014,657 | 5925 | 7794 | 16,589 | 300,279,232 | 499,885,294 | 7,242 |
g1b | 299,935,968 | 300,085,089 | 6622 | 8758 | 18,842 | 299,935,445 | 500,426,436 | 7,336 |
g2a | 299,800,192 | 299,758,460 | 7,461 | 9,635 | 20,622 | 399,836,486 | 400,312,354 | 8,446 |
G2B | 200,047,079 | 200,203,026 | 7899 | 9967 | 21,539 | 500,542,313 | 500,296,034 | 9,635 |
g3a | 36,568 | 550,860,773 | 7,784 | 10,147 | 22,538 | 749,063,082 | 99,856,623 | 9,767 |
g3b | 36,858 | 599,960,197 | 8,232 | 10,763 | 23,086 | 700,499,893 | 100,078,368 | 9,513 |
g4a | 200,142,036 | 300,600,535 | 5383 | 6705 | 15,344 | 400,045,302 | 500,364,377 | 6,802 |
g4b | 200,224,703 | 300,284,609 | 5464 | 7,031 | 15,817 | 400,047,050 | 499,467,546 | 6746 |
环境:英特尔i7-10700、ubuntu20.04和NASM 2.14.02。
对我来说,用英语解释这个有点难。如果描述不清楚,请注明。
推荐答案
您所有示例中的瓶颈是预解码器。
我用我的模拟器uiCA(https://uica.uops.info/,https://github.com/andreas-abel/uiCA)分析了您的示例。它预测以下吞吐量,与您的测量结果非常接近:
g1a | 13.00 | https://uica.uops.info/?code=... |
g1b | 14.00 | https://uica.uops.info/?code=... |
g2a | 16.00 | https://uica.uops.info/?code=... |
G2B | 17.00 | https://uica.uops.info/?code=... |
g3a | 17.00 | https://uica.uops.info/?code=... |
g3b | 18.00 | https://uica.uops.info/?code=... |
g4a | 12.00 | https://uica.uops.info/?code=... |
g4b | 12.00 | https://uica.uops.info/?code=... |
uiCA生成的跟踪表提供了有关代码如何执行的一些信息。例如,对于g1a,它生成以下跟踪:
您可以看到,对于32个NOP,预解码器需要8个周期,而对于其余指令,它需要5个周期,这些周期加在一起相当于您测量的13个周期。
您可能会注意到,在某些周期中,只对少量指令进行预解码;例如,在第四个周期中,只对一条指令进行预解码。这是因为预解码器在对齐的16字节块上工作,并且它每个周期最多可以处理5条指令(请注意,一些来源错误地声称它每个周期可以处理6条指令)。您可以在this paper中找到有关预解码器的更多详细信息,例如它如何处理跨越16字节边界的指令。如果将此跟踪与g1b的跟踪进行比较,您可以看到,NOPS之后的指令现在需要6个周期而不是5个周期来预解码,这是因为G1b中的几个指令比G1a中的相应指令更长。这篇关于32位和64位寄存器会导致CPU微体系结构的差异吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!