ความขัดแย้งของธนาคารคืออะไร? (การเขียนโปรแกรม Cuda / OpenCL)


97

ฉันอ่านคู่มือการเขียนโปรแกรมสำหรับ CUDA และ OpenCL แล้วและฉันไม่สามารถเข้าใจได้ว่าความขัดแย้งของธนาคารคืออะไร พวกเขาเพียงแค่ดำน้ำลงไปในวิธีการแก้ปัญหาโดยไม่ต้องลงรายละเอียดในเรื่องนั้น ๆ ใครสามารถช่วยฉันเข้าใจได้ไหม ฉันไม่ต้องการหากความช่วยเหลืออยู่ในบริบทของ CUDA / OpenCL หรือเพียงแค่ความขัดแย้งของธนาคารโดยทั่วไปในวิทยาการคอมพิวเตอร์

คำตอบ:


106

สำหรับ nvidia (และ amd สำหรับเรื่องนั้น) gpus หน่วยความจำในเครื่องจะแบ่งออกเป็น memorybanks แต่ละธนาคารสามารถจัดการกับชุดข้อมูลได้ครั้งละหนึ่งชุดเท่านั้นดังนั้นหาก halfwarp พยายามโหลด / จัดเก็บข้อมูลจาก / ไปยังธนาคารเดียวกันการเข้าถึงจะต้องทำให้เป็นอนุกรม (นี่คือความขัดแย้งของธนาคาร) สำหรับ gt200 gpus มี 16 ธนาคาร (32banks สำหรับ fermi) 16 หรือ 32 ธนาคารสำหรับ AMD gpus (57xx หรือสูงกว่า: 32 ทุกอย่างด้านล่าง: 16)) ซึ่งมีการแทรกสลับด้วยความละเอียด 32 บิต (ดังนั้นไบต์ 0-3 จึงอยู่ใน ธนาคาร 1, 4-7 ในธนาคาร 2, ... , 64-69 ในธนาคาร 1 และอื่น ๆ ) เพื่อให้เห็นภาพได้ดีขึ้นโดยทั่วไปจะมีลักษณะดังนี้:

Bank    |      1      |      2      |      3      |...
Address |  0  1  2  3 |  4  5  6  7 |  8  9 10 11 |...
Address | 64 65 66 67 | 68 69 70 71 | 72 73 74 75 |...
...

ดังนั้นหากแต่ละเธรดใน halfwarp เข้าถึงค่า 32 บิตต่อเนื่องกันจะไม่มีข้อขัดแย้งของธนาคาร ข้อยกเว้นจากกฎนี้ (ทุกเธรดต้องเข้าถึงธนาคารของตัวเอง) คือการออกอากาศ: หากเธรดทั้งหมดเข้าถึงที่อยู่เดียวกันค่าจะถูกอ่านเพียงครั้งเดียวและออกอากาศไปยังเธรดทั้งหมด (สำหรับ GT200 จะต้องเป็นเธรดทั้งหมดใน halfwarp ที่เข้าถึง ที่อยู่เดียวกัน iirc fermi และ AMD gpus สามารถทำได้สำหรับเธรดจำนวนเท่าใดก็ได้ที่เข้าถึงค่าเดียวกัน)


3
ขอบคุณมากสำหรับภาพและคำอธิบาย ฉันไม่รู้เกี่ยวกับการออกอากาศและดูเหมือนว่าจะเป็นข้อมูลที่สำคัญ :) ฉันจะตรวจสอบได้อย่างไรว่าการโหลดและการจัดเก็บของฉันไม่ทำให้เกิดความขัดแย้งของธนาคารในหน่วยความจำที่ใช้ร่วมกัน ฉันต้องได้รับรหัสแอสเซมบลีหรือมีวิธีอื่นหรือไม่?
ลักลอบ

