การรองรับการเร่งความเร็วแบบหลายโพรเซสและหลายเธรด
หน้านี้บันทึกขอบเขตที่ qiskit-addon-sqd รองรับการเร่งความเร็วแบบหลายเธรดและหลายโพรเซส และข้อสมมติที่นักพัฒนา high-performance computing (HPC) พึ่งพาได้เมื่อนำแพ็กเกจนี้ไปรวมในเวิร์กโหลดที่เร่งความเร็ว
ข้อสมมติแบบเธรดเดียว
เว้นแต่จะระบุไว้เป็นอย่างอื่น API ในแพ็กเกจนี้ถูกออกแบบให้เรียกจากเธรดเดียว API ระดับสูงที่แพ็กเกจนี้เปิดให้ใช้ไม่รับประกันว่าเป็น re-entrant และผู้ใช้ปลายทางไม่ควรเรียกจากเธรดอื่นนอกจากเธรดหลัก
การรันแบบหลายโพรเซสร่วมกัน
แพ็กเกจนี้รองรับการเร่งความเร็วแบบหลายโพรเซสร่วมกันในสไตล์ single-program, multiple-data (SPMD) ซึ่งโปรแกรมทั้งหมดถูกเริ่มเป็นหลายโพรเซสที่แยกจากกันและรันพร้อมการซิงโครไนซ์ส่วนกลางและการสื่อสารระหว่างกันอย่างชัดเจน (เช่น mpirun -n 128 python my_program.py) เนื่องจากสไตล์ SPMD ทำงานร่วมกับตัวจัดตารางงานและซอฟต์แวร์คู่ขนานอื่นได้อย่างราบรื่น และขยายขนาดไปยังจำนวนโพรเซสมาก ๆ ได้ จึงเป็นโมเดลที่แนะนำสำหรับเวิร์กโหลดประสิทธิภาพสูงและขนาดใหญ่ และเป็นหัวข้อของหน้านี้
แม้แพ็กเกจนี้ถูกออกแบบให้รองรับ backend การรันร่วมกันที่หลากหลาย แต่การ implement ปัจจุบันมุ่งเป้าที่ MPI ซึ่งเป็น API ส่งข้อความมาตรฐานสำหรับระบบ HPC ไม่ว่าจะ implement แบบใด แพ็กเกจนี้สมมติว่ามีเธรดเดียวควบคุมแต่ละโพรเซส ในกรณีของ MPI สิ่งนี้ตรงกับ MPI_THREAD_FUNNELED หรือต่ำกว่า
ถ้าฟังก์ชันรองรับการรันร่วมกัน เอกสารของฟังก์ชันนั้นต้องระบุไว้ ถ้าเอกสารไม่ได้กล่าวถึงการรันร่วมกัน ฟังก์ชันนั้นไม่มีความหมายแบบร่วมกันและต้องถูกเรียกจากโพรเซสควบคุมเพียงโพรเซสเดียว
ค่าที่ส่งคืนและความหมายด้านการซิงโครไนซ์เฉพาะของฟังก์ชันแบบร่วมกันถูกบันทึกไว้กับตัวฟังก์ชันเอง โดยทั่วไป เอกสารนั้นควรทำให้ชัดเจนว่า:
-
ฟังก์ชันนั้นตั้งใจให้แต่ละโพรเซสเรียกอย่างอิสระกับข้อมูลภายในของตัวเอง หรือให้ทุกโพรเซสเรียกร่วมกัน
-
อาร์กิวเมนต์ของมันต้องสอดคล้องกันข้ามโพรเซสอย่างไร
-
ค่าที่ส่งคืนถูกส่งมอบอย่างไร—ผลลัพธ์มีอยู่เฉพาะบนโพรเซสควบคุม ทุกโพรเซสได้รับค่าเดียวกัน หรือแต่ละโพรเซสได้รับ handle ไปยังส่วนภายในของโครงสร้างข้อมูลแบบกระจาย
ปัจจุบันมีเพียงฟังก์ชันเดียวที่รองรับการถูกเรียกร่วมกันจากทุกโพรเซส: diagonalize_fermionic_hamiltonian() เมื่อถูกเรียกร่วมกัน ขั้นตอน eigensolver คือจุดที่ทุกโพรเซสเข้าร่วมและช่วยทำงาน ดังนั้น implementation ของ eigensolver จึงใช้ทุกโพรเซสได้ ส่วนที่เหลือของลูปการกู้คืนคอนฟิกูเรชันไม่มี implementation แบบกระจายและรันบนโพรเซสควบคุม (rank 0) เท่านั้น
ซับสเปซทุกตัวของหนึ่งรอบถูกส่งให้ eigensolver ในการเรียกครั้งเดียว ดังนั้น implementation จึงมีอิสระที่จะแบ่งโพรเซสเป็นกลุ่มและทำ diagonalization หลายซับสเปซพร้อมกัน วิธีที่ตัวแก้ใช้โพรเซสที่มีอยู่เป็นคุณสมบัติของ eigensolver นั้น
implementation ของ eigensolver ที่มีอยู่บางตัวต้องการให้โปรแกรมที่เรียกรันนอกสภาพแวดล้อม MPI/SPMD เพราะมันเริ่มและจัดการโพรเซสคู่ขนานของตัวเองภายใน เช่น โดยการเรียก mpirun แทนผู้ใช้ โหมดนั้นสะดวกสำหรับงานแบบโต้ตอบและงานบนโน้ตบุ๊ก และยังคงรองรับอยู่ ข้อกำหนดที่มีต่อโปรแกรมที่เรียกอธิบายไว้ในเอกสารอ้างอิง API ของฟังก์ชัน diagonalize_fermionic_hamiltonian()
การจัดการข้อผิดพลาดในบริบทแบบหลายโพรเซส
ฟังก์ชันที่ถูกเรียกร่วมกันจากทุกโพรเซสต้องไม่ raise exception หรือยกเลิกเพียงโพรเซสเดียว เพราะจะทำให้โพรเซสที่เหลือเกิด deadlock หรืออยู่ในสถานะไม่สอดคล้องกัน แต่การจัดการข้อผิดพลาดเป็นไปตามความหมายแบบ fail-stop สำหรับบริบทการรันทั้งหมด: เมื่อเกิดข้อผิดพลาด implementation ต้องพร้อมยกเลิกบริบทการรันทั้งหมดร่วมกัน (เช่น โดยใช้ MPI_Abort)
API ไม่สามารถรับประกันการรายงานข้อผิดพลาดแบบประสานงานหรือการส่งมอบ exception ร่วมกันข้ามโพรเซสได้ เพราะ implementation ของ MPI ไม่ได้ให้การรับประกันเช่นนั้น implementation อาจพยายามทำให้ทุกโพรเซสที่เข้าร่วมมองเห็นข้อผิดพลาดเพิ่มเติม เช่น ให้แต่ละโพรเซส raise exception แต่ทำได้เพียงแบบ best-effort เท่านั้น และต้องไม่พึ่งพาเพื่อความถูกต้องหรือการกู้คืน
สิ่งเหล่านี้เป็นคุณสมบัติที่ implementation แบบร่วมกันได้รับอนุญาตให้มี ไม่ใช่การรับประกันสำหรับ implementation ใดโดยเฉพาะ ในแพ็กเกจนี้ ขั้นตอนร่วมกันเพียงขั้นตอนเดียวคือ eigensolver (ดูหัวข้อก่อนหน้า) implementation เริ่มต้นของมันไม่ได้กระจาย ดังนั้นข้อพิจารณาเหล่านี้จึงใช้กับ eigensolver แบบร่วมกันที่ผู้ใช้จัดหาเอง