खोज…


परिचय

ओपनसीएल का उपयोग करने से पहले, किसी को इसका उपयोग करने के लिए अपना कोड सेट करना होगा। यह विषय इस बात पर ध्यान केंद्रित करता है कि आप अपनी परियोजना में कैसे खुलें और चलें और एक बुनियादी कर्नेल को निष्पादित करें। उदाहरण C # रैपर OpenCL.NET पर आधारित हैं, लेकिन जैसा कि रैपर ने OpenCL में कोई अमूर्त नहीं जोड़ा है, कोड शायद C / C ++ aswell पर बहुत कम परिवर्तनों के साथ चलेगा।

C # में कॉल निम्नानुसार दिख सकती है: 'Cl.GetPlatformIDs'। C-Style OpenCL Api के लिए आप 'clGetPlatformIDs' कहेंगे और C ++ स्टाइल वन 'cl :: GetPlatformIDs' के लिए

टिप्पणियों

  • एनवीडिया, एएमडी और इंटेल में ओपनसीएल के कुछ अलग कार्यान्वयन हैं लेकिन ज्ञात अंतर कोष्ठक की आवश्यकताओं और निहित कलाकारों तक सीमित हैं। कभी-कभी एक विधि के लिए सही अधिभार का पता लगाने की कोशिश करते समय एनवीडिया आपके कर्नेल को क्रैश कर देगा। इस मामले में यह GPU की सहायता के लिए एक स्पष्ट कलाकारों की पेशकश करने में मदद करता है। रनटाइम-संकलित गुठली के लिए समस्या देखी गई थी।

  • इस विषय में उपयोग किए गए कॉल के बारे में अधिक जानकारी प्राप्त करने के लिए, यह 'OpenCL' नाम के फंक्शन नाम के बाद गूगल के लिए पर्याप्त है। ख्रोनोस समूह के पास अपनी वेबसाइट पर उपलब्ध सभी मापदंडों और डेटाटिप्स पर एक पूर्ण प्रलेखन है।

लक्ष्य डिवाइस को प्रारंभ करना

OpenCL कर्नेल या तो GPU या CPU पर निष्पादित किया जा सकता है। यह फ़ॉलबैक समाधानों की अनुमति देता है, जहां ग्राहक के पास एक बहुत पुरानी प्रणाली हो सकती है। प्रोग्रामर सीपीयू या जीपीयू को अपनी कार्यक्षमता को सीमित करने का विकल्प भी चुन सकता है।

OpenCL का उपयोग शुरू करने के लिए, आपको एक 'संदर्भ' और 'डिवाइस' की आवश्यकता होगी। दोनों OpenCL API (जिसे cl :: Context or clContext & ~ Device के रूप में भी जाना जाता है) द्वारा परिभाषित संरचनाएं हैं और उपयोग किए गए लक्ष्य प्रोसेसर को परिभाषित करते हैं।

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

संदर्भ स्मृति, कमांड कतार, विभिन्न गुठली और कार्यक्रमों का प्रबंधन करता है। एक संदर्भ या तो एक उपकरण तक सीमित हो सकता है, लेकिन कई उपकरणों को भी संदर्भित करता है।

हम कोडिंग शुरू करने से पहले एक त्वरित एपीआई नोट: ओपनसीएल के लगभग हर कॉल आपको एक त्रुटि मूल्य देता है, या तो रिटर्न वैल्यू के रूप में या रिफ-वैल्यू (सी में सूचक) के माध्यम से। अब शुरू करते हैं।

ErrorCode err;
var platforms = Cl.GetPlatformIDs(out err);
if(!CheckError(err, "Cl.GetPlatformIDs")) return;
foreach (var platform in platforms) {
    foreach (var device in Cl.GetDeviceIDs(platform, DeviceType.Gpu, out err)) {
        if(!CheckError(err, "Cl.GetDeviceIDs")) continue;
        [...]
    }
}

यह कोड स्निपेट सिस्टम पर उपलब्ध सभी GPU उपकरणों पर सवाल उठाता है। अब आप उन्हें एक सूची में जोड़ सकते हैं या पहले मैच से सीधे अपना संदर्भ शुरू कर सकते हैं। 'CheckError (...)' फ़ंक्शन एक साधारण उपयोगिता है, जो यह जाँचता है कि त्रुटि कोड में सफलता-मूल्य है या एक अलग है और आपको कुछ लॉगिंग की पेशकश कर सकता है। एक अलग समारोह या मैक्रो का उपयोग करने की सिफारिश की जाती है, क्योंकि आप इसे बहुत कुछ कहेंगे।

