2015-09-03 19 views
12

Hai đoạn mã này thực hiện tương tự: Thêm hai mảng float với nhau và lưu kết quả trở lại vào chúng.Mã C++ trơn tru nhanh hơn 10 lần so với trình tạo nội tuyến. Tại sao?

Inline Assembler:

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 
    } 
} 

Plain C++ Code:

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]; 
} 

Tháo lắp cho C++ Mã (Tháo lắp thực hiện trong chế độ Debug, vì tôi không thể xem Tháo lắp trong chế độ Release đối với một số lý do):

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 

} 

Bây giờ tôi đã đo thời gian trên những chức năng và nhận thấy rằng inlin mã lắp ráp điện tử mất khoảng 10 lần lâu hơn (trong chế độ Phát hành). Có ai biết tại sao không?

+3

Bạn có thể hiển thị việc tháo gỡ mã C++ để so sánh không? – Erik

+1

Cũng chỉ định trình biên dịch bạn đang sử dụng. (trông giống như VC++?) –

+0

Tôi đã sử dụng VC++ 2015 – Philinator

Trả lời

19

Trên máy tính của tôi (VS2015 64-bit mode), các trình biên dịch inlines vecAdd_Std và sản xuất

00007FF625921C8F vmovups  xmm1,xmmword ptr [[email protected] (07FF625929D60h)] 
00007FF625921C97 vmovups  xmm4,xmm1 
00007FF625921C9B vcvtss2sd xmm1,xmm1,xmm4 

mã kiểm tra

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]; 
} 
+0

Ok trả lời câu hỏi của tôi. Và bây giờ rõ ràng là tại sao tôi không thể đặt điểm ngắt trong hàm này. Cảm ơn rất nhiều cho câu trả lời của bạn. – Philinator

+1

Đó là gian lận, bạn đang sử dụng cùng một véc tơ hai lần để loại bỏ một tải bộ nhớ :) –

+4

@Cross_ - Điều này không có nghĩa là "chuẩn mực công bằng", nhưng để cho thấy rằng việc tháo gỡ của Philinator thậm chí không gần với trình biên dịch tạo ra trong chế độ phát hành. Và đó là "tay tối ưu hóa" lắp ráp không phải là automagically mã tốt nhất bạn có thể nhận được. –

5

Bạn đang không thực sự gọi một hàm để thực thi một Hướng dẫn SSE, phải không? Có chi phí không quan trọng liên quan đến việc thiết lập sổ đăng ký xmm, và bạn đang sao chép các giá trị từ bộ nhớ đến thanh ghi và ngược lại, sẽ mất nhiều thời gian hơn so với phép tính thực tế.

Tôi sẽ không ngạc nhiên khi thấy rằng trình biên dịch inlines phiên bản C++ của hàm, nhưng không (không thể, thực sự) làm tương tự cho các hàm chứa assembly nội tuyến.

Các vấn đề liên quan