2012-07-23 10 views
13

मैं इस तरह एक वर्ग है:संरचना - प्रदर्शन अंतर

//Array of Structures 
class Unit 
{ 
    public: 
    float v; 
    float u; 
    //And similarly many other variables of float type, upto 10-12 of them. 
    void update() 
    { 
     v+=u; 
     v=v*i*t; 
     //And many other equations 
    } 
}; 

मैं इकाई प्रकार की वस्तुओं की एक सरणी पैदा करते हैं। और उन पर अद्यतन कॉल करें।

int NUM_UNITS = 10000; 
void ProcessUpdate() 
{ 
    Unit *units = new Unit[NUM_UNITS]; 
    for(int i = 0; i < NUM_UNITS; i++) 
    { 
    units[i].update(); 
    } 
} 

आदेश चीज़ों को गति, और संभवतः पाश autovectorize करने के लिए, मैं सरणियों के संरचना करने के AOS बदल दिया।

//Structure of Arrays: 
class Unit 
{ 
    public: 
    Unit(int NUM_UNITS) 
    { 
    v = new float[NUM_UNITS]; 
    } 
    float *v; 
    float *u; 
    //Mnay other variables 
    void update() 
    { 
    for(int i = 0; i < NUM_UNITS; i++) 
    { 
     v[i]+=u[i]; 
     //Many other equations 
    } 
    } 
}; 

जब लूप ऑटोवेक्टरिज़ करने में विफल रहता है, तो मुझे सरणी की संरचना के लिए बहुत खराब प्रदर्शन मिल रहा है। 50 इकाइयों के लिए, एसओए का अपडेट एओएस की तुलना में थोड़ा तेज है। लेकिन फिर 100 इकाइयों से, एसओए एओएस की तुलना में धीमी है। 300 इकाइयों पर, सोए लगभग दोगुनी है। 100K इकाइयों पर, एसओए एओएस की तुलना में 4x धीमी है। जबकि कैश सोए के लिए एक मुद्दा हो सकता है, मुझे उम्मीद नहीं थी कि प्रदर्शन अंतर यह उच्च होगा। कैशग्रींड पर प्रोफाइलिंग दोनों दृष्टिकोणों के लिए समान संख्या में मिस दिखाती है। यूनिट ऑब्जेक्ट का आकार 48 बाइट्स है। एल 1 कैश 256 के है, एल 2 1 एमबी है और एल 3 8 एमबी है। मुझे यहां क्या समझ नहीं आ रहा है? क्या यह वास्तव में एक कैश मुद्दा है?

संपादित करें: मैं जीसीसी 4.5.2 का उपयोग कर रहा हूँ। कंपाइलर विकल्प -o3 -msse4 -ftree-vectorize हैं।

मैंने सोए में एक और प्रयोग किया। गतिशील रूप से सरणी आवंटित करने के बजाय, मैंने संकलन समय में "v" और "u" आवंटित किया। जब 100K इकाइयां होती हैं, तो यह एक प्रदर्शन देता है जो गतिशील रूप से आवंटित सरणी के साथ सोए से 10x तेज होता है। यहाँ क्या हो रहा है? स्थैतिक और गतिशील आवंटित स्मृति के बीच ऐसा प्रदर्शन अंतर क्यों है?

+0

इसे बनाने के लिए आप किस कंपाइलर विकल्प का उपयोग करते हैं? –

+0

