9. MPI kertesz.gabor@nik.uni-obuda.hu
MPI Message Passing Interface Elosztott memóriájú párhuzamos programozási API Gyk. folyamatok közötti kommunikáció de facto ipari standard Több száz előre definiált rutin De a legtöbb esetben néhány funckió használatával már működő megoldások készíthetőek
Inter-process kommunikáció Folyamatok közötti kommunikáció Ugyanazon CPUn több MPI folyamat is futtatható De több elosztott rendszer is alkalmazható A folyamatoknak küldeni és fogadni kell adatokat a többi folyamattól
Open MPI vs OpenMP Open MPI Négy egyetem közös MPI implementációja Cross-platform library OpenMP Open Multi-Processing Közös memóriájú multiprocessing, multithreading Magasszintű absztrakció párhuzamos programok készítésére Cross-platform library Tech-vállalatok konzorciuma felügyeli Alkalmazásuk együtt is lehetséges
MPI implementációk C, C++, Fortran Boost C++ libraries.net framework C#, C++, F#, VB.NET, stb. MPI.NET MS-MPI alapú
Point-to-point kommunikáció A folyamatok üzenetet tudnak küldeni, és fogadni Communicator: Folyamatok csoportja Azonosítóval: 0 N-1 MPI_Send(buf, count, datatype, dest, tag, comm) buf: starting address of send buffer count: number of elements data_type: data type of each send buffer element dest: processor ID (rank) destination tag: message tag comm: communicator MPI_Recv(buf, count, datatype, src, tag, comm, status) status: status object (an integer array in Fortran) Ezek a funkciók blokkolnak!
Point-to-point kommunikáció Üzenet fogadásához egyeznie kell a Forrásnak (src) vagy bárhonnan: MPI_ANY_SOURCE Üzenet címkéjének (tag) vagy bármilyen: MPI_ANY_TAG És a kommunikátornak (comm)
Send/Recv példa C syntax int f[n], src=0, dest=1; MPI_Status status; //... MPI_Comm_rank( MPI_COMM_WORLD, &rank); if (rank == src) // process dest ignores this MPI_Send(f, N, MPI_INT, dest, 0, MPI_COMM_WORLD); if (rank == dest) // process src ignores this MPI_Recv(f, N, MPI_INT, src, 0, MPI_COMM_WORLD, &status); //...
Holtpont Mivel a Send és Recv hívások blokkolóak, könnyen belátható hogy a hívások sorrendje nagyon fontos Holtpont kialakulhat!
Helyes felépítés MPI_Comm_rank(comm, &rank); if (rank == 0) MPI_Send(sendbuf, cnt, MPI_INT, 1, tag, comm); MPI_Recv(recvbuf, cnt, MPI_INT, 1, tag, comm, &stat); else // rank==1 MPI_Recv(recvbuf, cnt, MPI_INT, 0, tag, comm, &stat); MPI_Send(sendbuf, cnt, MPI_INT, 0, tag, comm);
Helytelen felépítés - holtpont MPI_Comm_rank(comm, &rank); if (rank == 0) MPI_Recv(recvbuf, cnt, MPI_INT, 1, tag, comm, &stat); MPI_Send(sendbuf, cnt, MPI_INT, 1, tag, comm); else // rank==1 MPI_Recv(recvbuf, cnt, MPI_INT, 0, tag, comm, &stat); MPI_Send(sendbuf, cnt, MPI_INT, 0, tag, comm);
Blokkolásmentes Send / Recv Létezik nem-blokkoló megvalósítás küldésre és fogadásra MPI_Isend MPI_Irecv Ebben az esetben azonban a küldés / fogadás teljesülésére várakozni kell (szinkronizációs pont) MPI_Wait(request, status)
Csoportos kommunikáció Egy mindenkinek MPI_Bcast MPI_Scatter Mindenki egynek MPI_Gather MPI_Reduce
Scatter / Gather A Broadcast ugyanazt az üzenetet küldi szét minden fogadó félnek A Scatter egy tömb különböző darabjait küldi az egyes folyamatoknak A Gather a Scatter fordítottja: begyűjti az adatokat a folyamatoktól
Reduce Gather hívás esetén nagy memória lehet szükséges az érkező adatok tárolására A kérdés, hogy szükséges-e ezeket az adatokat tárolni A Reduce hívás is adatokat fogad a többi folyamattól Azonban a kapott adatok nem kerülnek tárolásra Valamilyen művelet kerül elvégzésre rajtuk Max, Min, Sum, Prod
MPI.NET MS-MPI-ra épül Microsoft MPI implementáció https://msdn.microsoft.com/enus/library/windows/desktop/bb524831(v=vs.85).aspx MSMpiSetup.exe NuGetből letölthető a csomag (a jelenlegi verzió 4.6.2-es target frameworkre épül)
Hello world! namespace MPI_Hello class Program static void Main(string[] args) using (new MPI.Environment(ref args)) System.Console.WriteLine("Hello, from process number " + MPI.Communicator.world.Rank.ToString() + " of " + MPI.Communicator.world.Size.ToString());
Hello world! Hello, from process number 0 of 1 Press any key to continue...
Hello world! - mpiexec C:\Users\kerteszg\Documents\Visual Studio 2015\Projects\MPI_Hello\MPI_Hello\bin\Debug>mpiexec -n 8 MPI_Hello.exe Hello, from process number 1 of 8 Hello, from process number 0 of 8 Hello, from process number 4 of 8 Hello, from process number 3 of 8 Hello, from process number 6 of 8 Hello, from process number 2 of 8 Hello, from process number 5 of 8 Hello, from process number 7 of 8
Rank using (new MPI.Environment(ref args)) if (MPI.Communicator.world.Rank == 0) Console.WriteLine("I'm groot"); else Console.WriteLine("I'm someone else"); I'm groot I'm someone else I'm someone else I'm someone else
Send / Receive Semmi dolgom Semmi dolgom #0: Üzenet elküldve: #1: Üzenet megérkezett: Sziasztok! MPI.Intracommunicator comm = MPI.Communicator.world; int rank = comm.rank; if (rank == 0) comm.send("sziasztok!", 1, 0); Console.WriteLine("#0: Üzenet elküldve: ", rank); else if (rank == 1) string uzenet = comm.receive<string>(mpi.intracommunicator.anysource, 0); Console.WriteLine("#0: Üzenet megérkezett: 1", rank, uzenet); else Console.WriteLine("Semmi dolgom");
Send / Receive #1: Üzenet megérkezett: Demo #2: Üzenet megérkezett: Demo, 1 #3: Üzenet megérkezett: Demo, 1, 2 Vége! #0: Üzenet megérkezett: Demo, 1, 2, 3 MPI.Intracommunicator comm = MPI.Communicator.world; int rank = comm.rank; if (rank == 0) comm.send("demo", 1, 0); string uzenet = comm.receive<string>(mpi.intracommunicator.anysource, 0); Console.WriteLine("Vége!"); Console.WriteLine("#0: Üzenet megérkezett: 1", rank, uzenet); else string uzenet = comm.receive<string>(mpi.intracommunicator.anysource, 0); Console.WriteLine("#0: Üzenet megérkezett: 1", rank, uzenet); comm.send(uzenet + ", " + rank, (rank + 1) % comm.size, 0);
Broadcast #0: Üzenet megérkezett: Sziasztok! #2: Üzenet megérkezett: Sziasztok! #3: Üzenet megérkezett: Sziasztok! #1: Üzenet megérkezett: Sziasztok! MPI.Intracommunicator comm = MPI.Communicator.world; int rank = comm.rank; string uzenet = null; if (rank == 0) Console.WriteLine(comm.Size); uzenet = "Sziasztok!"; comm.broadcast(ref uzenet, 0); Console.WriteLine("#0: Üzenet megérkezett: 1", rank, uzenet);
Gather 0: 0 1: 1 2: 2 3: 3 using (new MPI.Environment(ref args)) MPI.Intracommunicator comm = MPI.Communicator.world; int[] ids = comm.gather(comm.rank, 0); if (comm.rank == 0) for (int i = 0; i < ids.length; i++) Console.WriteLine("0: 1", i, ids[i]);
6 Reduce using (new MPI.Environment(ref args)) MPI.Intracommunicator comm = MPI.Communicator.world; int total = comm.reduce(comm.rank, MPI.Operation<int>.Add, 0); if (comm.rank == 0) Console.WriteLine(total);
Összefoglalás Message Passing Interface de facto szabvány, többféle implementáció Folyamatok közötti, üzenetváltáson alapuló modell Elosztott rendszereknél is használható Kommunikáció Point-to-point Send / receive, blokkoló Csoportos kommunikáció Broadcast Scatter, Gather Reduce
Források open-mpi.org mpitutorial.com http://osl.iu.edu/research/mpi.net/ (1.0ig, 2008!) https://github.com/jmp75/mpi.net/ (1.30, up-to-date)