আমি আমার এএমডি রেডিয়ন এইচডি 7800 সিরিজের জিপিইউ ব্যবহারের জন্য একটি ওপেনসিএল প্রোগ্রাম লিখছি। এএমডির ওপেনসিএল প্রোগ্রামিং গাইড অনুসারে , জিপিইউর এই প্রজন্মের দুটি হার্ডওয়্যার সারি রয়েছে যা অবিচ্ছিন্নভাবে পরিচালনা করতে পারে।
5.5.6 কমান্ড সারি
দক্ষিণ দ্বীপপুঞ্জ এবং তারপরে, ডিভাইসগুলি কমপক্ষে দুটি হার্ডওয়্যার গণনা সারি সমর্থন করে। এটি একটি অ্যাপ্লিকেশনটিকে অ্যাসিঙ্ক্রোনাস জমা দেওয়ার জন্য এবং সম্ভবত কার্যকর করার জন্য দুটি কমান্ড সারি সহ ছোট প্রেরণের মাধ্যমে আউটপুট বৃদ্ধি করতে দেয়। হার্ডওয়্যার গণনা সারিগুলি নিম্নলিখিত ক্রমে নির্বাচিত হয়েছে: প্রথম সারি = এমনকি ওসিএল কমান্ড সারি, দ্বিতীয় সারি = বিজোড় ওসিএল সারি।
এটি করার জন্য, আমি জিপিইউতে ডেটা ফিড করতে দুটি পৃথক ওপেনসিএল কমান্ড সারি তৈরি করেছি। মোটামুটিভাবে, হোস্ট থ্রেডে চলমান প্রোগ্রামটি এরকম কিছু দেখাচ্ছে:
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
, এই অ্যাপ্লিকেশনটি প্রায়শই উদ্দেশ্য হিসাবে কাজ করে: এটি জিপিইউর পুরো সময় ব্যস্ত থাকার সাথে সাথে সম্পূর্ণরূপে চলে এমন একক কমান্ড কাতারে সমস্ত কাজ সংগ্রহ করে। আমি কোডএক্সএল প্রোফাইলারের আউটপুট দেখে এটি দেখতে সক্ষম হয়েছি:
যাইহোক, যখন আমি সেট করি kNumQueues = 2
, আমি একই জিনিসটি আশা করি তবে কাজটি সমানভাবে দুটি কাতারে বিভক্ত হয়ে। এটি ক্রমানুসারে কাজ শুরু না হওয়া পর্যন্ত সব কাজ হয়: তোমার কিছু হয়ে গেলে আমি প্রতিটি কিউ এক কিউ যেমন পৃথকভাবে একই বৈশিষ্ট্য থাকে আশা। যাইহোক, দুটি সারি ব্যবহার করার সময়, আমি দেখতে পাচ্ছি যে সমস্ত কাজ দুটি হার্ডওয়্যার সারিতে বিভক্ত নয়:
জিপিইউর কাজের শুরুতে, সারিগুলি কয়েকটি কার্নেলগুলি অবিচ্ছিন্নভাবে পরিচালনা করতে পারে, যদিও এটি মনে হয় না যে হার্ডওয়ারের সারিগুলি কখনও পুরোপুরি দখল করে না (যদি না আমার বোঝার ভুল হয়)। জিপিইউ কাজের সমাপ্তির কাছাকাছি মনে হচ্ছে সারিগুলি কেবল হার্ডওয়্যার সারির মধ্যে একটিতে ক্রমানুসারে কাজ যোগ করছে, তবে এমনও অনেক সময় আছে যে কোনও কার্নেল চলছে না। কি দেয়? রানটাইমটি আচরণ করার কথা কী তা সম্পর্কে আমার কিছু মৌলিক ভুল বোঝাবুঝি আছে?
কেন এটি হচ্ছে তা নিয়ে আমার কয়েকটি তত্ত্ব রয়েছে:
ছেদকৃত
clCreateBuffer
কলগুলি জিপিইউকে একটি ভাগ করা মেমরি পুল থেকে সিঙ্ক্রোনালি ডিভাইস সংস্থানগুলি বরাদ্দ করতে বাধ্য করছে যা পৃথক কার্নেলের কার্য সম্পাদন বন্ধ করে দেয়।অন্তর্নিহিত ওপেনসিএল বাস্তবায়ন শারীরিক সারিগুলিতে যৌক্তিক সারিগুলি মানচিত্র করে না এবং রানটাইমের সময় কোথায় অবজেক্ট স্থাপন করা উচিত তা স্থির করে।
যেহেতু আমি জিএল অবজেক্ট ব্যবহার করছি, জিপিইউকে লেখার সময় বিশেষভাবে বরাদ্দকৃত মেমরির অ্যাক্সেস সিঙ্ক্রোনাইজ করতে হবে।
এর মধ্যে কোন অনুমান সত্য? কেউ কি জানেন যে কী কারণে জিপিইউ দ্বি-সারির দৃশ্যে অপেক্ষা করতে পারে? যে কোনও এবং সমস্ত অন্তর্দৃষ্টি প্রশংসা করা হবে!