3
เนื่องจากความขัดแย้งของธนาคารเกิดขึ้นเป็นครั้งคราวซึ่งจะถูกกำหนดที่รันไทม์ (หมายความว่าคอมไพเลอร์ไม่ทราบเกี่ยวกับเรื่องนี้หลังจากสร้างที่อยู่ส่วนใหญ่ทั้งหมดในรันไทม์) การรับเวอร์ชันที่คอมไพล์จะไม่ช่วยอะไรมาก โดยปกติฉันจะทำแบบนี้ด้วยวิธีเก่า ๆ ฉันใช้ปากกาและกระดาษแล้วเริ่มคิดว่ารหัสของฉันเก็บไว้ที่ไหน โดยรวมแล้วกฎที่ควบคุมการเกิดความขัดแย้งของธนาคารนั้นไม่ได้ซับซ้อนขนาดนั้น มิฉะนั้นคุณสามารถใช้ nvidia OpenCL profiler (ควรมาพร้อมกับ sdk, iirc) ฉันคิดว่ามันมีตัวนับสำหรับ warp serializes
Grizzly

1
ขอขอบคุณที่ชี้ให้เห็นว่าวิปริตเป็นอนุกรม หนึ่งในไฟล์ข้อความ readme ที่มาพร้อมกับโปรแกรมสร้างโปรไฟล์การประมวลผลกล่าวว่า
ลักลอบนำเข้า

1
ใช่ขอโทษความคิดเห็นด้านบนด้วยเหตุผลบางประการฉันไม่สามารถแก้ไขซ้ำได้ อย่างไรก็ตามฉันพบสิ่งนี้ใน Readme ของโปรแกรมคำนวณของโพรไฟล์ "warp_serialize: จำนวนเธรดวาร์ปที่เรียงลำดับตามความขัดแย้งที่อยู่กับหน่วยความจำที่ใช้ร่วมกันหรือหน่วยความจำคงที่" นี่เป็นเรื่องดีที่ฉันสามารถดูได้อย่างง่ายดายว่ามีข้อขัดแย้งเพียงแค่ดูที่เอาต์พุตของโปรไฟล์ คุณจะทราบได้อย่างไรว่ามีความขัดแย้งของธนาคารบนปากกาและกระดาษ คุณได้เรียนรู้จากตัวอย่างหรือแบบฝึกหัดหรือไม่?
ลักลอบ

1
ดังที่ฉันได้กล่าวไว้ว่าการทำแผนที่จากที่อยู่ไปยังธนาคารนั้นค่อนข้างง่ายดังนั้นจึงไม่ยากที่จะระบุว่าการเข้าถึงใดไปที่ธนาคารใดและหากมีความขัดแย้งกับธนาคาร กระดาษนี้มีไว้สำหรับรูปแบบการเข้าถึงความขัดแย้งเท่านั้นโดยที่ฉันไม่สามารถทำได้หากไม่มี
Grizzly

13

หน่วยความจำแบบแบ่งใช้ที่สามารถเข้าถึงแบบขนานแบ่งออกเป็นโมดูล (เรียกอีกอย่างว่าธนาคาร) หากตำแหน่งหน่วยความจำสองแห่ง (ที่อยู่) เกิดขึ้นในธนาคารเดียวกันคุณจะได้รับความขัดแย้งของธนาคารในระหว่างที่การเข้าถึงดำเนินการแบบเป็นชุดทำให้สูญเสียข้อดีของการเข้าถึงแบบขนาน


สิ่งนี้เกี่ยวข้องกับเวลาที่ half-warp ต้องการจัดเก็บหรือโหลดหน่วยความจำหรือไม่? 16 เธรดจะพยายามทำธุรกรรมหน่วยความจำดังนั้นการเข้าถึงธนาคารเดียวกันที่มีเธรดมากกว่าหนึ่งเธรดทำให้เกิดการประมวลผลแบบอนุกรม? นอกจากนี้จะแน่ใจได้อย่างไรว่าคุณไม่ได้จัดเก็บ / โหลดข้อมูลในธนาคารเดียวกัน
ลักลอบแพนเค้ก

