1

我尝试了三种方法在 C 中的两个值之间切换变量,代码位于:

http://pastebin.com/K481DsU3

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)
4

2 回答 2

3

首先:代码的“条件”和“如果”变体在功能上是相同的,实际上编译器为两者生成几乎相同的代码。

分支预测可能会显着影响您的结果 - 因为您总是在 5 和 10 之间切换值并直接返回,条件/if 变体中的分支可以以接近 100% 的准确度进行预测,将函数转换为可以与比较几乎同时运行的商店。另一方面,XOR 变体必须作为加载-异或-存储序列运行——这三个操作都不能在前一个操作完成之前运行。

于 2012-07-02T00:49:34.710 回答
0

您通常不能在 CPU 上流水线异或,但可以流水线移动指令。所以异或过程要慢得多。

本质上,在您的指令管道中,您希望执行尽可能多的指令。因为总的来说,分支预测非常好,CPU 将能够正确解析所有这些 mov 指令并决定并行结束所有内容。另一方面,在其前任被异或之前不可能对事物进行异或运算,因此 CPU 必须等待前一个异或指令解决,然后再执行下一个异或指令。慢得多。

于 2012-07-02T00:44:15.273 回答