尝试切换变量时会出现意外的性能

时间:2012-07-02 00:22:47

标签: c optimization

我尝试了三种方法在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)

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

您通常无法在CPU上管道xors,但您可以管道移动指令。所以XOR过程要慢得多。

基本上,在您的指令管道中,您希望执行尽可能多的指令。由于一般情况下,分支预测非常好,CPU将能够正确解析所有这些mov指令并确定所有内容并行结束的位置。另一方面,在它们的前辈被异或之前不可能对事物进行异或,因此CPU必须等待先前的XOR指令在执行下一个之前解析。慢得多。