普通c++代码比内联汇编器快10倍.为什么
Plain C++ Code 10 times faster than inline assembler. Why?
这两个代码片段做同样的事情:将两个float数组相加并将结果存储回其中。
内联汇编程序:
void vecAdd_SSE(float* v1, float* v2) {
_asm {
mov esi, v1
mov edi, v2
movups xmm0, [esi]
movups xmm1, [edi]
addps xmm0, xmm1
movups [esi], xmm0
movups [edi], xmm0
}
}
普通c++代码:
void vecAdd_Std(float* v1, float* v2) {
v1[0] = v1[0]+ v2[0];
v1[1] = v1[1]+ v2[1];
v1[2] = v1[2]+ v2[2];
v1[3] = v1[3]+ v2[3];
v2[0] = v1[0];
v2[1] = v1[1];
v2[2] = v1[2];
v2[3] = v1[3];
}
c++代码的反汇编(在调试模式下进行的反汇编,因为某些原因无法在发布模式下查看反汇编):
void vecAdd_Std(float* v1, float* v2) {
push ebp
mov ebp,esp
sub esp,0C0h
push ebx
push esi
push edi
lea edi,[ebp-0C0h]
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
v1[0] = v1[0]+ v2[0];
mov eax,4
imul ecx,eax,0
mov edx,4
imul eax,edx,0
mov edx,dword ptr [v1]
mov esi,dword ptr [v2]
movss xmm0,dword ptr [edx+ecx]
addss xmm0,dword ptr [esi+eax]
mov eax,4
imul ecx,eax,0
mov edx,dword ptr [v1]
movss dword ptr [edx+ecx],xmm0
v1[1] = v1[1]+ v2[1];
mov eax,4
shl eax,0
v1[1] = v1[1]+ v2[1];
mov ecx,4
shl ecx,0
mov edx,dword ptr [v1]
mov esi,dword ptr [v2]
movss xmm0,dword ptr [edx+eax]
addss xmm0,dword ptr [esi+ecx]
mov eax,4
shl eax,0
mov ecx,dword ptr [v1]
movss dword ptr [ecx+eax],xmm0
v1[2] = v1[2]+ v2[2];
mov eax,4
shl eax,1
mov ecx,4
shl ecx,1
mov edx,dword ptr [v1]
mov esi,dword ptr [v2]
movss xmm0,dword ptr [edx+eax]
addss xmm0,dword ptr [esi+ecx]
mov eax,4
shl eax,1
mov ecx,dword ptr [v1]
movss dword ptr [ecx+eax],xmm0
v1[3] = v1[3]+ v2[3];
mov eax,4
imul ecx,eax,3
mov edx,4
imul eax,edx,3
mov edx,dword ptr [v1]
mov esi,dword ptr [v2]
movss xmm0,dword ptr [edx+ecx]
addss xmm0,dword ptr [esi+eax]
mov eax,4
imul ecx,eax,3
mov edx,dword ptr [v1]
movss dword ptr [edx+ecx],xmm0
v2[0] = v1[0];
mov eax,4
imul ecx,eax,0
mov edx,4
imul eax,edx,0
mov edx,dword ptr [v2]
mov esi,dword ptr [v1]
mov ecx,dword ptr [esi+ecx]
mov dword ptr [edx+eax],ecx
v2[1] = v1[1];
mov eax,4
shl eax,0
mov ecx,4
shl ecx,0
mov edx,dword ptr [v2]
mov esi,dword ptr [v1]
mov eax,dword ptr [esi+eax]
mov dword ptr [edx+ecx],eax
v2[2] = v1[2];
mov eax,4
shl eax,1
mov ecx,4
shl ecx,1
mov edx,dword ptr [v2]
mov esi,dword ptr [v1]
mov eax,dword ptr [esi+eax]
mov dword ptr [edx+ecx],eax
v2[3] = v1[3];
mov eax,4
imul ecx,eax,3
mov edx,4
imul eax,edx,3
mov edx,dword ptr [v2]
mov esi,dword ptr [v1]
mov ecx,dword ptr [esi+ecx]
mov dword ptr [edx+eax],ecx
}
现在,我对这些函数进行了时间测量,并注意到内联汇编程序代码花费了大约10倍的时间(在发布模式下)。有人知道为什么吗?
在我的机器上(VS2015 64位模式),编译器内联vecAdd_Std
并生成
00007FF625921C8F vmovups xmm1,xmmword ptr [__xmm@4100000040c000004080000040000000 (07FF625929D60h)]
00007FF625921C97 vmovups xmm4,xmm1
00007FF625921C9B vcvtss2sd xmm1,xmm1,xmm4
测试代码
int main() {
float x[4] = {1.0, 2.0, 3.0, 4.0};
float y[4] = {1.0, 2.0, 3.0, 4.0};
vecAdd_Std(x, y);
std::cout << x[0];
}
你并没有真正调用一个执行一个 SSE指令的函数,是吗?在设置xmm寄存器时涉及到不小的开销,并且要将值从内存复制到寄存器并再复制回来,这将比实际计算花费的时间长得多。
如果发现编译器内联了函数的c++版本,但对包含内联汇编的函数没有(真的不能)做同样的事情,我一点也不惊讶。
相关文章:
- 为什么我们不编写可以处理C++标识符的汇编器和链接器?
- 数组中的不同浮点值会影响性能 10 倍 - 为什么?
- C++,自使用boost和std::chrono的纪元以来的时间?为什么 Boost 版本慢 10 倍?
- 如何在 C++ 中将 2 中的数字倍数倍数在 2 中倍数 10 倍?
- 如何使用 gcc 内联汇编器代码访问成员变量
- 如何使用C 给出的地址覆盖汇编器堆栈的返回地址
- 与 2015 相比,内联汇编器给出了 C2400
- 在 c++ 中实现内联汇编器以对变量进行异或操作的正确方法
- C++随机生成器在g++中比MSVC快10倍
- 简单 g++ 内联汇编器中的错误
- C 汇编器转换问题
- 使用SSE将float值从汇编器DLL返回到C
- 内联汇编器直接双倍到长长转换
- “__cpp”和 gcc 内联 ARM 汇编器
- 需要用C或C++编写MIPS汇编器,寻找一些设计建议
- 将 GCC/ATT 风格的汇编器转换为可视化工作室汇编器
- 如何使用内联汇编器保存寄存器值
- 相同的功能?使用 GMP(C++) 时运行速度慢约 10 倍
- 调用传递给 gcc 内联汇编器 (avr-gcc) 的 const 函数地址
- 普通c++代码比内联汇编器快10倍.为什么