Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων MPI: Message Passing Interface 9 ο Εξάμηνο
Αρχιτεκτονική κοινής μνήμης l l l Οι επεξεργαστές έχουν κοινή μνήμη Κάθε επεξεργαστής διαθέτει τοπική ιεραρχία κρυφών μνημών Συνήθως η διασύνδεση γίνεται μέσω διαδρόμου μνήμης (memory bus) Αλλά και πιο εξελιγμένα δίκτυα διασύνδεσης l Ομοιόμορφη ή μη-ομοιόμορφη προσπέλαση στη μνήμη (Uniform Memory Access UMA, Non-uniform Memory Access NUMA) l l Η κοινή μνήμη διευκολύνει τον παράλληλο προγραμματισμό Δύσκολα κλιμακώσιμη αρχιτεκτονική τυπικά μέχρι λίγες δεκάδες κόμβους (δεν κλιμακώνει το δίκτυο διασύνδεσης) $ CPU $ CPU... $ CPU Διάδρομος Μνήμης (memory bus) M 2
Αρχιτεκτονική κατανεμημένης μνήμης l Κάθε επεξεργαστής έχει τη δική του τοπική μνήμη και ιεραρχία τοπικών μνημών l Διασυνδέεται με τους υπόλοιπους επεξεργαστές μέσω δικτύου διασύνδεσης l Η κατανεμημένη μνήμη δυσκολεύει τον προγραμματισμό l Η αρχιτεκτονική κλιμακώνει σε χιλιάδες υπολογιστικούς κόμβους Κόμβος 1 Κόμβος 2 Κόμβος Ν $ CPU $ CPU... $ CPU M M M Δίκτυο Διασύνδεσης (π.χ. Ethernet, Myrinet, SCI) 3
Υβριδική αρχιτεκτονική l Συνδυάζει τις δύο παραπάνω αρχιτεκτονικές: κόμβοι με αρχιτεκτονική κοινής μνήμης διασυνδέονται με ένα δίκτυο διασύνδεσης σε αρχιτεκτονική κατανεμημένης μνήμης l Τυπική αρχιτεκτονική των σύγχρονων συστοιχιώνυπερυπολογιστών SMP κόμβος 1 SMP κόμβος 2 SMP κόμβος Ν $ CPU 0 $ $... CPU Κ CPU 0 $...... CPU Κ CPU 0 $... $ CPU Κ M M M Δίκτυο Διασύνδεσης (π.χ. Ethernet, Myrinet, SCI) 4
Παραδοσιακά προγραμματιστικά μοντέλα l Κοινός χώρος διευθύνσεων (shared address space) Οι διεργασίες έχουν πρόσβαση σε κοινό χώρο διευθύνσεων Χρησιμοποιούνται κανονικές εντολές ανάγνωσης / εγγραφής Πιθανόν απαιτείται κάποια αρχικοποίηση του κοινού χώρου διευθύνσεων Οι διευθύνσεις μπορεί να αφορούν: lφυσικά κοινή μνήμη lφυσικά κατανεμημένη μνήμη (απαιτείται στρώμα υλικού ή λογισμικού) l Ανταλλαγή μηνυμάτων (message passing) Δεν υπάρχουν κοινά δεδομένα Πρόσβαση σε δεδομένα που κατέχει άλλη διεργασία γίνεται με ρητές κλήσεις σε συναρτήσεις αποστολής / λήψης 5
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... Κόμβος j $... CPU... CPU M M 6
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... Κόμβος j $... CPU... CPU M M 7
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... Κόμβος j $... CPU... CPU M M 8
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... Κόμβος j $... CPU... CPU M M 9
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... Κόμβος j $... MPI_Send CPU... CPU M M 10
Ανταλλαγή μηνυμάτων Διεργασία 1 Διεργασία 2 Κόμβος i $... MPI_Recv Κόμβος j $... MPI_Send CPU... CPU M M 11
Αρχιτεκτονικές και Προγραμματιστικά Μοντέλα από την οπτική του προγραμματιστή Αρχιτεκτονική Κοινής μνήμης (shared memory) Κατανεμημένης μνήμης (distributed memory) Προγραμματιστικό μοντέλο Κοινός χώρος διευθύνσεων (shared address space) Ανταλλαγή μηνυμάτων (message-passing) + Ευκολία υλοποίησης + Προγραμματιστική ευκολία + Υψηλή επίδοση + Ευκολία υλοποίησης + Υψηλή επίδοση - Προγραμματιστική δυσκολία + Προγραμματιστική ευκολία - Δυσκολία υλοποίησης - Χαμηλή επίδοση + Ευκολία υλοποίησης + Υψηλή επίδοση - Προγραμματιστική δυσκολία 12
l Είναι πρότυπο, όχι συγκεκριμένη υλοποίηση Αναπτύσσεται από το MPI forum από το 1992 l Βιβλιοθήκη ανταλλαγής μηνυμάτων Τι είναι το MPI Το πρότυπο περιγράφει συναρτήσεις με συγκεκριμένα ορίσματα και ορισμένη σημασιολογία Οι διάφορες υλοποιήσεις της βιβλιοθήκης ακολουθούν το πρότυπο l Σε υψηλό επίπεδο, παρέχει διεπαφήμε τον προγραμματιστή l Σε χαμηλό επίπεδο, επικοινωνεί με το δίκτυο διασύνδεσης l Υποστηρίζει C, C++, Fortran77, F90 13
l MPICH: http://www.mpich.org Υλοποιήσεις MPI Πολλές υλοποιήσεις από τη βιομηχανία βασίζονται στο MPICH l Intel MPI, Cray MPI, IBM PE MPI, TH-MPI l OpenMPI: http://www.open-mpi.org Συγχώνευσε παλαιότερες υλοποιήσεις του MPI l FT-MPI, LA-MPI, LAM/MPI, PACX-MPI Ανοιχτό project με πολλούς εταίρους από την έρευνα και τη βιομηχανία l MVAPICH: http://mvapich.cse.ohio-state.edu Υλοποίηση του προτύπου για το δίκτυο InfiniBand 14
Single Program Multiple Data (SPMD) l Όλες οι διεργασίες εκτελούν το ίδιο πρόγραμμα l Κάθε διεργασία επεξεργάζεται υποσύνολο των δεδομένων ή διαφοροποιεί τη ροή εκτέλεσης της με βάση το βαθμό (rank) που της αποδίδει το MPI l Επιδίωξη παράλληλου προγραμματισμού: Μεγιστοποίηση παραλληλίας Αποδοτική αξιοποίηση πόρων συστήματος (π.χ. μνήμη) Ελαχιστοποίηση όγκου δεδομένων επικοινωνίας Ελαχιστοποίηση αριθμού μηνυμάτων Ελαχιστοποίηση συγχρονισμού 15
Διεργασίες και communicators l Σε κάθε διεργασία αποδίδεται ένα μοναδικό rank στο εύρος 0...P-1, όπου P το συνολικό πλήθος διεργασιών στον συγκεκριμένο communicator l Σε γενικές γραμμές, o communicator ορίζει ένα σύνολο από διεργασίες που μπορούν να επικοινωνούν μεταξύ τους l O global communicator είναι ο MPI_COMM_WORLD l Προσοχή: Αναφερόμαστε πάντα σε διεργασίες, όχι σε επεξεργαστές 16
Βασικές συναρτήσεις στο MPI l MPI_Init(argc,argv) Αρχικοποίηση l MPI_Comm_rank(comm,rank) Αντιστοίχιση rank-διεργασίας σε communicator comm l MPI_Comm_size(comm,size) Εύρεση πλήθους διεργασιών size σε comm l MPI_Send(sndbuf,count,datatype,dest,tag,comm) Αποστολή μηνύματος σε διεργασία dest l MPI_Recv(rcvbuf,count,datatype,source,tag, comm,status) l Λήψη μηνύματος από διεργασία source MPI_Finalize() Τερματισμός 17
Τυπική δομή κώδικα MPI #include <mpi.h> void main(int argc, char **argv){ }... /* Πρώτη κλήση MPI */ MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size);... /* Τελευταία κλήση MPI */ MPI_Finalize(); 18
MPI_Init int MPI_Init(int* argc, char*** argv) l Αρχικοποίηση περιβάλλοντος MPI l Παράδειγμα: int main(int argc,char** argv){ } MPI_Init(&argc,&argv); 19
MPI_Comm_rank int MPI_Comm_rank (MPI_Comm comm, int* rank) l Καθορισμός rank καλούσας διεργασίας που ανήκει στον communicator comm l Παράδειγμα: int rank; MPI_Comm_rank(MPI_COMM_WORLD,&rank); 20
MPI_Comm_size int MPI_Comm_size (MPI_Comm comm, int* size) l Καθορισμός πλήθους διεργασιών size που ανήκουν στον communicator comm l Παράδειγμα: int size; MPI_Comm_size(MPI_COMM_WORLD,&size); 21
int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) l Αποστολή μηνύματος buf από καλούσα διεργασία σε διεργασία με rank dest l Ο πίνακας buf έχει count στοιχεία τύπου datatype MPI_Send l Παράδειγμα: int message[20],dest=1,tag=55; MPI_Send(message, 20, MPI_INT, dest, tag, MPI_COMM_WORLD); 22
MPI_Recv int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) l Λήψη μηνύματος από διεργασία με rank source και αποθήκευση σε buf l Λαμβάνονται το πολύ count δεδομένα τύπου datatype (ακριβής αριθμός με MPI_Get_count) l Wildcards: MPI_ANY_SOURCE, MPI_ANY_TAG l Παράδειγμα: int message[50],source=0,tag=55; MPI_Status status; MPI_Recv(message, 50, MPI_INT, source, tag, MPI_COMM_WORLD,&status); 23
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 24
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 25
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 26
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 27
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 28
Αποστολή λήψη στο MPI MPI διεργασία i MPI_Send(msg,3,j,...); virtual memory διεργασίας i MPI διεργασία j MPI_Recv(msg,3,i,...); virtual memory διεργασίας i MPI buffer MPI buffer 29
MPI_Sendrecv int MPI_Sendrecv( void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, MPI_Comm comm, MPI_Status *status ) l Λήψη και αποστολή μηνύματος με μία κλήση l Για «συμμετρικό» κώδικα χρήση του MPI_NULL_PROC 30
MPI_Finalize int MPI_Finalize() l Τερματισμός περιβάλλοντος MPI l Πρέπει να αποτελεί την τελευταία κλήση MPI του προγράμματος 31
Παράδειγμα προγράμματος MPI /* Παράλληλος υπολογισµός της παράστασης f(0)+f(1)*/ #include <mpi.h> int main(int argc,char** argv){ int v0,v1,sum,rank; MPI_Status stat; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); if(rank==1) MPI_Send(&f(1),1,0,50,MPI_INT,MPI_COMM_WORLD); else if(rank==0){ v0=f(0); MPI_Recv(&v1,1,1,50,MPI_INT,MPI_COMM_WORLD,&stat); sum=v0+v1; } MPI_Finalize(); } 32
Παράδειγμα προγράμματος MPI /* Παράλληλος υπολογισµός της παράστασης f(0)+f(1)*/ #include <mpi.h> int main(int argc,char** argv){ int v0,v1,sum,rank; MPI_Status stat; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); if(rank==1) Διεργασία 1 MPI_Send(&f(1),1,0,50,MPI_INT,MPI_COMM_WORLD); else if(rank==0){ v0=f(0); MPI_Recv(&v1,1,1,50,MPI_INT,MPI_COMM_WORLD,&stat); sum=v0+v1; } MPI_Finalize(); } 33
Παράδειγμα προγράμματος MPI /* Παράλληλος υπολογισµός της παράστασης f(0)+f(1)*/ #include <mpi.h> int main(int argc,char** argv){ int v0,v1,sum,rank; MPI_Status stat; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); if(rank==1) Διεργασία 1 MPI_Send(&f(1),1,0,50,MPI_INT,MPI_COMM_WORLD); else if(rank==0){ v0=f(0); MPI_Recv(&v1,1,1,50,MPI_INT,MPI_COMM_WORLD,&stat); sum=v0+v1; } MPI_Finalize(); Διεργασία 0 } 34
l Μπορεί να είναι point-to-point ή συλλογική (collective) Επικοινωνία l Μπορεί να είναι synchronous, buffered ή ready (ανάλογα με το τι θεωρείται ως συνθήκη επιτυχίας) l Μπορεί να είναι blocking ή non-blocking(ανάλογα με το πότε επιστρέφει η συνάρτηση επικοινωνίας) 35
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 if(rank==0) for(dest=1;dest<size;dest++) MPI_Send(msg,count,dest,tag,MPI_FLOAT,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 36
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 if(rank==0) for(dest=1;dest<size;dest++) MPI_Send(msg,count,dest,tag,MPI_FLOAT,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 37
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 if(rank==0) for(dest=1;dest<size;dest++) MPI_Send(msg,count,dest,tag,MPI_FLOAT,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 38
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 if(rank==0) for(dest=1;dest<size;dest++) MPI_Send(msg,count,dest,tag,MPI_FLOAT,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 39
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 if(rank==0) for(dest=1;dest<size;dest++) MPI_Send(msg,count,dest,tag,MPI_FLOAT,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 Γενικά: Για p διεργασίες έχουµε p-1 βήµατα επικοινωνίας 40
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 MPI_Bcast(msg,count,MPI_FLOAT,0,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 41
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 MPI_Bcast(msg,count,MPI_FLOAT,0,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 42
Συλλογική επικοινωνία Παράδειγμα: Αποστολή του msg στις διεργασίες 1-7 από τη 0 MPI_Bcast(msg,count,MPI_FLOAT,0,MPI_COMM_WORLD); Διεργασίες MPI msg 0 1 2 3 4 5 6 7 Γενικά: Για p διεργασίες έχουμε log! p βήματα επικοινωνίας 43
MPI_Bcast int MPI_Bcast(void* message, int count, MPI_Datatype datatype, int root, MPI_Comm comm) l Αποστολή του message από τη διεργασία με rank root προς όλες της διεργασίες του communicator comm l To message περιέχει count δεδομένα τύπου datatype l Καλείται από όλες τις διεργασίες του comm 44
MPI_Bcast int MPI_Bcast(void* message, int count, MPI_Datatype datatype, int root, MPI_Comm comm) P0 P1 P2 P3 45
MPI_Bcast int MPI_Bcast(void* message, int count, MPI_Datatype datatype, int root, MPI_Comm comm) P0 P0 P1 Bcast P1 P2 P2 P3 P3 46
MPI_Reduce int MPI_Reduce(void* operand, void* result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) l Τα δεδομένα operand συνδυάζονται με εφαρμογή του τελεστή op, και το αποτέλεσμα αποθηκεύεται στη διεργασία root στο result l Πρέπει να κληθεί από όλες τις διεργασίες του comm l MPI_Op: MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD κλπ. l Αντίστοιχα και MPI_Allreduce 47
MPI_Reduce int MPI_Reduce(void* operand, void* result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) P0 P1 P2 P3 48
MPI_Reduce int MPI_Reduce(void* operand, void* result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) P0 P0 P1 P2 Reduce P1 P2 P3 P3 MPI_Op=MPI_SUM root = 0 = + + + 49
Παράδειγμα συλλογικής επικοινωνίας /* Παράλληλος υπολογισµός της παράστασης f(0)+f(1)*/ #include <mpi.h> int main(int argc,char** argv){ int sum,rank; MPI_Status stat; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Reduce(&f(rank),&sum,1,MPI_INT,MPI_SUM,0, MPI_COMM_WORLD); MPI_Finalize(); } 50
MPI_Allreduce int MPI_Allreduce(void* operand, void* result, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) P0 P0 P1 P2 Allreduce P1 P2 P3 P3 MPI_Op=MPI_SUM No root! = + + + 51
MPI_Barrier int MPI_Barrier(MPI_Comm comm) l Συγχρονίζονται όλες οι διεργασίες στον communicator comm l Περιορίζει την παραλληλία 52
MPI_Gather int MPI_Gather(void* sendbuf, int sendcnt, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) l Συνενώνονται στη διεργασία root οι πίνακες sendbuf των υπολοιπών (κατά αύξουσα σειρά rank) l Το αποτέλεσμα αποθηκεύεται στον πίνακα recvbuf, ο οποίος έχει νόημα μόνο στη διεργασία root l Αντίστοιχα και MPI_Allgather l Αντίστροφη: MPI_Scatter 53
MPI_Gather int MPI_Gather(void* sendbuf, int sendcnt, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) P0 P1 P2 P3 54
MPI_Gather int MPI_Gather(void* sendbuf, int sendcnt, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) P0 P0 P1 Gather P1 P2 P2 P3 P3 55
MPI_Scatter int MPI_Scatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,mpi_comm comm) P0 P0 P1 Scatter P1 P2 P2 P3 P3 56
Synchronous-Buffered-Ready l l l int MPI_Ssend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) Επιτυγχάνει μόνο όταν πάρει επιβεβαίωση λήψης από δέκτη ασφαλές int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) Επιτυγχάνει όταν αντιγραφεί το μήνυμα σε system buffer για μελλοντική μετάδοση σφάλμα σε έλλειψη πόρων int MPI_Rsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) Επιτυγχάνει μόνο αν έχει προηγηθεί αντίστοιχο receive από το δέκτη αβέβαιο 57
Synchronous-Buffered-Ready l Αναφέρονται σε λειτουργία αποστολής, διαφοροποιούνται ως προς λειτουργία λήψης l Υπάρχουν τόσο σε blocking, όσο και σε non-blocking μορφή l Το απλό MPI_Send μπορεί να είναι είτε synchronous είτε buffered: εξαρτάται από υλοποίηση 58
Synchronous-Buffered-Ready MPI_Bsend MPI_Ssend MPI_Rsend Τοπικό Μη τοπικό Τοπικό 2 αντιγραφές στη μνήμη 1 αντιγραφή στη μνήμη 1 αντιγραφή στη μνήμη Αποτυγχάνει ελλείψει πόρων Δεν αποτυγχάνει ελλείψει πόρων Δεν αποτυγχάνει ελλείψει πόρων Δεν αποτυγχάνει αν δεν έχει προηγηθεί λήψη Δεν αποτυγχάνει αν δεν έχει προηγηθεί λήψη Αποτυγχάνει αν δεν έχει προηγηθεί λήψη 59
l Άμεση επιστροφή Non-blocking communication l Δεν είναι ασφαλές να επαναχρησιμοποιηθούν οι buffers επικοινωνίας πριν ελεγχθεί η επιτυχία l Δύο δυνατότητες για έλεγχο επιτυχίας της επικοινωνίας: int MPI_Test (MPI_Request* request,int* flag, MPI_Status* status) int MPI_Wait (MPI_Request* request,mpi_status* status) l Δυνατότητα ελέγχου για εισερχόμενα μηνύματα, χωρίς να γίνει λήψη (progress report): int MPI_Probe (int source, int tag, MPI_Comm comm, MPI_Status *status) 60
Non-blocking communication l Κάθε blocking συνάρτηση έχει την αντίστοιχη non-blocking: MPI_Isend (για MPI_Send) MPI_Issend (για MPI_Ssend) MPI_Ibsend (για MPI_Bsend) MPI_Irsend (για MPI_Rsend) MPI_Irecv (για MPI_Recv) 61
Επικάλυψη υπολογισμών - επικοινωνίας Blocking Non-blocking MPI_Recv(); MPI_Send(); Compute(); MPI_Irecv(); MPI_Isend(); Compute(); Waitall(); 62
Αποφυγή deadlocks l Blocking (deadlock!) Rank 0 Rank 1 MPI_Send(msg,Rank1); MPI_Recv(msg,Rank1); Compute(); MPI_Send(msg,Rank0); MPI_Recv(msg,Rank0); Compute(); l Non-blocking Rank 0 Rank 1 MPI_Isend(msg,Rank1); MPI_Irecv(msg,Rank1); Waitall(); Compute(); MPI_Isend(msg,Rank0); MPI_Irecv(msg,Rank0); Waitall(); Compute(); 63
Τύποι δεδομένων MPI l l l l l l l l l l l MPI_CHAR: 8-bit χαρακτήρας MPI_DOUBLE: 64-bit κινητής υποδιαστολής MPI_FLOAT: 32-bit κινητής υποδιαστολής MPI_INT: 32-bit ακέραιος MPI_LONG: 32-bit ακέραιος MPI_LONG_DOUBLE: 64-bit κινητής υποδιαστολής MPI_LONG_LONG: 64-bit ακέραιος MPI_LONG_LONG_INT: 64-bit ακέραιος MPI_SHORT: 16-bit ακέραιος MPI_SIGNED_CHAR: 8-bit προσημασμένος χαρακτήρας MPI_UNSIGNED: 32-bit απρόσημος ακέραιος MPI_UNSIGNED_CHAR: 8-bit απρόσημος χαρακτήρας MPI_UNSIGNED_LONG: 32-bit απρόσημος ακέραιος MPI_UNSIGNED_LONG_LONG: 64-bit απρόσημος ακέραιος MPI_UNSIGNED_SHORT: 16-bit απρόσημος ακέραιος MPI_WCHAR: 16-bit απρόσημος χαρακτήρας 64
l Ομαδοποίηση δεδομένων επικοινωνίας: Τύποι δεδομένων MPI l Παράμετρος count (για ομοιογενή δεδομένα σε συνεχόμενες θέσεις μνήμης) l MPI_Type_struct (derived datatype) l MPI_Pack(), MPI_Unpack() (για ετερογενή δεδομένα) 65
Τύποι δεδομένων MPI l l Derived datatypes Χρησιμοποιούμε τα derived datatypes όταν θέλουμε να ορίσουμε: μη συνεχόμενα στη μνήμη δεδομένα ίδιου τύπου (π.χ. μια στήλη ενός πίνακα) συνεχόμενα στη μνήμη δεδομένα διαφορετικών τύπων (π.χ. ένα struct) l μη συνεχόμενα στη μνήμη δεδομένα διαφορετικών τύπων Παράδειγμα χρήσης: Πώς μπορώ να στείλω μια στήλη ενός πίνακα; 1. Με μία κλήση send για κάθε στοιχείο 2. Με αντιγραφή της στήλης σε ειδικό buffer l 3. Με τη δημιουργία ενός datatype για τη στήλη του πίνακα Το 3o δεν είναι απαραίτητα πιο γρήγορο από το 2o - εξαρτάται από την υλοποίηση! 66
Τύποι δεδομένων MPI l l MPI_Type_contiguous int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) l Δημιουργεί ένα νέο datatype newtype ενώνοντας count συνεχόμενα στη μνήμη δεδομένα τύπου oldtype 67
Τύποι δεδομένων MPI l l MPI_Type_vector int MPI_Type_vector(int count, int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype) l l Δημιουργεί ένα νέο datatype newtype ενώνοντας blocklength δεδομένα τύπου oldtype από count blocks που απέχουν κατά κάποιο stride Στο παράδειγμα: blocklength=2, stride=3 68
Τύποι δεδομένων MPI l MPI_Type_indexed l int MPI_Type_indexed(int count, int * array_of_blocklengths, int *array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype) l Συνενώνει irregular υποσύνολα δεδομένων από πίνακα l Ακριβός τύπος δεδομένων 69
Τύποι δεδομένων MPI l MPI_Type_create_struct l int MPI_Type_create_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types, MPI_Datatype *newtype) l Δημιουργεί structs αντίστοιχα με τα structs της C l Επίσης ακριβός τύπος δεδομένων 70
Τύποι δεδομένων MPI l MPI_Type_create_struct l int MPI_Type_create_subarray(int ndims, int *array_of_sizes, int *array_of_subsizes, int *array_of_starts, int order, MPI_Datatype oldtype, MPI_Datatype *newtype ) l Δημιουργεί έναν υποπίνακα newtype από έναν πίνακα oldtype, ndims διαστάσεων 71
Χρήση των τύπων δεδομένων MPI l Κατασκευή του datatype MPI_Type_contiguous(10, MPI_DOUBLE, &my_datatype) l Δέσμευση χώρου για το datatype MPI_Type_commit(&my_datatype) l Χρήση του datatype MPI_Send(&my_array[100],1,my_datatype,1,55, MPI_COMM_WORLD) l Απελευθέρωση του χώρου στη μνήμη MPI_Type_free(&my_datatype) 72
Βιβλιογραφία-Πηγές l Using MPI, 3 rd Edition, Portable Parallel Programming with the Message-Passing Interface, William Gropp, Ewing Lusk, Anthony Skjellum, 2014. l Using Advanced MPI, Modern Features of the Message-Passing Interface, William Gropp, Torsten Hoefler, Rajeev Thakur and Ewing Lusk, The MIT Press, 2014. l Υλικό από διάφορα tutorials για το MPI: http://www.mcs.anl.gov/research/projects/mpi/tutorial/ 73