2011-02-01 23 views
6

4d vektörünü normalleştirmeye çalışıyorum.SSE normalizasyonu basit yaklaşımdan daha mı yavaş?

İlk onayım SSE intrinsics'i kullanmaktı - vektör aritmetiğime 2 kat hız artışı sağlayan bir şey. İşte temel kodudur: (v.v4 girişidir) (GCC kullanarak) (tüm bu satır içi)

//find squares 
v4sf s = __builtin_ia32_mulps(v.v4, v.v4); 
//set t to square 
v4sf t = s; 
//add the 4 squares together 
s = __builtin_ia32_shufps(s, s, 0x1B); 
t  = __builtin_ia32_addps(t, s); 
s = __builtin_ia32_shufps(s, s, 0x4e); 
t  = __builtin_ia32_addps(t, s); 
s = __builtin_ia32_shufps(s, s, 0x1B); 
t  = __builtin_ia32_addps(t, s); 
//find 1/sqrt of t 
t  = __builtin_ia32_rsqrtps(t); 
//multiply to get normal 
return Vec4(__builtin_ia32_mulps(v.v4, t)); 

Ben demontaj kontrol ve ben beklediğiniz nasıl benziyor. Orada büyük problemler görmüyorum.

Neyse, o zaman tahmin etmenin denedim: (ı google bu var) O SSE sürümü biraz daha hızlı çalışıyor

float x = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z); 
float xhalf = 0.5f*x; 
int i = *(int*)&x; // get bits for floating value 
i = 0x5f3759df - (i>>1); // give initial guess y0 
x = *(float*)&i; // convert bits back to float 
x *= 1.5f - xhalf*x*x; // newton step, repeating this step 
// increases accuracy 
//x *= 1.5f - xhalf*x*x; 
return Vec4(v.w*x, v.x*x, v.y*x, v.z*x); 

! (yaklaşık% 5-10 daha hızlı) Bu sonuçlar da çok doğru - Uzunluk bulurken 0.001'e söyleyebilirim! Ama .. GCC bana bu tür yumuşacık nedeniyle katı takma kuralını veriyor. Şimdi (herhangi bir uyarı olmadan) modifiye versiyonu yavaş çalışıyorsa

union { 
    float fa; 
    int ia; 
}; 
fa = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z); 
float faHalf = 0.5f*fa; 
ia = 0x5f3759df - (ia>>1); 
fa *= 1.5f - faHalf*fa*fa; 
//fa *= 1.5f - faHalf*fa*fa; 
return Vec4(v.w*fa, v.x*fa, v.y*fa, v.z*fa); 

Ve !!:

yüzden değiştirmek SSE sürümünün (ama aynı sonuç) çalıştığı hızın neredeyse% 60'ı çalışıyor! Bu neden?

  1. benim SSE implentation doğru mu: Yani burada

    soru (lar) mı?

  2. SSE normal fpu işlemlerinden gerçekten daha yavaş mı?
  3. Neden 3. kod bu kadar yavaş?
+0

Hangi CPU'yu kullandığınızı bilmek yardımcı olur. Örneğin. Eski x86 CPU'lar (ön Core 2) çok zayıf SSE yeteneklerine sahipti. –

+0

Intel Pentium Çift Çekirdekli – Pubby

+3

'm var http://stackoverflow.com/questions/1528727/why-is-sse-scalar-sqrtx-slower-than-rsqrtx-x Çoğaltıcım? – celion

cevap

2

Ben bir uyuşukum - Ben SETI @ Home kıyaslama yaparken çalışırken fark ettim. Sanırım SSE performansımı öldürüyordu. Çıkardı ve iki kat hızlı koştu.

Ayrıca bir AMD atlı üzerinde test ettim ve aynı sonuçları aldım - SSE daha hızlıydı.

En azından shuf hatasını düzelttim!

0

Derleyicim, 3. sürümün daha yavaş olduğunu çünkü derleyici birliği bir bellek değişkenine koymaya karar verdi. Döküm durumda, kayıttan kayıtlara değerleri kopyalayabilir. Sadece üretilen makine koduna bakabilirsiniz.

SSE'nin neden yanlış olduğuna dair bir cevabım yok. Gerçek sayılar verebilirseniz yardımcı olur. Boyut 1'in bir vektöründe fark 0,3 ise, bu çirkin olur.

+0

x87 fpu daha doğrudur, çünkü 80bit kayan nokta değerlerini kullanarak dahili olarak hesaplar. – Trass3r

1

İşte akla gelebilecek en verimli montaj kodu. Bunu, derleyicinizin ürettiği şeyle karşılaştırabilirsiniz. giriş ve çıkış XMM0 içinde olduğunu varsayalım.

 ; start with xmm0 = { v.x v.y v.z v.w } 
     movaps %xmm0, %mm1   ; save it till the end 
     mulps %xmm0, %xmm0  ; v=v*v 
     pshufd $1, %xmm0, %xmm1 ; xmm1 = { v.y v.x v.x v.x } 
     addss %xmm0, %xmm1  ; xmm1 = { v.y+v.x v.x v.x v.x } 
     pshufd $3, %xmm0, %xmm2 ; xmm2 = { v.w v.x v.x v.x } 
     movhlps %xmm0, %xmm3  ; xmm3 = { v.z v.w ? ? } 
     addss %xmm1, %xmm3  ; xmm3 = { v.y+v.x+v.z v.x ? ? } 
     addss %xmm3, %xmm2  ; xmm2 = { v.y+v.x+v.z+v.w v.x v.x v.x } 
     rsqrtps %xmm2, %xmm1  ; xmm1 = { rsqrt(v.y+v.x+v.z+v.w) ... } 
     pshufd $0, %xmm1, %xmm1 ; xmm1 = { rsqrt(v.y+v.x+v.z+v.w) x4 } 
     mulps %xmm1, %xmm0  
     ; end with xmm0 = { v.x*sqrt(...) v.y*sqrt(...) v.z*sqrt(...) v.w*sqrt(...) }