2011-10-07 8 views
5

यहां ओपनसीएल कर्नेल से कोड के दो टुकड़े हैं जिन पर मैं काम कर रहा हूं; वे काफी अलग रन-टाइम प्रदर्शित करते हैं।ओपनसीएल: इन दो मामलों के बीच प्रदर्शन इतना अलग क्यों है?

कोड अपेक्षाकृत जटिल है, इसलिए मैंने इसे सरल बना दिया है।

इस संस्करण में एक सेकंड के तहत में चलता है:

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
     double nothing = value1; 
    } 
} 

और इस संस्करण को चलाने के लिए चारों ओर 38 सेकंड लेता है:

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

मैं कहता हूँ के रूप में, कोड (इस की तुलना में कुछ अधिक जटिल है वहाँ लूप में कई अन्य चीजें चल रही हैं), लेकिन परिवर्तनीय "कुछ नहीं" वास्तव में ब्रेस के तुरंत बाद तुरंत से आगे बढ़ता है।

मैं ओपनसीएल के लिए बहुत नया हूं, और मैं यह नहीं कर सकता कि क्या हो रहा है, इसे ठीक करने के लिए बहुत कम है। कहने की जरूरत नहीं है, धीमा मामला वास्तव में मेरे कार्यान्वयन में मुझे चाहिए। मैंने पता रिक्त स्थान के साथ गड़बड़ करने की कोशिश की है (यहां सभी चर __private में हैं)।

मैं केवल कल्पना कर सकता हूं कि कुछ कारणों से जीपीयू परिवर्तनीय "वैल्यू 1" को धीमा स्मृति में बंद कर रहा है जब ब्रेस बंद हो जाता है। क्या यह एक संभावित स्पष्टीकरण है? मैं क्या कर सकता हूँ?

अग्रिम धन्यवाद!

अद्यतन: यह एक सेकंड के भीतर भी चलता है: (लेकिन किसी भी लाइन को अपरिवर्तित करने के साथ, यह अत्यधिक धीमी गति से बदल जाता है)। यह लूप में कोई अन्य बदलाव किए बिना है, और वैल्यू 1 अभी भी उसी स्थान पर घोषित किया गया है जैसा कि पहले था।

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
//  value1 = value2 + value3; 
//  value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

अद्यतन 2: के रूप में दिखाया गया कोड वास्तव में value1 की घोषणा के साथ, इस तरह एक और पाश में नेस्ट किया गया था:

double value1=0; 
for (int kk=0; kk<someNumber3;kk++) 
{ 
    for (int ii=0; ii<someNumber;ii++) 
    { 
     for (int jj=0; ii<someNumber2;jj++) 
     { 
      value1 = value2 + value3; 
      value1 = value1 * someFunction(a,b,c); 
     } 
     double nothing = value1; 
    } 
} 

बढ़ते जहां value1 यह भी घोषणा की हमें तेजी से मामले को वापस हो जाता है है:

for (int kk=0; kk<someNumber3;kk++) 
{ 
    double value1=0; 
    for (int ii=0; ii<someNumber;ii++) 
    { 
     for (int jj=0; ii<someNumber2;jj++) 
     { 
      value1 = value2 + value3; 
      value1 = value1 * someFunction(a,b,c); 
     } 
     double nothing = value1; 
    } 
} 

ऐसा लगता है कि ओपनसीएल एक बेहद मुश्किल कला है! मैं अभी भी वास्तव में समझ नहीं पा रहा हूं कि क्या हो रहा है, लेकिन कम से कम मुझे पता है कि इसे कैसे ठीक किया जाए!

+0

यह बहुत अजीब है। क्या आप वाकई धीमे संस्करण का उपयोग करने की ज़रूरत है? इन स्निपेट से वे कार्यात्मक रूप से समान दिखते हैं। – Chriszuma

+0

