ต้นทุนการคำนวณของการดำเนินงาน mpi_allgather เปรียบเทียบกับการดำเนินการรวบรวม / กระจายอย่างไร


11

ฉันกำลังทำงานกับปัญหาที่สามารถทำให้ขนานได้โดยใช้การดำเนินงาน mpi_allgather เดียวหรือหนึ่ง mpi_scatter และหนึ่งการดำเนินงาน mpi_gather การดำเนินการเหล่านี้จะถูกเรียกภายในวงขณะที่ดังนั้นพวกเขาอาจจะเรียกหลายครั้ง

ในการนำไปใช้กับรูปแบบ MPI_allgather ฉันกำลังรวบรวมเวกเตอร์แบบกระจายสู่กระบวนการทั้งหมดสำหรับการแก้เมทริกซ์ที่ซ้ำกัน ในการใช้งานอื่น ๆ ฉันรวบรวมเวกเตอร์ที่กระจายไปยังโปรเซสเซอร์เดียว (โหนดรูท) แก้ไขระบบเชิงเส้นบนโปรเซสเซอร์นี้จากนั้นกระจายเวกเตอร์โซลูชันกลับสู่กระบวนการทั้งหมด

ฉันอยากรู้ว่าค่าใช้จ่ายในการดำเนินการของตัวรวบรวมทั้งหมดมากกว่าการกระจายและรวมการปฏิบัติการเข้าด้วยกันอย่างมีนัยสำคัญหรือไม่ ความยาวของข้อความมีบทบาทสำคัญในความซับซ้อนหรือไม่ มันแตกต่างกันระหว่างการใช้งานของ MPI หรือไม่

แก้ไข:


โปรดอธิบายโครงสร้างของการสื่อสารและขนาดที่เกี่ยวข้อง MPI_Scatterตามมาด้วยไม่ได้ให้การสื่อสารความหมายเดียวกันเป็นMPI_Gather MPI_Allgatherบางทีอาจมีความซ้ำซ้อนเมื่อคุณแสดงการดำเนินการด้วยวิธีใด?
Jed Brown

พอลเจดพูดถูกคุณหมายถึงคนMPI_Gatherตามมาด้วยMPI_Bcastหรือเปล่า?
Aron Ahmadia

@JedBrown: ฉันเพิ่มข้อมูลอีกเล็กน้อย
Paul

@AronAhmadia: ฉันไม่คิดว่าฉันควรใช้ MPI_Bcast เพราะฉันส่งบางส่วนของเวกเตอร์ไปยังแต่ละกระบวนการไม่ใช่เวกเตอร์ทั้งหมด เหตุผลของฉันคือข้อความที่สั้นกว่าจะเร็วกว่าการส่งข้อความทั่วไป มันสมเหตุสมผลหรือไม่
Paul

เมทริกซ์มีการกระจายซ้ำซ้อนหรือไม่? มันเป็นปัจจัยแล้ว กระบวนการหลายอย่างใช้แคชเดียวกันและบัสหน่วยความจำร่วมกันหรือไม่ (นั่นจะส่งผลต่อความเร็วในการแก้ระบบซ้ำซ้อน) ระบบใหญ่ / แพงแค่ไหน? ทำไมต้องแก้ลำดับ
Jed Brown

คำตอบ:


9

อันดับแรกคำตอบที่แน่นอนขึ้นอยู่กับ: (1) การใช้งานเช่นอาร์กิวเมนต์ของฟังก์ชันอินพุต (2) คุณภาพและรายละเอียดการใช้ MPI และ (3) ฮาร์ดแวร์ที่คุณใช้ บ่อยครั้งที่เกี่ยวข้องกับ (2) และ (3) เช่นเมื่อผู้จำหน่ายฮาร์ดแวร์ปรับ MPI ให้เหมาะสมสำหรับเครือข่าย

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

ยกตัวอย่างเช่นในทางทฤษฎีMPI_Reduce_scatter_blockควรจะดีกว่าMPI_Reduceตามมาด้วยMPI_Scatterแม้ว่าในอดีตมักจะถูกนำไปใช้ในแง่ของสิ่งหลังซึ่งไม่มีประโยชน์จริง มีความสัมพันธ์กันระหว่างคุณภาพการปรับใช้และความถี่ในการใช้งานในการนำไปใช้งานส่วนใหญ่ของ MPI และผู้ขายเห็นได้ชัดว่าฟังก์ชั่นเหล่านั้นปรับฟังก์ชั่นการทำงานเหล่านี้ให้เหมาะสมกับสัญญาเครื่อง

