2015-09-03 8 views
12

Bu iki kod parçacığı aynı şeyi yapar: İki şamandıra dizisini bir araya ekleme ve sonucu tekrar onlara kaydetme.Düz C++ Kodu Satır içi birleştiriciden 10 kat daha hızlı. Niye ya?

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

Düz C++ Kod:

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

Demontaj C++ Kanunu (i nedense yayın modunda Demontajı görüntüleyemezsiniz çünkü Demontaj ayıklama modunda yapılan) için:

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 

} 

Şimdi bu işlevler için bir zaman ölçümü yaptım ve inlin fark ettim e assembler kodu yaklaşık 10 kat daha uzun sürer (Release modunda). Nedenini bilen var mı? Benim makinede (VS2015 64-bit modu) On

+3

Karşılaştırma için C++ kodunun demontajını gösterebilir misiniz? – Erik

+1

Ayrıca, hangi derleyiciyi kullandığınızı da belirtin. (VC++ gibi görünüyor mu?) –

+0

VC++ 2015 kullandım – Philinator

cevap

19

, derleyici inlines vecAdd_Std ve üretir

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

Testi kodu

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

Tamam, bu soruya cevap veriyor. Ve şimdi bu fonksiyonda neden bir kırılma noktası ayarlayamadığım açık. Cevaplarınız için teşekkürler. – Philinator

+1

Bu hile, aynı float vektörünü iki kez kullanarak bir bellek yükünü kaldırıyorsunuz :) –

+4

@Cross_ - Bu "adil bir kıyaslama" anlamına gelmiyordu, ama Philinator'un sökülmesinin bile derleyici serbest bırakma modunda üretir. Ve bu "el ile optimize edilmiş" montaj, alabileceğiniz en iyi kod otomatik olarak değil. –

5

Gerçekten bir çalışan bir işlevi demiyorsun SSE talimatı sen misin? Xmm kayıtlarını ayarlamak için önemsiz bir genel gider var, ve hafızadan kayıtlara ve geri değerlerini kopyalarsınız, bu da gerçek hesaplamadan çok daha uzun sürer.

Derleyicinin, işlevin C++ sürümünü satır içinde bulduğunu, ancak satır içi derlemeyi içeren işlevler için aynı şeyi yapamadığını (şaşırtmadığını) anlamıyorum.

İlgili konular