ฉันกำลังเขียนโปรแกรม OpenCL เพื่อใช้กับ GPU AMD Radeon HD 7800 series ของฉัน ตามคู่มือการเขียนโปรแกรม OpenCLของ AMD รุ่น GPU นี้มีคิวฮาร์ดแวร์สองคิวที่สามารถทำงานแบบอะซิงโครนัสได้
5.5.6 คิวคำสั่ง
สำหรับหมู่เกาะเซาท์เทิร์นและหลังจากนั้นอุปกรณ์ต่าง ๆ สนับสนุนฮาร์ดแวร์คำนวณคิวอย่างน้อยสองรายการ ที่ช่วยให้แอปพลิเคชันเพิ่มปริมาณงานของการแจกจ่ายเล็กน้อยด้วยคิวคำสั่งสองรายการสำหรับการส่งแบบอะซิงโครนัสและการดำเนินการที่เป็นไปได้ คิวการคำนวณฮาร์ดแวร์ถูกเลือกตามลำดับต่อไปนี้: first queue = แม้กระทั่งคำสั่ง OCL, คิวที่สอง = คิว OCL แปลก ๆ
ในการทำเช่นนี้ฉันได้สร้างคิวคำสั่ง OpenCL สองชุดแยกกันเพื่อป้อนข้อมูลไปยัง GPU โดยประมาณโปรแกรมที่ทำงานบนโฮสต์เธรดจะมีลักษณะดังนี้:
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 Profiler:
อย่างไรก็ตามเมื่อฉันตั้งค่าkNumQueues = 2
ฉันคาดหวังว่าสิ่งเดียวกันจะเกิดขึ้น แต่ด้วยการแบ่งงานอย่างเท่าเทียมกันในสองคิว หากมีสิ่งใดฉันคาดว่าแต่ละคิวจะมีคุณสมบัติเหมือนกันแยกกันเป็นหนึ่งคิว: มันเริ่มทำงานตามลำดับจนกว่าทุกอย่างจะเสร็จสิ้น อย่างไรก็ตามเมื่อใช้สองคิวฉันเห็นได้ว่าไม่ใช่งานทั้งหมดที่แบ่งเป็นสองฮาร์ดแวร์:
ในช่วงเริ่มต้นของการทำงานของ GPU คิวจะจัดการเพื่อให้เมล็ดบางส่วนทำงานแบบอะซิงโครนัสแม้ว่ามันจะดูเหมือนว่าไม่เคยใช้งานคิวของฮาร์ดแวร์อย่างเต็มที่ ใกล้ถึงจุดสิ้นสุดของงาน GPU ดูเหมือนว่าคิวกำลังเพิ่มงานตามลำดับให้กับหนึ่งในฮาร์ดแวร์คิวเท่านั้น แต่มีบางครั้งที่ไม่มีเคอร์เนลทำงานอยู่ สิ่งที่ช่วยให้? ฉันมีความเข้าใจผิดพื้นฐานเกี่ยวกับการทำงานของ runtime หรือไม่?
ฉันมีทฤษฎีบางอย่างเกี่ยวกับสาเหตุที่เกิดขึ้น:
การ
clCreateBuffer
เรียกสลับสัญญาณนั้นบังคับให้ GPU จัดสรรทรัพยากรอุปกรณ์จากพูลหน่วยความจำที่ใช้ร่วมกันแบบซิงโครนัสซึ่งจะหยุดการทำงานของแต่ละเมล็ดการใช้งาน OpenCL พื้นฐานไม่ได้แมปโลจิคัลคิวกับฟิสิคัลคิวและตัดสินใจเฉพาะตำแหน่งที่วางวัตถุที่รันไทม์
เนื่องจากฉันใช้วัตถุ GL จึงจำเป็นต้องประสานการเข้าถึงหน่วยความจำที่จัดสรรเป็นพิเศษระหว่างการเขียน
สมมติฐานเหล่านี้เป็นจริงหรือไม่? ไม่มีใครรู้ว่าสิ่งใดที่อาจทำให้ GPU ต้องรอในสถานการณ์สองคิว ความเข้าใจใด ๆ และทั้งหมดจะได้รับการชื่นชม!