ในทางตรงกันข้ามถ้ามีใครอยู่ในยีนสีน้ำเงินการMPI_Reduce_scatter_blockใช้MPI_Allreduceซึ่งจะทำให้การสื่อสารมากกว่าMPI_ReduceและMPI_Scatterรวมกันเป็นจริงเร็วขึ้นเล็กน้อย นี่คือสิ่งที่ฉันค้นพบเมื่อเร็ว ๆ นี้และเป็นการละเมิดหลักการของความสอดคล้องในการปฏิบัติงานที่น่าสนใจใน MPI (หลักการนี้มีการอธิบายรายละเอียดเพิ่มเติมใน"แนวทางปฏิบัติงาน MPI ที่สอดคล้องกับตนเอง" )

ในกรณีเฉพาะของการกระเจิง + รวบรวมกับตัวรวบรวมพิจารณาว่าในอดีตข้อมูลทั้งหมดจะต้องไปและจากกระบวนการเดียวซึ่งทำให้เกิดคอขวดในขณะที่ในตัว allgather ข้อมูลสามารถไหลเข้าและออกจากตำแหน่งทั้งหมดได้ทันที เนื่องจากอันดับทั้งหมดมีข้อมูลที่จะส่งไปยังอันดับอื่นทั้งหมด อย่างไรก็ตามการส่งข้อมูลจากโหนดทั้งหมดในครั้งเดียวไม่จำเป็นต้องเป็นความคิดที่ดีในบางเครือข่าย

สุดท้ายวิธีที่ดีที่สุดในการตอบคำถามนี้คือทำสิ่งต่อไปนี้ในรหัสของคุณและตอบคำถามโดยการทดสอบ

#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
  MPI_Scatter(..)
  MPI_Gather(..)
#else
  MPI_Allgather(..)
#endif

ตัวเลือกที่ดียิ่งขึ้นคือการให้โค้ดของคุณวัดค่าในระหว่างการทำซ้ำสองครั้งแรกจากนั้นใช้ค่าใดก็ตามที่เร็วกว่าสำหรับการวนซ้ำที่เหลืออยู่:

const int use_allgather = 1;
const int use_scatter_then_gather = 2;

int algorithm = 0;
double t0 = 0.0, t1 = 0.0, dt1 = 0.0, dt2 = 0.0;

while (..)
{
    if ( (iteration==0 && algorithm==0) || algorithm==use_scatter_then_gather )
    {
        t0 = MPI_Wtime();
        MPI_Scatter(..);
        MPI_Gather(..);
        t1 = MPI_Wtime();
        dt1 = t1-t0;
    } 
    else if ( (iteration==1 && algorithm==0) || algorithm==use_allgather)
    {
        t0 = MPI_Wtime();
        MPI_Allgather(..);
        t1 = MPI_Wtime();
        dt2 = t1-t0;
    }

    if (iteration==1)
    {
       dt2<dt1 ? algorithm=use_allgather : algorithm=use_scatter_then_gather;
    }
}

นั่นไม่ใช่ความคิดที่ดี ... เวลาพวกเขาทั้งสองและกำหนดว่าจะเร็ว
เปาโล

ฮาร์ดแวร์สภาพแวดล้อม HPC ที่ทันสมัยส่วนใหญ่ใช้การเรียก MPI ได้หลายตัว บางครั้งสิ่งนี้นำไปสู่การเพิ่มความเร็วอย่างไม่น่าเชื่อเวลาอื่นพฤติกรรมที่ทึบมาก ระวัง!
meawoppl

@ เจฟฟ์: ฉันเพิ่งรู้ว่าฉันทิ้งรายละเอียดสำคัญไว้หนึ่งข้อ ... ฉันทำงานกับกลุ่มที่ Texas Advanced Computing Center ซึ่งพวกเขาใช้เครือข่ายทอพอโลยีต้นไม้อ้วน สิ่งนั้นจะส่งผลกระทบต่อความแตกต่างในการทำงานระหว่างการรวบรวมทั้งหมดและการรวบรวมออกอากาศหรือไม่
พอล

@ พอลโทโพโลยีไม่ได้เป็นปัจจัยสำคัญที่นี่ แต่ต้นไม้ไขมันมีแบนด์วิดธ์ bisection อย่างมีนัยสำคัญซึ่งจะทำให้ราคาถูก allgather อย่างไรก็ตามการรวบรวมควรจะถูกกว่าทุกคนเสมอ สำหรับข้อความที่มีขนาดใหญ่ขึ้นอาจเป็นปัจจัยที่น้อยกว่า 2
Jeff