आपके उत्तर के लिए धन्यवाद। हाँ मुझे यकीन है, लेकिन आप सही हैं कि मैंने जो उदाहरण दिए हैं वे कार्यात्मक रूप से समान हैं। आंतरिक ब्रेसिज़ में कोड एक + = होना चाहिए। – carthurs

+0

मुझे कोई कारण नहीं दिख रहा है कि दूसरे कोड को उन कोड स्निपेट के आधार पर धीमा होना चाहिए। मुझे लगता है कि असाइनमेंट को ले जाना कहीं साइड इफेक्ट्स होना चाहिए, जैसे बढ़ी हुई शाखाएं (एक कार्य इकाई 'if' निष्पादित करती है, अगला' अन्य 'निष्पादित करती है), जो वास्तव में GPU को धीमा कर सकती है। –

उत्तर

4

आप किस कार्यान्वयन का उपयोग कर रहे हैं? मैं "डबल कुछ नहीं = मूल्य 1;" की उम्मीद करूंगा किसी भी मामले में किसी भी उचित संकलक द्वारा मृत कोड के रूप में समाप्त किया जाना है।

+0

मुझे लगता है कि मुझे आपकी समस्या के कारण समस्या मिली है। यदि 1 (मेरे प्रश्न से पहला बॉक्स) में, मुझे लगता है कि संकलक आंतरिक लूप को "मृत कोड के रूप में समाप्त करने" द्वारा अनुकूलित करता है। 2 मामले में, यह महसूस करता है कि आंतरिक लूप के बाहर परिवर्तनीय 'value1' की आवश्यकता है, इसलिए यह इसे चलाता है। समारोह 'कुछ समारोह (ए, बी, सी)' बहुत धीमा है, इसलिए यह मंदी का कारण बनता है। एफवाईआई कार्यान्वयन लिनक्स के लिए एएमडी का एसडीके है। सभी की मदद के लिए धन्यवाद! – carthurs

+0

आप कह रहे हैं कि मान 1 का उपयोग नहीं किया गया है, इसलिए संकलक कुछ फ़ंक्शन को कॉल को ऑप्टिमाइज़ करता है। यह कैसे सुनिश्चित हो सकता है कि कुछ फ़ंक्शन का दुष्प्रभाव नहीं है? – vocaro

+0

क्योंकि 'कुछ नहीं' अप्रयुक्त है। मैं मूल्य 1 के बारे में बात नहीं कर रहा था। – arsenm

2

पहला मामला केवल एक लूप (कंपाइलर अनुकूलन के साथ) है लेकिन दूसरा एक नेस्टेड लूप वाला लूप है। यह एक बड़ा मुद्दा है। वैश्विक/स्थानीय चर के बहुत सारे चेकिंग। (यकीन है कि वे निजी हैं? आपने कर्नेल के अंदर सभी को घोषित किया है?)

मैं आपको लूप शुरू करने से पहले निजी चर (somenumber और somenumber2) के रूप में सहेजने की सलाह देता हूं। क्योंकि इस तरह आप एक निजी डेटा के साथ हर बार जांच करेंगे। व्यक्तिगत अनुभव के रूप में, ओपनसीएल लूप के चेक केस के रूप में उपयोग किए जाने वाले प्रत्येक var को निजी होना चाहिए। यह वैश्विक स्मृति पहुंच का 80% तक बचा सकता है। (खास तौर पर अगर पाश बहुत ही कम या सरल है)

उदाहरण के रूप में, यह तेजी से काम करना चाहिए:

int c_somenumber = someNumber; 
for (int ii=0; ii<c_someNumber;ii++) 
{ 
    int c_somenumber2 = someNumber2;  
    for (int jj=0; ii<c_someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

संपादित करें: इसके अलावा, मान 1 निजी स्मृति में संचित किया जा चाहिए।(जैसा कि आपने अपने अंतिम संपादन में किया था)

+0

हाँ, सबकुछ निजी के रूप में सहेजा जाता है। अन्य जवाब पर टिप्पणी के रूप में समस्या के लिए मेरी व्याख्या देखें! – carthurs

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