ErrorCode सिर्फ C # के लिए डेटाटाइप cl_int पर एक एनम है, C / C ++ यहां दिए गए पूर्वनिर्धारित त्रुटि स्थिरांक के साथ int मान की तुलना कर सकता है: https://www.khronos.org/registry/OpenCL/sdh1/docs/man/ एक्सएचटीएमएल / errors.html

आप यह भी जांचना चाहेंगे कि क्या डिवाइस सभी आवश्यक सुविधाओं का समर्थन करता है, अन्यथा आपकी गुठली रनटाइम पर दुर्घटनाग्रस्त हो सकती है। आप डिवाइस की क्षमता के साथ क्वेरी कर सकते हैं

Cl.GetDeviceInfo(_device, DeviceInfo.ImageSupport, out err)

यह उदाहरण डिवाइस से पूछता है कि क्या यह छवि कार्यों को निष्पादित कर सकता है। अगले और अंतिम चरण के लिए हमें एकत्रित उपकरणों से अपने संदर्भ का निर्माण करना होगा।

_context = Cl.CreateContext(null, 1, new[] { _device }, ContextNotify, IntPtr.Zero, out err);

कुछ सामान यहां चल रहा है। C / C ++ लोगों के लिए, IntPtr C # में एक सूचक पता है। मैं यहां महत्वपूर्ण हिस्सों पर ध्यान केंद्रित करूंगा।

  • दूसरा पैरामीटर उन उपकरणों की संख्या को परिभाषित करता है जिन्हें आप उपयोग करना चाहते हैं
  • तीसरा पैरामीटर उन उपकरणों की एक सरणी है (या C / C ++ में एक सूचक)
  • और तीसरा पैरामीटर कॉलबैक फ़ंक्शन के लिए एक फ़ंक्शन पॉइंटर है। जब भी त्रुटि संदर्भ के अंदर होती है तो इस फ़ंक्शन का उपयोग किया जाएगा।

फ़्यूचर उपयोग के लिए, आपको अपने उपयोग किए गए उपकरणों और संदर्भ को कहीं न कहीं संरक्षित करने की आवश्यकता होगी।

जब आप अपनी सभी OpenCL बातचीत समाप्त कर लेते हैं, तो आपको संदर्भ को फिर से जारी करना होगा

Cl.ReleaseContext(_context);

अपने कर्नेल को संकलित करना

लक्ष्य डिवाइस पर रनटाइम पर गुठली संकलित की जा सकती है। ऐसा करने के लिए, आपको जरूरत है

  • कर्नेल स्रोत कोड
  • जिस पर संकलन करने के लिए लक्ष्य डिवाइस
  • लक्ष्य डिवाइस के साथ बनाया गया एक संदर्भ

एक त्वरित शब्दावली अद्यतन: एक कार्यक्रम में गुठली का संग्रह होता है। आप किसी प्रोग्राम को पूर्ण C / C ++ / C # स्रोत फ़ाइल के रूप में सोच सकते हैं, जबकि गुठली उस फ़ाइल के विभिन्न फ़ंक्शन सदस्य हैं।

सबसे पहले आपको अपने सोर्स कोड से एक प्रोग्राम बनाना होगा।

var program = Cl.CreateProgramWithSource(_context, 1, new[] { source }, null, out err);

आप कई स्रोत फ़ाइलों को एक कार्यक्रम में जोड़ सकते हैं और उन्हें एक साथ संकलित कर सकते हैं, जो आपको अलग-अलग फ़ाइलों में गुठली रखने और उन्हें एक बार में एक साथ संकलित करने की अनुमति देता है।

अगले चरण में आपको अपने लक्ष्य डिवाइस पर प्रोग्राम को संकलित करना होगा।

err = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);

अब यहां थोड़ा कैविएट आता है: त्रुटि कोड आपको केवल यह बताता है कि क्या फ़ंक्शन कॉल स्वयं सफल था लेकिन यह नहीं कि आपका कोड वास्तव में संकलित हुआ था या नहीं। यह सत्यापित करने के लिए, हमें कुछ अतिरिक्त जानकारी की क्वेरी करनी होगी