10

กล่าวง่ายๆคือความขัดแย้งของธนาคารเป็นกรณีที่รูปแบบการเข้าถึงหน่วยความจำใด ๆ ล้มเหลวในการแจกจ่าย IO ข้ามธนาคารที่มีอยู่ในระบบหน่วยความจำ ตัวอย่างต่อไปนี้อธิบายแนวคิดอย่างละเอียด: -

สมมติว่าเรามีอาร์เรย์ 512x512 สองมิติและ DRAM หรือระบบหน่วยความจำของเรามี 512 ธนาคารอยู่ในนั้น ตามค่าเริ่มต้นข้อมูลอาร์เรย์จะถูกจัดวางในลักษณะที่ arr [0] [0] ไปที่ธนาคาร 0, arr [0] [1] ไปที่ธนาคาร 1, arr [0] [2] ไปยังธนาคาร 2 .... arr [0] [511] ไปที่ธนาคาร 511 หากต้องการสรุป arr [x] [y] ให้ใช้หมายเลขธนาคาร y ตอนนี้โค้ดบางส่วน (ดังแสดงด้านล่าง) เริ่มเข้าถึงข้อมูลในคอลัมน์หลักเช่น การเปลี่ยน x ในขณะที่ทำให้ค่าคงที่ของ y ผลสุดท้ายก็คือการเข้าถึงหน่วยความจำที่ต่อเนื่องกันทั้งหมดจะเข้าสู่ธนาคารเดียวกันดังนั้นความขัดแย้งของธนาคาร

int arr[512][512];
  for ( j = 0; j < 512; j++ ) // outer loop
    for ( i = 0; i < 512; i++ ) // inner loop
       arr[i][j] = 2 * arr[i][j]; // column major processing

โดยทั่วไปแล้วปัญหาดังกล่าวจะหลีกเลี่ยงได้โดยคอมไพเลอร์โดยการบัฟเฟอร์อาร์เรย์หรือใช้จำนวนเฉพาะขององค์ประกอบในอาร์เรย์


8

(CUDA Bank Conflict) หวังว่านี่จะช่วยได้ .. นี่เป็นคำอธิบายที่ดีมาก ...

http://www.youtube.com/watch?v=CZgM3DEBplE


1
โปรดทราบว่าคำตอบแบบลิงก์เท่านั้นไม่ได้รับการสนับสนุนคำตอบ SO ควรเป็นจุดสิ้นสุดของการค้นหาวิธีแก้ปัญหา (เทียบกับการหยุดการอ้างอิงอื่น ๆ ซึ่งมักจะค้างเมื่อเวลาผ่านไป) โปรดพิจารณาเพิ่มเรื่องย่อแบบสแตนด์อโลนที่นี่โดยเก็บลิงก์ไว้เป็นข้อมูลอ้างอิง
kleopatra

โปรดอธิบายรายละเอียดผ่านลิงก์เพื่อพยายามช่วยเหลือ OP ให้ดียิ่งขึ้น
Peter Foti

1
วิดีโอนี้มีประโยชน์จริงๆ! และฉันไม่รู้ว่าทำไมถึงโหวต! เป็นอินพุตที่ดีมาก! +1
Gabriel

1

http://en.wikipedia.org/wiki/Memory_bank
และ http://mprc.pku.cn/mentors/training/ISCAreading/1989/p380-weiss/p380-weiss.pdf

จากหน้านี้คุณจะพบรายละเอียดเกี่ยวกับธนาคารหน่วยความจำ แต่มันแตกต่างจากที่ @Grizzly พูดเล็กน้อย ในหน้านี้ธนาคารจะเป็นแบบนี้

ธนาคาร 1 2 3

ที่อยู่ | 0, 3, 6 ... | | 1, 4, 7 ... | | 2, 5,8 ... |

หวังว่านี่จะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.