我尝试了三种方法在C中的两个值之间切换变量,代码位于:
void with_xor(int *value)
{
*value ^= VAL_ONE ^ VAL_TWO;
}
void with_conditional(int *value)
{
*value = (*value == VAL_ONE)? VAL_TWO : VAL_ONE;
}
void with_if(int *value)
{
if(VAL_ONE == *value)
{
*value = VAL_TWO;
}
else
{
*value = VAL_ONE;
}
}
我期待“xor”方法比其他两种方法快得多,但似乎并非如此。那是为什么?
以下是测试结果:
xor 0.052300
conditional 0.035738
if 0.034924
这是一个反汇编(没有标志编译):
_with_xor:
0000000100000bd0 pushq %rbp
0000000100000bd1 movq %rsp,%rbp
0000000100000bd4 movq %rdi,0xf8(%rbp)
0000000100000bd8 movq 0xf8(%rbp),%rax
0000000100000bdc movl (%rax),%eax
0000000100000bde xorl $0x0f,%eax
0000000100000be1 movq 0xf8(%rbp),%rcx
0000000100000be5 movl %eax,(%rcx)
0000000100000be7 popq %rbp
0000000100000be8 ret
0000000100000be9 nopl 0x00000000(%rax)
_with_conditional:
0000000100000bf0 pushq %rbp
0000000100000bf1 movq %rsp,%rbp
0000000100000bf4 movq %rdi,0xf8(%rbp)
0000000100000bf8 movq 0xf8(%rbp),%rax
0000000100000bfc movl (%rax),%eax
0000000100000bfe cmpl $0x0a,%eax
0000000100000c01 jne 0x100000c0c
0000000100000c03 movl $0x00000005,0xf4(%rbp)
0000000100000c0a jmp 0x100000c13
0000000100000c0c movl $0x0000000a,0xf4(%rbp)
0000000100000c13 movq 0xf8(%rbp),%rax
0000000100000c17 movl 0xf4(%rbp),%ecx
0000000100000c1a movl %ecx,(%rax)
0000000100000c1c popq %rbp
0000000100000c1d ret
0000000100000c1e nop
_with_if:
0000000100000c20 pushq %rbp
0000000100000c21 movq %rsp,%rbp
0000000100000c24 movq %rdi,0xf8(%rbp)
0000000100000c28 movq 0xf8(%rbp),%rax
0000000100000c2c movl (%rax),%eax
0000000100000c2e cmpl $0x0a,%eax
0000000100000c31 jne 0x100000c3f
0000000100000c33 movq 0xf8(%rbp),%rax
0000000100000c37 movl $0x00000005,(%rax)
0000000100000c3d jmp 0x100000c49
0000000100000c3f movq 0xf8(%rbp),%rax
0000000100000c43 movl $0x0000000a,(%rax)
0000000100000c49 popq %rbp
0000000100000c4a ret
0000000100000c4b nopl 0x00(%rax,%rax)
答案 0 :(得分:3)
首先:代码的“条件”和“if”变体在功能上是相同的,实际上编译器为两者生成几乎相同的代码。
分支预测可能会在这里显着影响您的结果 - 因为您总是在5到10之间切换值并且直接返回,条件/ if变量中的分支可以以接近100%的准确度预测,转向函数进入商店,可以与比较几乎同时运行。另一方面,XOR变体必须作为load-xor-store序列运行 - 这三个操作都不能在前一个操作完成之前运行。
答案 1 :(得分:0)
您通常无法在CPU上管道xors,但您可以管道移动指令。所以XOR过程要慢得多。
基本上,在您的指令管道中,您希望执行尽可能多的指令。由于一般情况下,分支预测非常好,CPU将能够正确解析所有这些mov指令并确定所有内容并行结束的位置。另一方面,在它们的前辈被异或之前不可能对事物进行异或,因此CPU必须等待先前的XOR指令在执行下一个之前解析。慢得多。