我正在寻找一种公式/方法来衡量一条指令的速度,或者更具体地说是通过CPU周期给出每条指令的"得分".
我们以下面的汇编程序为例,
nop
mov eax,dword ptr [rbp+34h]
inc eax
mov dword ptr [rbp+34h],eax
Run Code Online (Sandbox Code Playgroud)
以及英特尔Skylake的以下信息:
mov r,m:吞吐量= 0.5延迟= 2
mov m,r:吞吐量= 1延迟= 2
nop:吞吐量= 0.25延迟=非
inc:吞吐量= 0.25延迟= 1
我知道程序中指令的顺序在这里很重要,但我希望创建一些通用的东西,不需要"对单循环准确"
任何人都知道我该怎么做?
非常感谢
我发现与二进制/双态特性相反,x86 CPU在处理诸如SHR,BT,BTR,ROL等类似的二进制操作指令时非常慢.
例如,我从某个地方读取它,比特移位/旋转超过1个位置被认为是慢的(具有高延迟,性能损失和那些可怕的东西).当操作数在内存中时更糟糕(不是内存双态外设吗?)
shl eax,1 ;ok
shl eax,7 ;slow?
Run Code Online (Sandbox Code Playgroud)
那么是什么让他们变慢?具有讽刺意味的是,像CPU一样的二进制机器在进行这种操作时应该很慢.它给人的印象是二进制CPU正在将位移位困难!
编辑:现在在手册中第二次看SHL条目后,它确实涉及一些沉重的微代码逻辑!
来自英特尔的vol.2手册shl ...
Operation
TemporaryCount = Count & 0x1F;
TemporaryDestination = Destination;
while(TemporaryCount != 0) {
if(Instruction == SAL || Instruction == SHL) {
CF = MSB(Destination);
Destination = Destination << 1;
}
//instruction is SAR or SHR
else {
CF = LSB(Destination);
if(Instruction == SAR) Destination = Destination / 2; //Signed divide, rounding toward negative infinity
//Instruction is SHR
else Destination = Destination / 2; //Unsigned divide …Run Code Online (Sandbox Code Playgroud) 我写了一个简单的循环:
int volatile value = 0;
void loop(int limit) {
for (int i = 0; i < limit; ++i) {
++value;
}
}
Run Code Online (Sandbox Code Playgroud)
我用gcc和clang(-O3 -fno-unroll-loops)进行了编译,得到了不同的输出。它们++value部分不同:
铛:
add dword ptr [rip + value], 1 # ++value
add edi, -1 # --limit
jne .LBB0_1 # if limit > 0 then continue looping
Run Code Online (Sandbox Code Playgroud)
gcc:
mov eax, DWORD PTR value[rip] # copy value to a register
add edx, 1 # ++i
add eax, 1 # increment a copy of value …Run Code Online (Sandbox Code Playgroud) 我在鬼混,发现以下
#include <stdio.h>
void f(int& x){
x+=1;
}
int main(){
int a = 12;
f(a);
printf("%d\n",a);
}
Run Code Online (Sandbox Code Playgroud)
当由g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4with翻译g++ main.cpp -S生成此组件时(仅显示相关部件)
_Z1fRi:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
leal 1(%rax), %edx
movq -8(%rbp), %rax
movl %edx, (%rax)
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $12, -4(%rbp)
leaq -4(%rbp), %rax
movq %rax, %rdi
call _Z1fRi
movl -4(%rbp), %eax
movl %eax, %esi …Run Code Online (Sandbox Code Playgroud) 我目前正在编写编译器,即将实现代码生成.目前的目标指令集是x64.
现在x64是CISC,因此有许多复杂的指令.但我知道这些内部由CPU内部转换为RISC,之后也会出现无序执行.
因此,我的问题是:使用更短的指令(类似RISC)是否会比使用更少的复杂指令产生性能影响?我语言的测试程序并不是那么大,所以我认为在缓存中使用指令应该不是问题.
我了解的是,指令融合有两种类型:
微操作是指可以在1个时钟周期内执行的操作。如果几个微操作融合在一起,我们将获得一个“指令”。
如果融合了多条指令,我们将获得宏操作。
如果几个宏操作融合在一起,我们将获得宏操作融合。
我对么?
设置均值flag value = 1和未设置均值flag value = 0
现在我了解有几种方法可以在MASM中设置和取消设置标志,如下所示:
test al,0 ; set Zero flag
and al,0 ; set Zero flag
or al,1 ; clear Zero flag
Run Code Online (Sandbox Code Playgroud)
同样适用于Sign flag:
or al,80h ; set Sign flag
and al,7Fh ; clear Sign flag
Run Code Online (Sandbox Code Playgroud)
要设置Carry flag,我们使用STC指令; 要清除Carry标志,我们使用CLC:
stc ; set Carry flag
clc ; clear Carry flag
Run Code Online (Sandbox Code Playgroud)
要设置Overflow flag,我们添加两个产生负和的正值.要清除Overflow flag,我们OR操作数为0:
mov al,7Fh ; AL = +127
inc al ; AL = 80h (-128), …Run Code Online (Sandbox Code Playgroud)