मैं अपने AMD Radeon HD 7800 श्रृंखला GPU के साथ उपयोग के लिए एक OpenCL कार्यक्रम लिख रहा हूं। AMD के OpenCL प्रोग्रामिंग गाइड के अनुसार , GPU की इस पीढ़ी की दो हार्डवेयर कतारें हैं जो अतुल्यकालिक रूप से काम कर सकती हैं।
5.5.6 कमांड कतार
दक्षिणी द्वीप समूह और बाद के लिए, उपकरण कम से कम दो हार्डवेयर कंप्यूट कतारों का समर्थन करते हैं। यह एक आवेदन को अतुल्यकालिक सबमिशन और संभवतः निष्पादन के लिए दो कमांड क्यू के साथ छोटे प्रेषण के थ्रूपुट को बढ़ाने की अनुमति देता है। हार्डवेयर गणना कतारों को निम्नलिखित क्रम में चुना जाता है: पहली कतार = यहां तक कि ओसीएल कमांड कतार, दूसरी कतार = विषम ओसीएल कतार।
ऐसा करने के लिए, मैंने GPU को डेटा खिलाने के लिए दो अलग OpenCL कमांड कतारें बनाई हैं। मोटे तौर पर, होस्ट थ्रेड पर चलने वाला प्रोग्राम कुछ इस तरह दिखता है:
static const int kNumQueues = 2;
cl_command_queue default_queue;
cl_command_queue work_queue[kNumQueues];
static const int N = 256;
cl_mem gl_buffers[N];
cl_event finish_events[N];
clEnqueueAcquireGLObjects(default_queue, gl_buffers, N);
int queue_idx = 0;
for (int i = 0; i < N; ++i) {
cl_command_queue queue = work_queue[queue_idx];
cl_mem src = clCreateBuffer(CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ...);
// Enqueue a few kernels
cl_mem tmp1 = clCreateBuffer(CL_READ_WRITE);
clEnqueueNDRangeKernel(kernel1, queue, src, tmp1);
clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp1);
cl_mem tmp2 = clCreateBuffer(CL_READ_WRITE);
clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp2);
clEnqueueNDRangeKernel(kernel3, queue, tmp2, gl_buffer[i], finish_events + i);
queue_idx = (queue_idx + 1) % kNumQueues;
}
clEnqueueReleaseGLObjects(default_queue, gl_buffers, N);
clWaitForEvents(N, finish_events);
kNumQueues = 1
इस एप्लिकेशन के साथ , यह बहुत अधिक काम करता है: यह पूरी तरह से एक ही कमांड कतार में काम करता है जो कि पूरे समय में व्यस्त होने के कारण GPU के साथ पूरा होता है। मैं CodeXL प्रोफाइलर के आउटपुट को देखकर इसे देख सकता हूं:
हालांकि, जब मैं सेट करता हूं, तो मैं kNumQueues = 2
एक ही बात होने की उम्मीद करता हूं लेकिन काम के साथ समान रूप से दो कतारों में विभाजित हो जाता है। यदि कुछ भी हो, तो मुझे उम्मीद है कि प्रत्येक कतार में एक कतार के समान व्यक्तिगत रूप से एक ही विशेषता होगी: कि यह क्रमिक रूप से तब तक काम करना शुरू करता है जब तक कि सब कुछ नहीं हो जाता। हालांकि, दो कतारों का उपयोग करते समय, मैं देख सकता हूं कि सभी कार्य दो हार्डवेयर कतारों में विभाजित नहीं हैं:
GPU के काम की शुरुआत में, कतारें कुछ गुठली को अतुल्य रूप से चलाने का प्रबंधन करती हैं, हालांकि ऐसा लगता है कि न तो कभी पूरी तरह से हार्डवेयर कतारों पर कब्जा होता है (जब तक कि मेरी समझ गलत नहीं है)। GPU के काम के अंत के पास, ऐसा लगता है कि कतारें अनुक्रमिक रूप से केवल एक हार्डवेयर कतार में काम कर रही हैं, लेकिन कई बार ऐसा भी होता है कि कोई गुठली नहीं चल रही है। क्या देता है? क्या मुझे कुछ बुनियादी गलतफहमी है कि रनटाइम को कैसे माना जाता है?
मेरे पास कुछ सिद्धांत हैं कि ऐसा क्यों हो रहा है:
इंटरसेप्टर
clCreateBuffer
कॉल जीपीयू को एक साझा मेमोरी पूल से डिवाइस संसाधनों को समकालिक रूप से आवंटित करने के लिए मजबूर कर रही है जो व्यक्तिगत कर्नेल के निष्पादन को रोकती है।अंतर्निहित ओपनसीएल कार्यान्वयन भौतिक कतारों के लिए तार्किक कतारों को मैप नहीं करता है, और केवल यह तय करता है कि रनटाइम पर वस्तुओं को कहां रखा जाए।
क्योंकि मैं GL ऑब्जेक्ट्स का उपयोग कर रहा हूं, इसलिए GPU को लिखने के दौरान विशेष रूप से आवंटित मेमोरी तक पहुंच को सिंक्रनाइज़ करने की आवश्यकता होती है।
क्या इनमें से कोई भी धारणा सत्य है? क्या किसी को पता है कि दो-कतार परिदृश्य में प्रतीक्षा करने के लिए GPU क्या हो सकता है? किसी भी और सभी अंतर्दृष्टि की सराहना की जाएगी!