2010-03-29 13 views
39

मैं हाल ही में ओपनसीएल के साथ खेल रहा हूं, और मैं सरल कर्नेल लिखने में सक्षम हूं जो केवल वैश्विक स्मृति का उपयोग करते हैं। अब मैं स्थानीय मेमोरी का उपयोग शुरू करना चाहता हूं, लेकिन मुझे लगता है कि एक समय में आउटपुट के "खंड" की गणना करने के लिए get_local_size() और get_local_id() का उपयोग कैसे करें।मैं ओपनसीएल में स्थानीय मेमोरी का उपयोग कैसे करूं?

उदाहरण के लिए, मान लीजिए कि मैं ऐप्पल के ओपनसीएल हैलो वर्ल्ड उदाहरण कर्नेल को स्थानीय मेमोरी का उपयोग करने के लिए परिवर्तित करना चाहता हूं। आपको इसे कैसे करना होगा?

__kernel square(
    __global float *input, 
    __global float *output, 
    const unsigned int count) 
{ 
    int i = get_global_id(0); 
    if (i < count) 
     output[i] = input[i] * input[i]; 
} 

इस उदाहरण आसानी से कुछ पता चलता है कि कैसे स्थानीय स्मृति का उपयोग करते हैं, किसी अन्य साधारण उदाहरण क्या करेंगे बनाने के लिए में परिवर्तित नहीं किया जा सकता है: यहाँ मूल कर्नेल स्रोत है।

उत्तर

30

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

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

__kernel square(
    __global float *input, 
    __global float *output, 
    __local float *temp, 
    const unsigned int count) 
{ 
    int gtid = get_global_id(0); 
    int ltid = get_local_id(0); 
    if (gtid < count) 
    { 
     temp[ltid] = input[gtid]; 
     // if the threads were reading data from other threads, then we would 
     // want a barrier here to ensure the write completes before the read 
     output[gtid] = temp[ltid] * temp[ltid]; 
    } 
} 
+4

मैंने एनवीआईडीआईए प्रारंभिक सामग्री के माध्यम से पढ़ा है, और मुझे अभी भी उदाहरण बहुत जटिल हैं। मैं अपने पैरों को गीला करने के लिए स्थानीय स्मृति का उपयोग करने के लिए एक uber-सरल 1-आयामी उदाहरण की तलाश में हूं। – splicer

+6

आपके अंतिम संपादन में कोड जोड़ने के लिए धन्यवाद! मुझे लगता है कि आपका कर्नेल काम नहीं कर रहा है .... मैं tempetKernelArg() temp के लिए कैसे उपयोग करूं? क्या मुझे tempreateBuffer() temp के लिए उपयोग करने की आवश्यकता है? इसके अलावा, आपके कर्नेल में कुछ टाइपो हैं: "temp * temp" "temp [ltid] * temp [ltid]" होना चाहिए, और अंतिम पंक्ति से पहले एक बंद ब्रेस डालना चाहिए। – splicer

+0

हिम तेंदुए के तहत सीपीयू पर चल रहा है, मैंने clSetKernelArg (कर्नेल, 2, आकार (cl_float), NULL) की कोशिश की; लेकिन यह दुर्घटनाग्रस्त हो जाता है। कोई विचार? – splicer

27

स्थानीय स्मृति का आकार स्थिर होने पर ऐसा करने की एक और संभावना है। कर्नेल पैरामीटर सूची में एक सूचक का उपयोग कर के बिना, स्थानीय बफर बस इसे __local की घोषणा के द्वारा कर्नेल के भीतर घोषित किया जा सकता:

__local float localBuffer[1024]; 

यह कम clSetKernelArg कॉल की वजह से कोड निकाल देता है।

+0

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

4

ओपनसीएल स्थानीय मेमोरी में वर्क ग्रुप में सभी कार्य आइटमों में डेटा साझा करने के लिए है। और स्थानीय स्मृति डेटा का उपयोग करने से पहले इसे आमतौर पर बाधा कॉल करने की आवश्यकता होती है (उदाहरण के लिए, एक कार्य आइटम अन्य कार्य वस्तुओं द्वारा लिखे गए स्थानीय मेमोरी डेटा को पढ़ना चाहता है)। हार्डवेयर में बैरियर महंगा है। ध्यान रखें, बार-बार डेटा पढ़ने/लिखने के लिए स्थानीय स्मृति का उपयोग किया जाना चाहिए। जितना संभव हो सके बैंक संघर्ष से बचा जाना चाहिए।

यदि आप स्थानीय स्मृति से सावधान नहीं हैं, तो आप वैश्विक स्मृति का उपयोग करने से कुछ समय के साथ खराब प्रदर्शन के साथ समाप्त हो सकते हैं।

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