यह सुनिश्चित नहीं है कि इससे कोई फर्क पड़ता है, लेकिन [std :: valarray] (http://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a00738.html) हो सकता है (या हो सकता है) मदद। यह पूरे सरणी (इस तरह के क्लीनर सिंटैक्स) पर गणितीय परिचालन करने के लिए डिज़ाइन किया गया है, लेकिन मुझे लगता है कि कार्यान्वयनकर्ताओं के पास उन परिचालनों को अनुकूलित करने और बुद्धिमान आवंटन आदि को संभव बनाने के लिए विशेष ओवरलोड होते हैं। यह बिल्कुल मदद नहीं कर सकता है, लेकिन एक लायक हो सकता है। – pstrjds

+1

जब आप बेंचमार्क चलाने से पहले डेटासेट को शून्य करते हैं तो क्या होता है? अनियंत्रित फ्लोटिंग-पॉइंट [denormalized] होने का एक उच्च अवसर है (http://stackoverflow.com/a/9314926/922184)। आप नहीं चाहते कि वह आपके बेंचमार्क को खराब कर दे। – Mysticial

उत्तर

9

इस मामले में सरणी का ढांचा कैश अनुकूल नहीं है।

आप एक साथ दोनों u और v उपयोग करते हैं, लेकिन उनके लिए 2 अलग सरणियों के मामले में वे एक कैश लाइन और कैश छूट जाए में एक साथ लोड किया जा नहीं होगा विशाल प्रदर्शन जुर्माना खर्च होंगे।

_mm_prefetch का उपयोग AoS प्रस्तुत करने के लिए भी किया जा सकता है।

+0

क्या '_mm_prefetch' के लिए जीसीसी/क्लैंग समतुल्य है? –

+0

http://gcc.gnu.org/ml/gcc-patches/2008-01/msg01425.html –

+2

कैश मिस आंशिक रूप से बर्बाद नहीं होते हैं - आपको जो चीजें मिलती हैं वह सामान है * आपको * आवश्यकता होगी (अधिक 'u' और अधिक 'v' है), तो यह प्रदर्शन को कम क्यों करेगा? – harold

1

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

विभिन्न कारणों से, संरचनाएं और कक्षाएं सी ++ में कई प्रदर्शन समस्याएं पैदा कर सकती हैं, और प्रदर्शन के स्वीकार्य स्तर प्राप्त करने के लिए अधिक tweaking की आवश्यकता हो सकती है। जब कोड बड़ा होता है, ऑब्जेक्ट उन्मुख प्रोग्रामिंग का उपयोग करें। जब डेटा बड़ा होता है (और प्रदर्शन महत्वपूर्ण है), तो नहीं।

float v[N]; 
float u[N]; 
    //And similarly many other variables of float type, up to 10-12 of them. 
//Either using an inlined function or just adding this text in main() 
     v[j] += u[j]; 
     v[j] = v[j] * i[j] * t[j]; 
+1

मुझे नहीं लगता कि ओओपी को एओएस का उपयोग करने के साथ भ्रमित नहीं किया जाना चाहिए। एक स्केलर फ़ील्ड को ओओपी में ऑब्जेक्ट माना जा सकता है, क्योंकि इसे गणित में एक वस्तु माना जाता है, लेकिन यदि आप एकाधिक स्केलर फ़ील्ड का उपयोग करके अंतरिक्ष के क्षेत्र का प्रतिनिधित्व करते हैं, तो आप ओओपी के अनुरूप एसओए का उपयोग कर रहे हैं। यह ओओपी में होने वाली वस्तु को आप समझते हैं। – 16807

0

निश्चित रूप से, अगर आप vectorization को प्राप्त नहीं है, वहाँ बहुत ज्यादा नहीं प्रोत्साहन एक SOA परिवर्तन बनाने के लिए है।

__RESTRICT की काफी व्यापक रूप से स्वीकार्यता के अलावा, जीसीसी 4.9 ने अनुमानित एलियासिंग निर्भरताओं को तोड़ने के लिए #pragma GCC ivdep अपनाया है।

स्पष्ट प्रीफेच के उपयोग के रूप में, यदि यह उपयोगी है, तो निश्चित रूप से आपको उनमें से अधिक की आवश्यकता हो सकती है। प्राथमिक बिंदु आगे पृष्ठों को लाकर डीटीएलबी मिस रिज़ॉल्यूशन में तेजी लाने के लिए हो सकता है, इसलिए आपका एल्गोरिदम अधिक कैश भूख बन सकता है।

मुझे नहीं लगता कि जो कुछ भी आप "संकलित समय" आवंटन कहते हैं, उसके बारे में अधिक जानकारी के बिना बुद्धिमान टिप्पणियां की जा सकती हैं, जिसमें आपके ओएस के बारे में विशिष्टताएं शामिल हैं। इसमें कोई संदेह नहीं है कि उच्च स्तर पर आवंटित करने और आवंटन का पुन: उपयोग करने की परंपरा महत्वपूर्ण है।

संबंधित मुद्दे