เธรดมีการจัดการที่จะดำเนินการโดย GPU อย่างไร?
เธรดมีการจัดการที่จะดำเนินการโดย GPU อย่างไร?
คำตอบ:
ตัวอย่างเช่นหากอุปกรณ์ GPU มีหน่วยประมวลผลหลายตัว 4 หน่วยและพวกเขาสามารถเรียกใช้ 768 เธรดแต่ละรายการ: จากนั้นในช่วงเวลาที่กำหนดไม่เกิน 4 * 768 เธรดจะทำงานแบบขนานจริง ๆ (หากคุณวางแผนเธรดเพิ่มเติมพวกเขาจะรอ ตาของพวกเขา)
กระทู้ถูกจัดระเบียบในบล็อก บล็อกถูกดำเนินการโดยหน่วยประมวลผลหลายตัว กระทู้ของบล็อกสามารถระบุ (ดัชนี) โดยใช้ 1Dimension (x), 2 มิติ (x, y) หรือดัชนี 3Dim (x, y, z) แต่ในทุกกรณี x y z <= 768 สำหรับตัวอย่างของเรา (ข้อ จำกัด อื่น ๆ ใช้ ถึง x, y, z, ดูคำแนะนำและความสามารถของอุปกรณ์ของคุณ)
เห็นได้ชัดว่าถ้าคุณต้องการมากกว่า 4 * 768 เธรดที่คุณต้องการมากกว่า 4 บล็อก บล็อกอาจถูกจัดทำดัชนีด้วย 1D, 2D หรือ 3D มีคิวของบล็อกรอการเข้าสู่ GPU (เนื่องจากในตัวอย่างของเรา GPU มีมัลติโปรเซสเซอร์ 4 ตัวและดำเนินการพร้อมกัน 4 บล็อกเท่านั้น)
สมมติว่าเราต้องการเธรดหนึ่งเธรดเพื่อประมวลผลหนึ่งพิกเซล (i, j)
เราสามารถใช้บล็อกจำนวน 64 เธรด จากนั้นเราต้องการบล็อก 512 * 512/64 = 4096 (เพื่อให้มีหัวข้อ 512x512 = 4096 * 64)
เป็นเรื่องปกติที่จะจัดระเบียบ (เพื่อให้การจัดทำดัชนีรูปภาพง่ายขึ้น) เธรดในบล็อก 2 มิติที่มี blockDim = 8 x 8 (64 เธรดต่อบล็อก) ฉันชอบที่จะเรียกมันว่ากระทู้ Perlock
dim3 threadsPerBlock(8, 8); // 64 threads
และ 2D gridDim = 64 x 64 บล็อก (จำเป็นต้องมี 4096 บล็อก) ฉันชอบเรียกมันว่า numBlocks
dim3 numBlocks(imageWidth/threadsPerBlock.x, /* for instance 512/8 = 64*/
imageHeight/threadsPerBlock.y);
เคอร์เนลถูกเปิดใช้งานเช่นนี้:
myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );
ในที่สุด: จะมีบางอย่างเช่น "คิว 4096 บล็อก" ซึ่งบล็อกกำลังรอที่จะกำหนดหนึ่งในมัลติโปรเซสเซอร์ของ GPU เพื่อให้ได้ 64 เธรด
ในเคอร์เนลมีการคำนวณพิกเซล (i, j) โดยเธรดด้วยวิธีนี้:
uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
สมมติว่า 9800GT GPU:
https://www.tutorialspoint.com/cuda/cuda_threads.htm
บล็อกไม่สามารถมีเธรดที่ใช้งานได้มากกว่า 512 ดังนั้น__syncthreads
สามารถซิงโครไนซ์จำนวนเธรดที่ จำกัด ได้เท่านั้น เช่นถ้าคุณดำเนินการต่อไปนี้ด้วย 600 กระทู้:
func1();
__syncthreads();
func2();
__syncthreads();
เคอร์เนลจะต้องรันสองครั้งและลำดับการดำเนินการจะเป็น:
บันทึก:
จุดหลักคือ__syncthreads
การดำเนินการทั้งบล็อกและไม่ซิงโครไนซ์เธรดทั้งหมด
ฉันไม่แน่ใจเกี่ยวกับจำนวนเธรดที่แน่นอนที่__syncthreads
สามารถซิงโครไนซ์ได้เนื่องจากคุณสามารถสร้างบล็อกที่มีเธรดมากกว่า 512 เธรดและให้ warp จัดการการกำหนดเวลา เพื่อความเข้าใจของฉันมันแม่นยำมากขึ้นที่จะพูดว่า: func1 ดำเนินการอย่างน้อยสำหรับ 512 กระทู้แรก
ก่อนที่ฉันจะแก้ไขคำตอบนี้ (ย้อนกลับไปในปี 2010) ฉันวัดว่ามีการซิงโครไนซ์ 14x8x32 เธรดโดยใช้ __syncthreads
หัวข้อที่ถูกใช้ทำข้อมูลให้ตรงกัน
ฉันจะขอบคุณมากถ้ามีคนทดสอบอีกครั้งเพื่อหาข้อมูลที่แม่นยำยิ่งขึ้น
__syncthreads
คือการดำเนินการทั้งบล็อกและความจริงที่ว่าไม่ได้ซิงโครไนซ์เธรดทั้งหมดจริง ๆ เป็นสิ่งที่สร้างความรำคาญให้กับผู้เรียน CUDA ดังนั้นฉันจึงอัปเดตคำตอบตามข้อมูลที่คุณให้ไว้ ฉันซาบซึ้งจริงๆ