Κατανεμημένος και Παράλληλος Προγραμματισμός Ηλίας Κ. Σάββας Καθηγητής Τμήμα Μηχανικών Πληροφορικής ΤΕ, ΤΕΙ Θεσσαλίας Email: savvas@teilar.gr MPI Διαμοίραση (MPI_Scatter) και συλλογή δεδομένων (MPI_Gather) Άθροισμα διανυσμάτων Σειριακό πρόγραμμα Παράλληλο πρόγραμμα (1 η έκδοση) Παράλληλο πρόγραμμα (2 η έκδοση) Σύγκριση προγραμμάτων / τεχνικών Χρονομέτρηση αποστολής / παραλαβής ΕνόητηταI #5 2 Γρήγορος οδηγός αναφοράς Οδηγία MPI_Init MPI_Comm.size MPI_Comm.rank MPI_Send MPI_Recv MPI_Bcast MPI_Reduce MPI_Finalize Αποτέλεσμα Αρχικοποίηση MPI Εύρεση πλήθους διεργασιών / κόμβων Εύρεση ποια διεργασία / κόμβος είμαι εγώ Αποστολή μηνύματος Παραλαβή μηνύματος Εκπομπή (μαζική) μηνύματος Παραλαβή μηνύματος και συσσώρευση τιμής Τερματισμός MPI ΕνόητηταI #5 3 1
Άθροισμα διανυσμάτων C N = A N + B N Το κάθε στοιχείο προκύπτει από το άθροισμα των αντίστοιχων στοιχείων του πρώτου και δεύτερου πίνακα // Σειριακή προσέγγιση for (i=0; i<n; i++) c[i] = a[i] + b[i]; ΕνόητηταI #5 4 Παραλληλία Εισαγωγή του μεγέθους του διανύσματος Αποστολή του μεγέθους σε όλες τις διεργασίες / κόμβους Εισαγωγή των πινάκων Παραλληλισμός του βρόγχου for Αποστολή στην βασική διεργασία των επιμέρους αποτελεσμάτων ΜΕΙΟΝΕΚΤΗΜΑ: κατανάλωση άσκοπης μνήμης αφού σε κάθε κόμβο πρέπει να αποθηκευθούν όλοι οι πίνακες ΕνόητηταI #5 5 Διαμοίραση δεδομένων (1 από 4) Έστω το διάνυσμα A[N]: Α[16] = { 2, 5, 6, 1, 6, 7, 3, 9, 5, 0, 6, 8, 3, 5, 6, 1} MPI_Bcast(&N,..., 0, ); MPI_Bcast(A,..., 0, ); Αποστολή Ν και Α σε όλες της διεργασίες / κόμβους MPI_Scatter(Α, 4, MPI_INT, Β, 4, MPI_INT, 0, Διαμοίραση των δεδομένων! ΕνόητηταI #5 6 2
Διαμοίραση δεδομένων (2 από 4) Διαμοίραση δεδομένων: MPI_Scatter( Buffer: διεύθυνση μεταβλητής αποστολέα Ποσότητα: πόσα δεδομένα θα αποσταλούν ανά διεργασία Τύπος δεδομένων: τύπος δεδομένων του MPI Buffer: διεύθυνση μεταβλητής παραλήπτη Ποσότητα: πόσα δεδομένα θα παραληφθούν Τύπος δεδομένων: τύπος δεδομένων του MPI Αποστολέας: διεργασία/κόμβος που διαμοιράζει MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Scatter(&A, 4, MPI_INT, &W, 4, MPI_INT, 0, ΕνόητηταI #5 7 Διαμοίραση δεδομένων (3 από 4) MPI_Scatter(&A, 4, MPI_INT, &W, 4, MPI_INT, 0, Α[16] = { 2, 5, 6, 1, 6, 7, 3, 9, 5, 0, 6, 8, 3, 5, 6, 1} P=0: B[4] = {2, 5, 6, 1} P=1: B[4] = {6, 7, 3, 9} P=2: B[4] = {5, 0, 6, 8} P=3: B[4] = {3, 5, 6, 1} ΕνόητηταI #5 8 Διαμοίραση δεδομένων (4 από 4) MPI_Scatter( ) Η μεταβλητή παραλαβής πρέπει να δηλωθεί σε όλες τις διεργασίες / κόμβους Σαν την MPI_Bcast() όλες οι διεργασίες / κόμβοι συμμετέχουν (εξαρτάται από τον επικοινωνητή) Συνήθως οι τύποι δεδομένων αποστολής / παραλαβής είναι ίδιοι αλλά δεν είναι απαραίτητο. Επιτρέπεται η αλλαγή τύπου. ΕνόητηταI #5 9 3
Συγκέντρωση αποτελεσμάτων (1 από 5) MPI_Gather( Buffer: διεύθυνση μεταβλητής αποστολέα Ποσότητα: πόσα δεδομένα θα αποσταλούν Τύπος δεδομένων: τύπος δεδομένων αποστολέα Buffer: διεύθυνση μεταβλητής παραλήπτη Ποσότητα: πόσα δεδομένα θα παραληφθούν από κάθε διεργασία Τύπος δεδομένων: τύπος δεδομένων παραλήπτη Παραλήπτης: διεργασία/κόμβος που συγκεντρώνει MPI_Comm: επικοινωνητής (ομάδα κόμβων) MPI_Gather(&V, 4, MPI_INT, &A, 4, MPI_INT, 0, ΕνόητηταI #5 10 Συγκέντρωση αποτελεσμάτων (2 από 5) MPI_Gather(&V, 4, MPI_INT, &A, 4, MPI_INT, 0, P=0: V[4] = {7, 4, 2, 5} P=1: V[4] = {2, 1, 6, 0} P=2: V[4] = {3, 1, 9, 2} P=3: V[4] = {4, 0, 1, 8} Συγκέντρωση, P=0: A[16] = {7, 4, 2, 5, 2, 1, 6, 0, 3, 1, 9, 2, 3, 1, 9, 2} ΕνόητηταI #5 11 Συγκέντρωση αποτελεσμάτων (3 από 5) Έστω η μεταβλητή myid περιέχει τον αριθμό της κάθε διεργασίας / κόμβου. Τι θα αποθηκευθεί στον πίνακα/διάνυσμα Β σε κάθε διεργασία / κόμβο εάν όλες (4) εκτελούν τον κώδικα: int b[4] = {0, 0, 0, 0}; MPI_Gather ( &myid, 1, MPI_INT, B, 1, MPI_INT, 3, MPI_COMM_WORLD ); ΕνόητηταI #5 12 4
Συγκέντρωση αποτελεσμάτων (4 από 5) int b[4] = {0, 0, 0, 0}; MPI_Gather ( &myid, 1, MPI_INT, B, 1, MPI_INT, 3, MPI_COMM_WORLD ); P=0: B[4] = {0, 0, 0, 0} P=1: B[4] = {0, 0, 0, 0} P=2: B[4] = {0, 0, 0, 0} P=3: B[4] = {0, 1, 2, 3} ΕνόητηταI #5 13 Συγκέντρωση αποτελεσμάτων (5 από 5) MPI_Gather(...) Τα δεδομένα που αποστέλλονται παραλαμβάνονται σε συνεχή διαδοχική σειρά από κάθε διεργασία / κόμβο Όλες οι μεταβλητές πρέπει να δηλωθούν παντού αλλά μόνο η μεταβλητή παραλαβής θα δεχτεί τιμές Όλες οι διεργασίες / κόμβοι συμμετέχουν (εξαρτάται από τον επικοινωνητή) ΕνόητηταI #5 14 Παράλληλο πρόγραμμα v1 (1 από 3) Παραλληλία του for και αποστολή αποτελεσμάτων for (i=myid; i<n; i+=p) C[i] = A[i] + B[i]; if (myid!= 0) // αποστολή από όλες τις διεργασίες στον 0 for (j=myid; j<n; j+=p) MPI_Send(&C[j], 1, MPI_INT, 0, myid, ΕνόητηταI #5 15 5
Παράλληλο πρόγραμμα v1 (2 από 3) if (myid == 0 ) { Λήψη αποτελεσμάτων for (i=1; i<p; i++) // από όλες τις διεργασίες for (j=i; j<n; j+=p) // τι παραλαμβάνει MPI_Recv(&C[j], 1, MPI_INT, i, i, MPI_COMM_WORLD, MPI_STATUS_IGNORE); ΕνόητηταI #5 16 Παράλληλο πρόγραμμα v1 (3 από 3) Μειονεκτήματα: Υπερβολική κατανάλωση μνήμης στα worker nodes. Δημιουργούν όλοι όλους του πίνακες ενώ διαχειρίζονται μόνο μέρος τους Αποστολή / λήψη μεμονωμένων στοιχείων του πίνακα αποτέλεσμα (C) Υπερβολική επιβράδυνση λόγω των επικοινωνιών ΕνόητηταI #5 17 Παράλληλο πρόγραμμα v2 (1 από 4) Δηλώσεις μεταβλητών. Χw οι πίνακες των workers int *A, *B, *C, N, i, j; /* Πίνακες C=A+B Μέγεθος Δείκτες. Οι Α, Β, C θα ορισθούν μόνο στον master node*/ int *Aw, *Bw, *Cw; /* Οι αντίστοιχοι πίνακες που θα ορισθούν και θα χρησιμοποιηθούν από τους worker nodes. Το μέγεθός τους είναι N/P, εάν P είναι το σύνολο των κόμβων και Ν το μέγεθος των A, B, C */ ΕνόητηταI #5 18 6
Παράλληλο πρόγραμμα v2 (2 από 4) Διαμοίραση (μαζική) δεδομένων MPI_Scatter(A, N/P, MPI_INT, Aw, N/P, MPI_INT, 0, MPI_Scatter(B, N/P, MPI_INT, Bw, N/P, MPI_INT, 0, Οι Α, Β διαμοιράζονται σε όλους τους συμμετέχοντες κόμβους από τον master node 0 Προσοχή: πρέπει Ν % P = 0 (γιατί?) ΕνόητηταI #5 19 Παράλληλο πρόγραμμα v2 (3 από 4) Παραλαβή (μαζική) δεδομένων MPI_Gather(Cw, N/P, MPI_INT, C, N/P, MPI_INT, 0, Οι Cw παραλαμβάνονται από όλους τους συμμετέχοντες κόμβους από τον master node 0. Τα δεδομένα παραλαμβάνονται με την σειρά από τον πίνακα C (πρώτα από τον κόμβο 0, μετά από τον 1, κοκ). ΕνόητηταI #5 20 Παράλληλο πρόγραμμα v2 (4 από 4) Πλεονεκτήματα: Μικρότερη κατανάλωση μνήμης στα worker nodes. Δημιουργούν όλοι πίνακες της τάξης N/P (P=συμμετέχοντες κόμβοι/διεργασίες) Αποστολή / λήψη μαζικά των στοιχείων των πινάκων αποτέλεσμα (Cw). Ταχύτερη από την 1 προς 1 αποστολή. ΕνόητηταI #5 21 7
Συγκρίσεις (1 από 3) ΕνόητηταI #5 22 Συγκρίσεις (2 από 3) ΕνόητηταI #5 23 Συγκρίσεις (3 από 3) ΕνόητηταI #5 24 8
Συμπεράσματα Οι επικοινωνίες και μεταφορές δεδομένων επιβραδύνουν πολύ τα παράλληλα προγράμματα Οι μαζικές επικοινωνίες / μεταφορές δεδομένων είναι ταχύτερες από τις σημείο προς σημείο Πρέπει να γνωρίζουμε τον χρόνο μεταφοράς δεδομένων Είναι προτιμότερο να μεταφέρουμε τους υπολογισμούς (προγράμματα) στα δεδομένα παρά τα δεδομένα στου υπολογισμούς ΕνόητηταI #5 25 Χρονομέτρηση επικοινωνιών Δημιουργία προγράμματος ping pong Δύο συμμετέχοντες κόμβοι / διεργασίες Ο κόμβος 0 στέλνει ένα αριθμό στον κόμβο 1 ο οποίος αφού τον παραλάβει τότε πάλι ο κόμβος 0 τον αλλάζει τον αριθμό (πχ τον αυξάνει κατά 1) και τον ξαναστέλνει Επανάληψη μέχρι κάποιο όριο του αριθμού Χρονομέτρηση της διαδικασίας Το αποτέλεσμα δείχνει με καλή προσέγγιση τον χρόνο μεταφοράς ενός αριθμού. ΕνόητηταI #5 26 Ping-pong while (ping_pong_counter < PING_PONG_ORIO) { if (myid == 0) { // εάν είμαι ο 0 ping_pong_counter++; MPI_Send(&ping_pong_counter, 1, MPI_INT, 0, 0, printf( O %d αύξησε τον αριθμό και έστειλε το %d στον %d\n",0, ping_pong_counter, 1); } else { // εάν είμαι ο 1 MPI_Recv(&ping_pong_count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf(«ο %d παρέλαβε τον αριθμό %d από τον %d\n", 1, ping_pong_counter, 0); } } // οι printf δεν πρέπει να χρονομετρηθούν ΕνόητηταI #5 27 9
Άσκηση Να γραφεί το πρόγραμμα ping_pong.c και να χρονομετρηθεί για PING_PONG_ORIO από 10,000 έως 100,000 με βήμα 10,000. Κάθε φορά να υπολογίζεται ο χρόνο αποστολής / παραλαβής ενός αριθμού. Τέλος, να υπολογισθεί η μέση τιμή του παραπάνω χρόνου για όλες τις περιπτώσεις. ΕνόητηταI #5 28 Ερωτήσεις; Τέλος της # 05 ενότητας Χρησιμοποιείστε το email για όποιες επιπλέον απορίες / ερωτήσεις: savvas@teilar.gr Σημειώσεις μαθήματος (και όχι μόνο): https://e-class.teilar.gr/courses/cs386/ Εισαγωγή στον παράλληλο ΕνόητηταI #5 προγραμματισμό 29 10