编辑:的确,我的计时代码中出现了一个奇怪的错误,导致了这些结果。当我修复错误时,智能版本按预期更快地结束。我的时间码看起来像这样:
bool x = false;
before = now();
for (int i=0; i<N; ++i) {
x ^= smart_xor(A[i],B[i]);
}
after = now();
我完成了^=
以阻止我的编译器优化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;
}
我的时序测试表明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
我在Intel Xeon X5570上使用g ++ 4.4.3-4ubuntu5。我用-O3编译。
答案 0 :(得分:5)
我认为您没有正确对代码进行基准测试。
我们可以在生成的程序集中看到您的smart_xor
函数是:
movl %esi, %eax
xorl %edi, %eax
,而您的dumb_xor
功能是:
movl %esi, %edx
movl %esi, %eax
xorl $1, %edx
testb %dil, %dil
cmovne %edx, %eax
很明显,第一个会更快 如果没有,那么你就有基准问题。
所以你可能想要调整你的基准测试代码......并且记住你需要运行很多调用来获得一个好的和有意义的平均值。
答案 1 :(得分:4)
鉴于您的“哑XOR”代码明显更长(并且大多数指令依赖于前一个,因此它不会并行运行),我怀疑您的结果中存在某种测量错误。
编译器需要为“smart XOR”的外联版本生成两条指令,因为数据所在的寄存器不是给出返回结果的寄存器,因此数据必须移动从EDI和ESI到EAX。在内联版本中,代码应该能够在调用之前使用数据所在的任何寄存器,如果代码允许,结果将保留在它所来自的寄存器中。
调用函数的行外可能至少与函数中的实际代码一样长。
如果您展示用于基准测试的测试工具,那将会有所帮助......