5

เจฟฟ์พูดถูกต้องเกี่ยวกับวิธีเดียวที่จะแน่ใจได้ว่าเราจะทำการวัด - เราเป็นนักวิทยาศาสตร์หลังจากทั้งหมดและนี่คือคำถามเชิงประจักษ์ - และให้คำแนะนำที่ดีเกี่ยวกับวิธีการใช้การวัดดังกล่าว ให้ฉันเสนอมุมมองที่ตรงกันข้าม (หรืออาจจะเสริม)

มีความแตกต่างที่จะทำระหว่างการเขียนรหัสที่จะใช้กันอย่างแพร่หลายและปรับไปยังจุดสิ้นสุดที่เฉพาะเจาะจง โดยทั่วไปเรากำลังสร้างรหัสแรกของเราเพื่อให้ก) เราสามารถใช้มันบนแพลตฟอร์มที่หลากหลายและข) รหัสนั้นสามารถคงไว้ได้และสามารถขยายได้ในอีกหลายปีข้างหน้า แต่บางครั้งเรากำลังทำสิ่งอื่น ๆ - เราได้รับการจัดสรรปีหนึ่งสำหรับเครื่องจักรขนาดใหญ่บางส่วนและเรากำลังเร่งเครื่องจำลองขนาดใหญ่ที่ต้องการและเราต้องการประสิทธิภาพการทำงานขั้นพื้นฐานเพื่อให้ได้สิ่งที่เราต้องการในระหว่าง เวลาของการจัดสรรที่ได้รับ

เมื่อเราเขียนโค้ดการทำให้ใช้งานได้อย่างกว้างขวางและบำรุงรักษามีความสำคัญมากกว่าการโกนสักสองสามเปอร์เซ็นต์ของรันไทม์บนเครื่องเฉพาะ ในกรณีนี้สิ่งที่ถูกต้องคือเกือบทุกครั้งที่จะใช้รูทีนที่อธิบายสิ่งที่คุณต้องการได้ดีที่สุด - นี่คือการโทรที่เฉพาะเจาะจงที่สุดที่คุณสามารถทำได้ตามที่คุณต้องการ ตัวอย่างเช่นหากตัวแบ่งตรงหรือ allgatherv ทำในสิ่งที่คุณต้องการคุณควรใช้สิ่งนั้นแทนที่จะนำตัวคุณเองออกจากการปฏิบัติการกระจาย / แยก เหตุผลก็คือ:

  • รหัสนี้แสดงให้เห็นอย่างชัดเจนยิ่งขึ้นว่าคุณกำลังพยายามทำอะไรทำให้คนอื่นที่เข้ามาใช้รหัสของคุณเข้าใจในปีถัดไปโดยไม่รู้ว่าควรจะทำอย่างไร (บุคคลนั้นอาจเป็นคุณ)
  • การปรับให้เหมาะสมมีอยู่ในระดับ MPI สำหรับกรณีเฉพาะเจาะจงมากขึ้นซึ่งไม่ได้อยู่ในกรณีทั่วไปมากขึ้นดังนั้นไลบรารี MPI ของคุณสามารถช่วยคุณได้ และ
  • การพยายามม้วนตัวเองจะทำให้ย้อนกลับมา แม้ว่ามันจะทำงานได้ดีขึ้นในเครื่อง X ด้วยการใช้งาน MPI Y.ZZ มันอาจทำงานได้แย่ลงมากเมื่อคุณย้ายไปที่เครื่องอื่นหรืออัพเกรดการใช้งาน MPI ของคุณ

ในกรณีทั่วไปนี้หากคุณพบว่า MPI บางกลุ่มทำงานช้าลงอย่างไม่มีเหตุผลบนเครื่องของคุณสิ่งที่ต้องทำคือส่งรายงานข้อผิดพลาดกับผู้จำหน่าย MPI คุณไม่ต้องการให้ซอฟท์แวร์ของคุณเองยุ่งยากในการพยายามแก้ไขแอปพลิเคชันในสิ่งที่ควรแก้ไขในระดับไลบรารี MPI

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

ดังนั้นฉันไม่เห็นด้วยกับ Jeff ฉันแค่ต้องการเพิ่มบริบทบางอย่างเกี่ยวกับเวลาที่คุณควรกังวลเกี่ยวกับคำถามเกี่ยวกับประสิทธิภาพที่เกี่ยวข้องเพื่อแก้ไขโค้ดของคุณเพื่อจัดการกับมัน


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