Κατανεμημένος και Παράλληλος Προγραμματισμός Ηλίας Κ. Σάββας Αναπληρωτής Καθηγητής Τμήμα Μηχανικών Πληροφορικής ΤΕ, ΤΕΙ Θεσσαλίας Email: savvas@teilar.gr MPI Οδηγίες αποστολής / παραλαβής μηνυμάτων, Υπολογισμός του π (3.14159.) Σειριακό πρόγραμμα Παράλληλο πρόγραμμα Απόδοση παράλληλου προγράμματος Βελτίωση προγραμμάτων Συνήθη λάθη MPI #2 2 MPI Απλές εντολές MPI_Comm_rank( MPI_COMM_WORLD, &rank ): αποδίδει στην ακέραια μεταβλητή rank τον αριθμό της τρέχουσας διεργασίας ή υπολογιστικού κόμβου (node) της υπολογιστικής συστοιχίες (computational clusters) MPI_Comm_size( MPI_COMM_WORLD, &size ): αποδίδει στην ακέραια μεταβλητή size το συνολικό πλήθος των ενεργών διεργασιών ή υπολογιστικών κόμβων (nodes) της υπολογιστικής συστοιχίες (computational clusters) MPI #2 3 1
MPI p2p επικοινωνίες (1 από 2) Αποστολή μηνυμάτων: MPI_Send( Buffer: διεύθυνση μεταβλητής Ποσότητα: πόσα δεδομένα θα αποσταλούν Τύπος δεδομένων: τύπος δεδομένων του MPI Προορισμός: σε ποιο κόμβο θα αποσταλούν Tag: ετικέτα μηνύματος MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Send(&x, 1, MPI_INT, i, 0, MPI_COMM_WORLD); MPI #2 4 MPI p2p επικοινωνίες (2 από 2) Παραλαβή μηνυμάτων: MPI_Recv( Buffer: διεύθυνση μεταβλητής Ποσότητα: πόσα δεδομένα θα αποσταλούν Τύπος δεδομένων: τύπος δεδομένων του MPI Προορισμός: σε ποιο κόμβο θα αποσταλούν Tag: ετικέτα μηνύματος MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Status: πληροφορίες μηνύματος MPI_Recv(&xw, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI #2 5 Τύποι δεδομένων C char int long int long long int float double long double MPI MPI_CHAR MPI_INT MPI_LONG MPI_LONG_LONG MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE MPI #2 6 2
MPI μαζική αποστολή - εκπομπή Broadcast: MPI_Bcast( Buffer: διεύθυνση μεταβλητής Ποσότητα: πόσα δεδομένα θα αποσταλούν Τύπος δεδομένων: τύπος δεδομένων του MPI Αποστολέας: ποιός κόμβος εκπέμπει MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Bcast(&x, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI #2 7 MPI συλλογική επικοινωνία (1 από 2) Συλλογική επικοινωνία: MPI_Reduce( Buffer 1: διεύθυνση τοπικής μεταβλητής Buffer 2: διεύθυνση μεταβλητής συσσώρευσης Ποσότητα: πόσα δεδομένα θα αποσταλούν Τύπος δεδομένων: τύπος δεδομένων του MPI Operator: τελεστής πράξης Προορισμός: σε ποιο κόμβο θα αποσταλούν MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Reduce(&x, &y, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); MPI #2 8 MPI συλλογική επικοινωνία (2 από 2) Operator (τελεστής) MPI_SUM MPI_PROD MPI_MAX MPI_MIN MPI_LAND MPI_LOR Επεξήγηση Άθροισμα Γινόμενο Μέγιστη τιμή Ελάχιστη τιμή Λογικό ΚΑΙ σύζευξη Λογικό Η - διάζευξη Παράδειγμα: Εάν 3 worker nodes αποστέλλουν τις τιμές 2, 4, και 10 τότε μία αντίστοιχη MPI_Reduce με τελεστή MPI_SUM θα απέδιδε στην μεταβλητή συσσώρευσης την τιμή 16 ΠΡΟΣΟΧΗ: Είναι δυνατόν να αποσταλούν και ολόκληρα διανύσματα (?) MPI #2 9 3
Γρήγορος οδηγός αναφοράς Οδηγία MPI_Init MPI_Comm.size MPI_Comm.rank MPI_Send MPI_Recv MPI_Bcast MPI_Reduce MPI_Finalize Αποτέλεσμα Αρχικοποίηση MPI Εύρεση πλήθους διεργασιών / κόμβων Εύρεση ποια διεργασία / κόμβος είμαι εγώ Αποστολή μηνύματος Παραλαβή μηνύματος Εκπομπή (μαζική) μηνύματος Παραλαβή μηνύματος και συσσώρευση τιμής Τερματισμός MPI MPI #2 10 Υπολογισμός του π 1 1 1 + x 2 dx = arctan x 0: 1 = arctan 1 arctan 0 = arctan 1 = π 0 4 f x = 4 1 + x2 Αριθμητικός υπολογισμός: Διαίρεση του διαστήματος 0 1 σε Ν υπο-διαστήματα και άθροιση των αποτελεσμάτων MPI #2 11 Σειριακό πρόγραμμα (1 από 3) #include "mpi.h" #include <stdio.h> #include <math.h> int main( int argc, char *argv[] ) { int n; int i; double Pi = 3.141592653689793238482643; double mypi, pi, h, sum, x; double ta, tt; MPI_Init( &argc, &argv ); MPI #2 12 4
Σειριακό πρόγραμμα (2 από 3) while (1) { printf("\neisagogi plithous diastimatwn (0 gia telos: "); scanf("%d", &n); if ( n == 0 ) break; else { ta = MPI_Wtime(); h = 1.0 / (double) n; sum = 0.0; for (i=1; i<=n; i++) { x = h * ((double) i - 0.5); sum += (4.0 / (1 + x * x)); MPI #2 13 Σειριακό πρόγραμμα (3 από 3) mypi = h * sum; pi = mypi; tt = MPI_Wtime(); printf("\n\nto pi proseggistike sto %.16f", pi); printf("\n\nme lathos %.16f\n\n", fabs(pi - Pi)); printf("\n\nxronos ektelesis: %.16f\n\n", tt-ta); MPI_Finalize(); return 0; MPI #2 14 Τι μπορεί να παραλληλιστεί? Ο βρόγχος του for Κάθε κόμβος να εκτελεί ένα μέρος του βρόγχου, Το αποτέλεσμα να σταλεί στον master κόμβο Ο master κόμβος να λάβει τα αποτελέσματα και στην συνέχεια να τα αθροίσει Το πρόγραμμα βασίστηκε στο πρωτότυπο: W. Gropp, E. Lusk, and A.Skjellum, Using MPI, The MIT Press, 1999, pp: 23-35 MPI #2 15 5
Παράλληλο πρόγραμμα (1 από 4) #include "mpi.h" #include <stdio.h> #include <math.h> int main( int argc, char *argv[] ) { int n, rank, size; int i; double Pi = 3.141592653689793238482643; double mypi, pi, h, sum, x; double ta, tt; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI #2 16 Παράλληλο πρόγραμμα (2 από 4) while (1) { if (rank == 0 ) { printf("\neisagogi plithous diastimatwn (0 gia telos): "); scanf("%d", &n); Γιατί if (rank==0)??? MPI #2 17 Παράλληλο πρόγραμμα (3 από 4) ta = MPI_Wtime(); // Αρχή χρονομέτρησης MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if ( n == 0 ) break; else { h = 1.0 / (double) n; sum = 0.0; for (i=rank+1; i<=n; i+=size) { x = h * ((double) i - 0.5); sum += (4.0 / (1 + x * x)); mypi = h * sum; Καλή τεχνική παραλληλισμού το βρόγχου for MPI #2 18 6
Παράλληλο πρόγραμμα (4 από 4) MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); tt = MPI_Wtime(); // τέλος χρονομέτρησης if (rank == 0) { printf("\n\nto pi proseggistike sto %.16f", pi); printf("\n\nme lathos %.16f\n\n", fabs(pi - Pi)); printf("\n\nxronos ektelesis: %.16f\n\n", tt-ta); MPI_Finalize(); return 0; MPI #2 19 Παρατηρήσεις - βελτιώσεις MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); και όχι for (i=1; i<size; i++) MPI_Send(&n, 1, MPI_INT, i, 0, MPI_COMM_WORLD); και στην συνέχεια MPI_Recv( από κάθε κόμβο MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); και όχι for (i=1; i<size; i++) MPI_Recv(&R[i-1],. Και στην συνέχεια άθροιση των στοιχείων του πίνακα R MPI #2 20 Συνηθισμένο λάθος if (rank == 0 ) { printf("\neisagogi plithous diastimatwn: "); scanf("%d", &n); Εάν έλειπε το if (rank == 0) τότε ο κάθε κόμβος / διεργασία θα ζητούσε το n (το ίδιο ισχύει και στην εκτύπωση αποτελεσμάτων) Δοκιμάστε το!!! MPI #2 21 7
Υπολογισμός π Απόδοση (1 από 2) MPI #2 22 Υπολογισμός π Απόδοση (2 από 2) P/ Nx1,000, 000 P=1 P=2 P=3 P=4 100 1.522 0.778 0.540 0.420 200 3.125 1.555 1.060 0.844 300 4.630 2.332 1.621 1.232 400 6.090 3.109 2.123 1.653 500 7.644 3.886 2.667 2.074 600 9.136 4.662 3.201 2.457 700 10.736 5.443 3.719 2.929 800 12.249 6.217 4.297 3.361 900 13.691 6.994 4.814 3.766 1000 15.204 7.774 5.426 4.204 MPI #2 23 Ερωτήσεις; Τέλος της # 03 ενότητας Χρησιμοποιείστε το email για όποιες επιπλέον απορίες / ερωτήσεις: savvas@teilar.gr Σημειώσεις μαθήματος (και όχι μόνο): https://e-class.teilar.gr/courses/cs386/ Εισαγωγή στον παράλληλο MPI #2 προγραμματισμό 24 8