慢速XOR运算符

dsh*_*hin 6 c++ optimization xor

编辑:的确,我的计时代码中出现了一个奇怪的错误,导致了这些结果.当我修复错误时,智能版本按预期更快地结束.我的时间码看起来像这样:

bool x = false;
before = now();
for (int i=0; i<N; ++i) {
  x ^= smart_xor(A[i],B[i]);
}
after = now();
Run Code Online (Sandbox Code Playgroud)

我这样做是^=为了阻止我的编译器优化for循环.但我认为它以^=某种方式奇怪地与两个xor函数交互.我改变了我的定时代码,只需填写xor结果数组,然后在定时代码之外用该数组进行计算.那个固定的东西.

我应该删除这个问题吗?

结束编辑

我定义了两个C++函数如下:

bool smart_xor(bool a, bool b) {
  return a^b;
}

bool dumb_xor(bool a, bool b) {
  return a?!b:b;
}
Run Code Online (Sandbox Code Playgroud)

我的时序测试表明它dumb_xor()稍快一些(内联时为1.31ns vs 1.90ns,未内联时为1.92ns vs 2.21ns).这让我很困惑,因为^操作员应该是一台机器操作.我想知道是否有人有解释.

程序集看起来像这样(当没有内联时):

    .file   "xor.cpp"
    .text
    .p2align 4,,15
.globl _Z9smart_xorbb
    .type   _Z9smart_xorbb, @function
_Z9smart_xorbb:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    movl    %esi, %eax
    xorl    %edi, %eax
    ret
    .cfi_endproc
.LFE0:
    .size   _Z9smart_xorbb, .-_Z9smart_xorbb
    .p2align 4,,15
.globl _Z8dumb_xorbb
    .type   _Z8dumb_xorbb, @function
_Z8dumb_xorbb:
.LFB1:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    movl    %esi, %edx
    movl    %esi, %eax
    xorl    $1, %edx
    testb   %dil, %dil
    cmovne  %edx, %eax
    ret
    .cfi_endproc
.LFE1:
    .size   _Z8dumb_xorbb, .-_Z8dumb_xorbb
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section        .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

我在Intel Xeon X5570上使用g ++ 4.4.3-4ubuntu5.我用-O3编译.

Mac*_*ade 5

我认为你没有正确地对你的代码进行基准测试.

我们可以在生成的程序集中看到您的smart_xor函数是:

movl    %esi, %eax
xorl    %edi, %eax
Run Code Online (Sandbox Code Playgroud)

而你的dumb_xor功能是:

movl    %esi, %edx
movl    %esi, %eax
xorl    $1, %edx
testb   %dil, %dil
cmovne  %edx, %eax
Run Code Online (Sandbox Code Playgroud)

显然,第一个会更快.
如果没有,那么你有基准问题.

因此,您可能希望调整基准测试代码......并且记住,您需要运行大量调用以获得良好且有意义的平均值.


Mat*_*son 4

鉴于您的“哑异或”代码明显更长(并且大多数指令依赖于前一个指令,因此它不会并行运行),我怀疑您的结果中存在某种测量错误。

编译器将需要为“智能 XOR”的外联版本生成两条指令,因为数据传入的寄存器不是给出返回结果的寄存器,因此数据必须从 EDI 移动,并且ESI 到 EAX。在内联版本中,代码应该能够使用调用之前数据所在的任何寄存器,并且如果代码允许,结果将保留在它传入的寄存器中。

离线调用函数的执行时间可能至少与函数中实际代码的执行时间一样长。

如果您也展示用于基准测试的测试工具,这将会有所帮助......