ก่อนอื่นคุณควรตระหนักถึงความจริงที่ว่า CUDA จะไม่ทำให้การคำนวณเร็วขึ้นโดยอัตโนมัติ ในมือข้างหนึ่งเพราะการเขียนโปรแกรม GPU เป็นศิลปะและมันสามารถมากที่ท้าทายมากที่จะได้รับมันขวา ในทางกลับกันเนื่องจาก GPU นั้นเหมาะสำหรับการคำนวณบางประเภทเท่านั้น
สิ่งนี้อาจฟังดูสับสนเนื่องจากคุณสามารถคำนวณอะไรก็ได้บน GPU จุดสำคัญคือแน่นอนว่าคุณจะประสบความสำเร็จในการเร่งความเร็วหรือไม่ การจัดหมวดหมู่ที่สำคัญที่สุดคือว่านี่เป็นปัญหางานคู่ขนานหรือข้อมูลแบบขนาน คนแรกอ้างถึงการพูดอย่างคร่าว ๆ ถึงปัญหาที่หลายกระทู้กำลังทำงานของตนเองไม่มากก็น้อย ส่วนที่สองหมายถึงปัญหาที่เธรดจำนวนมากกำลังทำสิ่งเดียวกัน - แต่ในส่วนต่าง ๆ ของข้อมูล
หลังเป็นปัญหาที่ GPUs ทำได้ดี: มีหลายคอร์และคอร์ทุกตัวทำเหมือนกัน แต่ทำงานในส่วนต่าง ๆ ของข้อมูลอินพุท
คุณพูดถึงว่าคุณมี "คณิตศาสตร์ง่าย ๆ แต่มีข้อมูลจำนวนมาก" แม้ว่าสิ่งนี้อาจฟังดูเป็นปัญหาที่ขนานกันอย่างสมบูรณ์แบบของข้อมูลและดังนั้นจึงเหมาะสำหรับ GPU แต่ก็มีอีกด้านที่ต้องพิจารณา: GPUs มีความรวดเร็วอย่างน่าขันในแง่ของพลังการคำนวณเชิงทฤษฎี (FLOPS, Floating Point Operations Per Second) แต่บ่อยครั้งที่พวกเขาถูกแบนด์วิดท์หน่วยความจำลง
สิ่งนี้นำไปสู่การจำแนกปัญหาอีกประเภทหนึ่ง กล่าวคือไม่ว่าจะเป็นปัญหาที่หน่วยความจำที่ถูกผูกไว้หรือการคำนวณที่ถูกผูกไว้
คนแรกหมายถึงปัญหาที่จำนวนคำสั่งที่ทำสำหรับแต่ละองค์ประกอบข้อมูลต่ำ ตัวอย่างเช่นพิจารณาการเพิ่มเวกเตอร์แบบขนาน: คุณจะต้องอ่านองค์ประกอบข้อมูลสองรายการจากนั้นทำการบวกแบบครั้งเดียวแล้วเขียนผลรวมลงในเวกเตอร์ผลลัพธ์ คุณจะไม่เห็นการเร่งความเร็วเมื่อทำสิ่งนี้กับ GPU เพราะการเพิ่มครั้งเดียวไม่ได้ชดเชยความพยายามในการอ่าน / เขียนหน่วยความจำ
คำศัพท์ที่สอง "ขอบเขตการคำนวณ" หมายถึงปัญหาที่จำนวนคำสั่งนั้นสูงเมื่อเทียบกับจำนวนหน่วยความจำที่อ่าน / เขียน ตัวอย่างเช่นพิจารณาการคูณเมทริกซ์: จำนวนคำสั่งจะเป็น O (n ^ 3) เมื่อ n คือขนาดของเมทริกซ์ ในกรณีนี้เราสามารถคาดหวังได้ว่า GPU จะมีประสิทธิภาพสูงกว่าซีพียูในขนาดเมทริกซ์ที่แน่นอน อีกตัวอย่างหนึ่งคือเมื่อมีการคำนวณตรีโกณมิติเชิงซ้อนจำนวนมาก (ไซน์ / โคไซน์ ฯลฯ ) ในองค์ประกอบข้อมูล "น้อย"
ตามกฎทั่วไป: คุณสามารถสันนิษฐานได้ว่าการอ่าน / เขียนข้อมูลหนึ่งองค์ประกอบจากหน่วยความจำ GPU "หลัก" มีความล่าช้าประมาณ 500 คำสั่ง ....
ดังนั้นจุดสำคัญอีกประการหนึ่งสำหรับประสิทธิภาพของ GPU คือตำแหน่งข้อมูล : หากคุณต้องอ่านหรือเขียนข้อมูล (และในกรณีส่วนใหญ่คุณจะต้อง ;-)) คุณควรตรวจสอบให้แน่ใจว่าข้อมูลนั้นถูกเก็บไว้ใกล้เคียงที่สุด เป็นไปได้ที่จะแกน GPU GPU จึงมีพื้นที่หน่วยความจำบางอย่าง (เรียกว่า "หน่วยความจำท้องถิ่น" หรือ "หน่วยความจำที่ใช้ร่วมกัน") ซึ่งโดยปกติจะมีขนาดเพียงไม่กี่ KB แต่มีประสิทธิภาพโดยเฉพาะอย่างยิ่งสำหรับข้อมูลที่กำลังจะมีส่วนร่วมในการคำนวณ
ดังนั้นเพื่อเน้นสิ่งนี้อีกครั้ง: การเขียนโปรแกรม GPU เป็นศิลปะที่เกี่ยวข้องกับการเขียนโปรแกรมแบบขนานบน CPU จากระยะไกลเท่านั้น สิ่งที่ชอบกระทู้ใน Java มีทั้งหมดเห็นพ้องด้วยโครงสร้างพื้นฐานเช่นThreadPoolExecutors
, ForkJoinPools
ฯลฯ อาจจะให้ความประทับใจที่คุณเพียงแค่ต้องแยกการทำงานของคุณอย่างใดและแจกจ่ายในหมู่โปรเซสเซอร์หลาย บน GPU คุณอาจพบกับความท้าทายในระดับที่ต่ำกว่ามากเช่นการเข้าพักการลงทะเบียนความกดดันการแชร์หน่วยความจำการรวมหน่วยความจำ ... เพื่อชื่อไม่กี่คน
อย่างไรก็ตามเมื่อคุณมีปัญหาข้อมูลแบบขนาน, ขอบเขตการคำนวณเพื่อแก้ไข GPU เป็นวิธีที่จะไป
หมายเหตุทั่วไป: คุณขอเฉพาะ CUDA แต่ฉันขอแนะนำให้คุณดู OpenCL ด้วย มันมีข้อดีหลายประการ ก่อนอื่นมันเป็นมาตรฐานของอุตสาหกรรมที่เปิดอิสระและมีการใช้งาน OpenCL โดย AMD, Apple, Intel และ NVIDIA นอกจากนี้ยังมีการสนับสนุนที่กว้างขวางยิ่งขึ้นสำหรับ OpenCL ในโลก Java กรณีเดียวที่ฉันต้องการชำระ CUDA คือเมื่อคุณต้องการใช้ไลบรารีรันไทม์ CUDA เช่น CUFFT สำหรับ FFT หรือ CUBLAS สำหรับ BLAS (การดำเนินการ Matrix / Vector) แม้ว่าจะมีวิธีการในการจัดหาไลบรารี่ที่คล้ายกันสำหรับ OpenCL แต่ก็ไม่สามารถใช้งานได้โดยตรงจากฝั่ง Java ยกเว้นว่าคุณจะสร้างการเชื่อม JNI ของคุณเองสำหรับไลบรารี่เหล่านี้
นอกจากนี้คุณยังอาจพบว่ามันน่าสนใจที่จะได้ยินว่าในเดือนตุลาคม 2012 กลุ่ม OpenJDK HotSpot เริ่มโครงการ "สุมาตรา" นี้: http://openjdk.java.net/projects/sumatra/ เป้าหมายของโครงการนี้คือการให้การสนับสนุน GPU โดยตรงใน JVM ด้วยการสนับสนุนจาก JIT สถานะปัจจุบันและผลลัพธ์แรกสามารถเห็นได้ในรายชื่อผู้รับจดหมายที่http://mail.openjdk.java.net/mailman/listinfo/sumatra-dev
อย่างไรก็ตามเมื่อไม่นานมานี้ฉันได้รวบรวมทรัพยากรบางอย่างที่เกี่ยวข้องกับ "Java บน GPU" โดยทั่วไป ฉันจะสรุปสิ่งเหล่านี้อีกครั้งโดยไม่เรียงลำดับ
( ข้อจำกัดความรับผิดชอบ : ฉันเป็นผู้เขียนhttp://jcuda.org/และhttp://jocl.org/ )
(Byte) การแปลโค้ดและการสร้างโค้ด OpenCL:
https://github.com/aparapi/aparapi : ไลบรารีโอเพ่นซอร์สที่สร้างและดูแลโดย AMD ในคลาส "เคอร์เนล" พิเศษหนึ่งสามารถแทนที่วิธีการเฉพาะซึ่งควรจะดำเนินการในแบบคู่ขนาน โค้ดไบต์ของวิธีนี้ถูกโหลดเมื่อรันไทม์โดยใช้ตัวอ่าน bytecode ของตัวเอง โค้ดถูกแปลเป็นโค้ด OpenCL ซึ่งจะถูกคอมไพล์โดยใช้คอมไพเลอร์ OpenCL ผลลัพธ์สามารถดำเนินการได้บนอุปกรณ์ OpenCL ซึ่งอาจเป็น GPU หรือ CPU หากการรวบรวมเป็น OpenCL เป็นไปไม่ได้ (หรือไม่มี OpenCL) รหัสจะยังคงถูกดำเนินการแบบขนานโดยใช้กลุ่มเธรด
https://github.com/pcpratts/rootbeer1 : ไลบรารีโอเพ่นซอร์สสำหรับการแปลงส่วนต่าง ๆ ของ Java เป็นโปรแกรม CUDA มันมีอินเทอร์เฟซเฉพาะที่อาจนำไปใช้เพื่อบ่งชี้ว่าคลาสบางอย่างควรดำเนินการบน GPU ตรงกันข้ามกับ Aparapi จะพยายามเรียงลำดับข้อมูล "ที่เกี่ยวข้อง" โดยอัตโนมัติ (นั่นคือส่วนที่เกี่ยวข้องอย่างสมบูรณ์ของกราฟวัตถุ!) ไปสู่การแสดงที่เหมาะสำหรับ GPU
https://code.google.com/archive/p/java-gpu/ : ห้องสมุดสำหรับการแปลโค้ด Java ที่มีคำอธิบายประกอบ (มีข้อ จำกัด บางอย่าง) เป็นรหัส CUDA ซึ่งจะถูกรวบรวมไว้ในไลบรารีที่ประมวลผลโค้ดบน GPU ห้องสมุดได้รับการพัฒนาในบริบทของวิทยานิพนธ์ระดับปริญญาเอกซึ่งมีข้อมูลพื้นฐานที่ลึกซึ้งเกี่ยวกับกระบวนการแปล
https://github.com/ochafik/ScalaCL : การผูกสกาล่าสำหรับ OpenCL อนุญาตให้ประมวลผลคอลเลกชันสกาล่าแบบพิเศษพร้อมกับ OpenCL ฟังก์ชั่นที่เรียกใช้ในองค์ประกอบของคอลเลกชันสามารถเป็นฟังก์ชั่น Scala ปกติ (มีข้อ จำกัด บางอย่าง) ซึ่งจะถูกแปลเป็นเมล็ด OpenCL
ส่วนขยายภาษา
http://www.ateji.com/px/index.html : ส่วนขยายภาษาสำหรับ Java ที่อนุญาตการสร้างแบบขนาน (เช่นขนานสำหรับลูป, สไตล์ OpenMP) ซึ่งจะถูกดำเนินการบน GPU ด้วย OpenCL น่าเสียดายที่โครงการที่มีแนวโน้มดีนี้ไม่ได้รับการดูแลรักษาอีกต่อไป
http://www.habanero.rice.edu/Publications.html (JCUDA): ห้องสมุดที่สามารถแปลรหัส Java พิเศษ (เรียกว่ารหัส JCUDA) เป็นรหัส Java- และ CUDA-C ซึ่งสามารถรวบรวมและดำเนินการใน GPU อย่างไรก็ตามดูเหมือนว่าห้องสมุดจะไม่เปิดเผยต่อสาธารณะ
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html : ส่วนขยายภาษา Java สำหรับการสร้าง OpenMP พร้อม CUDA แบ็กเอนด์
Java OpenCL / CUDA ผูกพันไลบรารี
https://github.com/ochafik/JavaCL : การรวม Java สำหรับ OpenCL: ไลบรารี OpenCL เชิงวัตถุโดยยึดตามการเชื่อมระดับต่ำที่สร้างขึ้นโดยอัตโนมัติ
http://jogamp.org/jocl/www/ : การผูก Java สำหรับ OpenCL: ไลบรารี OpenCL เชิงวัตถุโดยยึดตามการผูกระดับต่ำที่สร้างขึ้นโดยอัตโนมัติ
http://www.lwjgl.org/ : การรวม Java สำหรับ OpenCL: การผูกระดับต่ำที่สร้างโดยอัตโนมัติและคลาสความสะดวกสบายเชิงวัตถุ
http://jocl.org/ : การรวม Java สำหรับ OpenCL: การผูกระดับต่ำที่เป็นการแมป 1: 1 ของ OpenCL API ดั้งเดิม
http://jcuda.org/ : การรวม Java สำหรับ CUDA: การเชื่อมระดับต่ำที่เป็นการแมป 1: 1 ของ CUDA API ดั้งเดิม
เบ็ดเตล็ด
http://sourceforge.net/projects/jopencl/ : การรวม Java สำหรับ OpenCL ดูเหมือนจะไม่ได้รับการบำรุงรักษาอีกต่อไปตั้งแต่ปี 2010
http://www.hoopoe-cloud.com/ : การรวม Java สำหรับ CUDA ดูเหมือนจะไม่ได้รับการบำรุงรักษาอีกต่อไป