2011-02-01 9 views
6

मैं एक 4 डी वेक्टर सामान्य करने की कोशिश कर रहा हूं।सरल सन्निकटन से एसएसई सामान्यीकरण धीमा?

मेरा पहला दृष्टिकोण एसएसई इंट्रिनिक्स का उपयोग करना था - कुछ ऐसा जो मेरे वेक्टर अंकगणित में 2 गुना गति प्रदान करता था। यहाँ बुनियादी कोड है: (v.v4 इनपुट है) (जीसीसी का उपयोग कर) (यह सब inlined है)

//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)); 

मैं disassembly की जाँच करें और यह मैं कैसे उम्मीद करेंगे की तरह दिखता है। मुझे वहां कोई बड़ी समस्या नहीं दिख रही है।

फिर भी, तो मैं यह एक सन्निकटन उपयोग करने की कोशिश: (मैं गूगल से यह मिल गया)

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); 

यह SSE संस्करण की तुलना में थोड़ा तेजी से चल रहा है! (लगभग 5-10% तेज) इसके परिणाम भी बहुत सटीक हैं - लंबाई खोजने पर मैं 0.001 कहूंगा! लेकिन .. जीसीसी मुझे उस लंगड़ा प्रकार के कारण लंगड़ा सख्त एलियासिंग नियम दे रहा है। संशोधित संस्करण (कोई चेतावनी के साथ) धीमी चल रहा है

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); 

और अब !!:

तो मैं इसे संशोधित यह लगभग 60% गति चल रहा है जो एसएसई संस्करण चलाता है (लेकिन एक ही परिणाम)! ऐसा क्यों है?

तो यहाँ सवाल (रों) है:

  1. मेरी SSE implentation सही है?
  2. एसएसई सामान्य एफपीयू संचालन से वास्तव में धीमी है?
  3. तीसरा कोड इतना धीमा क्यों है?
+0

यह जानने में मदद करेगा कि आप किस सीपीयू का उपयोग कर रहे हैं। जैसे पुराने x86 CPUs (पूर्व कोर 2) में बहुत खराब एसएसई क्षमताओं थी। –

+0

मैं इंटेल पेंटियम ड्यूल-कोर – Pubby

+3

पर हूं http://stackoverflow.com/questions/1528727/why-is-sse-scalar-sqrtx-slower-than-rsqrtx-x का डुप्लिकेट? – celion

उत्तर

2

मैं एक डोप हूं - मुझे एहसास हुआ कि मेरे पास बेंचमार्किंग के दौरान सेटी @ होम चल रहा था। मुझे लगता है कि यह मेरे एसएसई प्रदर्शन को मार रहा था। इसे बंद कर दिया और इसे तेजी से दो बार चल रहा था।

मैंने इसे एएमडी एथलॉन पर भी परीक्षण किया और उसी परिणाम प्राप्त किए - एसएसई तेज था।

कम से कम मैंने शफ बग तय किया!

0

मेरा अनुमान है कि तीसरा संस्करण धीमा है क्योंकि संकलक यूनियन को मेमोरी वैरिएबल में डालने का फैसला करता है। कास्ट केस में, यह रजिस्टर से पंजीकरण के लिए मूल्यों की प्रतिलिपि बना सकता है। आप जेनरेट किए गए मशीन कोड को देख सकते हैं।

एसएसई गलत क्यों है, मेरे पास कोई जवाब नहीं है। यदि आप वास्तविक संख्या दे सकते हैं तो इससे मदद मिलेगी। यदि अंतर 1 आकार के वेक्टर पर 0.3 है, तो यह अपमानजनक होगा।

+0

x87 fpu अधिक सटीक कारण है क्योंकि यह आंतरिक रूप से 80 बिट फ़्लोटिंग पॉइंट मानों का उपयोग करके गणना करता है। – Trass3r

1

यहां सबसे कुशल असेंबली कोड है जो मैं सोच सकता हूं। आप इसकी तुलना कर सकते हैं कि आपके कंपाइलर क्या उत्पन्न करता है। मान लें कि इनपुट और आउटपुट एक्सएमएम 0 में हैं।

 ; 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(...) } 
संबंधित मुद्दे