BuildStatus status;
status = Cl.GetProgramBuildInfo(program, _device, ProgramBuildInfo.Status, out err).CastTo<BuildStatus>();
if (status != BuildStatus.Success) {
    var log = Cl.GetProgramBuildInfo(program, _device, ProgramBuildInfo.Log, out err);
}

C / C ++ लोग अंत में कलाकारों को अनदेखा कर सकते हैं और बस दिए गए पूर्णांक की संगत कंटिन्यू से तुलना कर सकते हैं।

पहला कॉल यह जाँचता है कि क्या हमारा निर्माण वास्तव में सफल था। यदि नहीं, तो हम एक लॉग को वापस ले सकते हैं और ठीक से देख सकते हैं कि चीजें कहां गलत हुईं। विभिन्न प्लेटफार्मों के बारे में कुछ सामान्य पिटफल्स के लिए टिप्पणी देखें।

एक बार प्रोग्राम बन जाने के बाद, आपको अपने अलग-अलग कर्नेल को संकलित प्रोग्राम से बाहर निकालने की आवश्यकता होती है। ऐसा करने के लिए आप अपनी गुठली बनाते हैं

_kernel = Cl.CreateKernel(_program, kernel, out err);

जहाँ 'कर्नेल' कर्नेल नाम का एक स्ट्रिंग है। जब आप अपने कर्नेल के साथ समाप्त हो जाते हैं, तो आपको इसे जारी करने की आवश्यकता होती है

Cl.ReleaseKernel(_kernel);

एक कमांड कतार बनाना

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

एक कतार बनाना बहुत सीधा है:

_queue = Cl.CreateCommandQueue(_context, _device, CommandQueueProperties.None, out err);

आपकी कमांड कतार के साथ मूल इंटरैक्शन आपके द्वारा किए जाने वाले विभिन्न ऑपरेशनों को सम्‍मिलित करना है, जैसे अपने डिवाइस से डेटा कॉपी करें और कर्नेल लॉन्च करें।

जब आप कमांड कतार का उपयोग करके समाप्त कर लेते हैं, तो आपको कॉल के साथ कतार जारी करने की आवश्यकता होती है

Cl.ReleaseCommandQueue(_queue);

कर्नेल को निष्पादित करना

तो अब हम असली सामान के नीचे आते हैं, समानांतर डिवाइस पर अपनी गुठली को मारते हैं। कृपया कर्नेल डिस्पैचिंग को पूरी तरह से समझने के लिए हार्डवेयर बेसिक्स के बारे में पढ़ें।

पहले आपको कर्नेल को वास्तव में कॉल करने से पहले कर्नेल तर्क सेट करने की आवश्यकता होगी। इसके माध्यम से किया जाता है

err = Cl.SetKernelArg(_kernel, $argumentIndex, $argument);

यदि आप कर्नेल लॉन्च करने से पहले हर तर्क सेट नहीं करते हैं, तो कर्नेल विफल हो जाएगा।

इससे पहले कि हम वास्तव में अपना कर्नेल लॉन्च करें, हमें 'वैश्विक कार्य आकार' और 'स्थानीय कार्य आकार' की गणना करने की आवश्यकता है।

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

काम का आकार या तो एक आयामी, दो आयामी या तीन आयामी हो सकता है। आप कितने आयाम चाहते हैं, इस पर चुनाव पूरी तरह से आप पर निर्भर है और आप अपने एल्गोरिथ्म को सबसे उपयुक्त मानते हैं।

अब जब हमने अपने काम के आकार पर फैसला किया है तो हम कर्नेल कह सकते हैं।

Event clevent;
err = Cl.EnqueueNDRangeKernel(_queue, _kernel, $dimensions, null, $globalWorkSize, $localWorkSize, 0, null, out clevent);

$ आयाम हमारे वांछित संख्या आयामों को परिभाषित करते हैं, $ GlobalWorkSize वैश्विक कार्य आकार के साथ $ आयामों की एक सरणी है और $ LocalWorkSize के लिए समान है। अंतिम तर्क आपको एक वस्तु देता है जो आपके वर्तमान में निष्पादित कर्नेल का प्रतिनिधित्व करता है।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow