Κατανεμημένος και Παράλληλος Προγραμματισμός Ηλίας Κ. Σάββας Αναπληρωτής Καθηγητής Τμήμα Μηχανικών Πληροφορικής ΤΕ, ΤΕΙ Θεσσαλίας Email: savvas@teilar.gr Εισαγωγή στο MPI Εγκατάσταση του Message Passing Interface, To πρώτο πρόγραμμα με MPI Αναζήτηση στοιχείου σε πίνακα: Σειριακό πρόγραμμα, Παράλληλο πρόγραμμα, Συγκρίσεις (απόδοση παράλληλου προγράμματος) Εισαγωγή στο MPI, #1 2 Εγκατάσταση MPICH σε ένα ΗΥ Ψευδοπαράλληλο σύστημα Όλες οι λειτουργίες ενός παράλληλου υπολογιστικού συστήματος (cluster) σε ένα υπολογιστή Εισαγωγή στο MPI, #1 3 1
Βήμα 1: download Κατέβασμα του συμπιεσμένου αρχείου απο https://www.mpich.org/downloads/ Αποσυμπίεση του αρχείου: Αποσυμπίεση: tar -xzf mpich2_version.tar.gz H αποσυμίεση θα γίνει σε ένα νέο φάκελο με όνομα ίδιο με το όνομα του αρχείου, πχ: mpich2_version tar = αποσυμπίεση x = αποσυμπίεση αρχείων εάν προέρχοναται απο gzip ή bzip2 συμπίεση z = φιλτράρισμα των αρχείων απο το gzip για αποσυμπίεση f = αποσυμπίεση αρχείων που ακολουθούν ονομαστικά Εισαγωγή στο MPI, #1 4 Βήμα 2: configure (1)./configure: H διαταγή εκτελεί ένα πρόγραμμα (script) το οποίο ελέγχει εάν το σύστημά μας περιέχει όλο τα απαραίτητο λογισμικό για να μεταγλωττίσει κάποιο πρόγραμμα/πακέτο προγραμμάτων, καθώς επίσης και ότι λογισμικό απαιτείται για να εκτελέσει το πρόγραμμα (μετά την μεταγλώττιση)./: τρέχων κατάλογος Εισαγωγή στο MPI, #1 5 Βήμα 2: configure (2) Μετακίνηση στο κατάλογο που αποσυμπιέστηκε το mpich-3.2: cd mpich-3.2 pwd και ls για επιβεβαίωση Configure./configure ή./configure disable -fortran (για να μην εγκαταστήσει βιβλιοθήκες για Fortran) CONFIGURATION COMPLETED Εισαγωγή στο MPI, #1 6 2
Βήμα 3: make / install make: μεταγλώττιση προγράμματος/πακέτων (θα χρειαστεί χρόνο...) make sudo = εκτέλεση κάποιας διαταγής που απαιτεί δικαιώματα super user (θα ζητηθεί το αντίστοιχο password) sudo make install: εγκατάσταση το προγράμματος mpiexec --version: επιβεβαίωση και έκδοση mpi Version 3.2 κλπ Εισαγωγή στο MPI, #1 7 To πρώτο πρόγραμμα: hello1.c #include "mpi.h" #include <stdio.h> int main( int argc, char *argv[] ) { MPI_Init( &argc, &argv ); printf( "Hello, world!\n" ); MPI_Finalize(); return 0; Εισαγωγή στο MPI, #1 8 Μεταγλώττιση και εκτέλεση (1) mpicc hello1.c -o hello1.out mpiexec./hello1.out Hello, world! mpicc = o μεταγλωττιστής της C mpic++ = o μεταγλωττιστής της C++ mpiexec (mpirun) = εκτέλεση προγράμματος Εισαγωγή στο MPI, #1 9 3
Καλύτερο πρόγραμμα (με χρήση της mpi): hello2.c #include "mpi.h" #include <stdio.h> int main( int argc, char *argv[] ) { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); printf( "I am %d of %d\n", rank, size ); MPI_Finalize(); return 0; Εισαγωγή στο MPI, #1 10 Μεταγλώττιση και εκτέλεση (2) mpicc hello2.c -o hello2 mpiexec -np 5./hello2 Hello from 0 process of 5 Hello from 3 process of 5 Hello from 2 process of 5 Hello from 1 process of 5 Hello from 4 process of 5 Εισαγωγή στο MPI, #1 11 MPI Απλές εντολές (1) #include mpi.h : ενσωμάτωση στο πρόγραμμα του header file της MPI. Περιέχει όλες τις συναρτήσεις οι οποίες μας επιτρέπουν να χρησιμοποιήσουμε παραλληλία στο πρόγραμμα MPI_Init( &argc, &argv ): αρχικοποίηση της MPI MPI_Finalize(): τερματισμός της MPI Εισαγωγή στο MPI, #1 12 4
MPI Απλές εντολές (2) MPI_Comm_rank( MPI_COMM_WORLD, &rank ): αποδίδει στην ακέραια μεταβλητή rank τον αριθμό της τρέχουσας διεργασίας ή υπολογιστικού κόμβου (node) της υπολογιστικής συστοιχίες (computational clusters) MPI_Comm_size( MPI_COMM_WORLD, &size ): αποδίδει στην ακέραια μεταβλητή size το συνολικό πλήθος των ενεργών διεργασιών ή υπολογιστικών κόμβων (nodes) της υπολογιστικής συστοιχίες (computational clusters) Εισαγωγή στο MPI, #1 13 Ασκήσεις Πράξης # 01 Έστω ότι έχουμε ένα σύνολο S αποτελούμενο από Ν ακέραιους αριθμούς (αποθηκευμένοι σε ένα αρχείο κειμένου) και P διαθέσιμους υπολογιστικούς πόρους. Επίσης, έστω ακέραιος αριθμός X. Το ζητούμενο είναι εάν ο X υπάρχει στο S και εάν ναι πόσες φορές υπάρχει. Εισαγωγή στο MPI, #1 14 Σειριακός αλγόριθμος Counter 0 Για i 1 μέχρι Ν Εάν S[i] = X τότε Counter Counter + 1 Πολυπλοκότητα = O(N) Τέλος (εάν) Τέλος (Για) Εάν Counter = 0 τότε Ο Χ δεν υπάρχει στο S Αλλιώς Ο Χ εμφανίζεται Counter φορές στο S Τέλος (εάν) Εισαγωγή στο MPI, #1 15 5
Πρόγραμμα (1 από 3) #include "mpi.h" #include <stdio.h> #include <stdlib.h> #include <time.h> int main( int argc, char *argv[] ) { int *P, N, i; /* Pinakαs - megethos - deiktis */ int x, f=0; /* stoixeio poy anazitoyme, poses fores vrethike */ double ta, tt; /* gia metrisi xronou */ MPI_Init( &argc, &argv ); printf("\nmegethos pinaka:"); scanf("%d", &N); Εισαγωγή στο MPI, #1 16 Πρόγραμμα (2 από 3) /* Dimioyrgia pinaka */ P = malloc( N * sizeof( int ) ); if ( P == NULL ) { printf("\n\npoly megalos pinakas..."); printf("\n\nto programma termatizei...\n\n"); return -1; //srand(time(null)); for (i=0; i<n; i++) P[i] = rand() % 10000; printf("\neisagofi stoixiou pros anazitisi (0-->9999):"); scanf("%d", &x); Εισαγωγή στο MPI, #1 17 Πρόγραμμα (3 από 3) ta = MPI_Wtime(); /* arxi metrisis xronou */ /* anazitisi */ for (i=0; i<n; i++) if (P[i] == x ) f++; tt = MPI_Wtime(); /* telos metrisis xronou */ printf("\n\nto %d yparxei ston pinaka %d fores", x, f); printf("\n\nxronos ektelesis: %.16f\n\n", tt-ta); MPI_Finalize(); return 0; Εισαγωγή στο MPI, #1 18 6
Παραλληλισμός προβλήματος Ακολουθεί το μοντέλο SIMD (Single Instruction Multiple Data) Ο master node (v 0 ) πρέπει: Να διαμοιράσει τα δεδομένα Να λάβει τα αποτελέσματα Να αθροίσει τα αποτελέσματα Τα worker nodes (v i, i=1 P-1) πρέπει: Να λάβουν τα δεδομένα Να εκτελέσουν τις οδηγίες Να στείλουν στον master node τα αποτελέσματα. Εισαγωγή στο MPI, #1 19 v 0 : διαμοίραση δεδομένων Όγκος δεδομένων: Ν (Σε πίνακα Α Ν ) Σύνολο κόμβων: P-1 (όλοι εκτός του v 0 ) Επομένως ο κάθε κόμβος πρέπει να λάβει Ν/(P- 1) δεδομένα ΠΡΟΣΟΧΗ: ο τελευταίος κόμβος θα λάβει ότι περισσεύσει εάν το Ν δεν είναι ακέραιο πολλαπλάσιο του Ρ-1 ΕΠΟΜΕΝΩΣ: ο v i ποιο μέρος των δεδομένων θα λάβει; A i 1 N P 1 +1 A i N P 1 Εισαγωγή στο MPI, #1 20 v 0 : αποτελέσματα O v 0 λαμβάνει από τον v i και το αποθηκεύει σε ένα νέο πίνακα R στην θέση i. To μέγεθος του R πρέπει να είναι Ρ-1 Στην συνέχεια αθροίζει όλα τα στοιχεία του R και αυτό είναι το ζητούμενο αποτέλεσμα. Εισαγωγή στο MPI, #1 21 7
v i : εργασίες Λαμβάνει το Ν/(Ρ-1) δεδομένα (εκτός ίσως από τον τελευταίο) και το υπο αναζήτηση στοιχείο Αποθήκευση σε πίνακα D μεγέθους Ν/(Ρ-1) Εκτέλεση των οδηγιών (όπως στο σειριακό αλγόριθμο) Αποστολή στον v 0 το αποτέλεσμα Εισαγωγή στο MPI, #1 22 Παράλληλο πρόγραμμα (1 από 7) #include "mpi.h" #include <stdio.h> #include <stdlib.h> #include <time.h> int main( int argc, char *argv[] ) { int myid, numprocs; /* node id, synolo nodes */ MPI_Init( &argc, &argv ); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank( MPI_COMM_WORLD, &myid ); Εισαγωγή στο MPI, #1 23 Παράλληλο πρόγραμμα (2 από 7) /* Eisagogi pinaka mono sto master node */ if (myid == 0) { int *P, N, i; /* Pinakas - megethos - deiktis */ int *R; /* Pinakas ypodoxis apoantiseon sto master node */ int part; /* temaxismos pinaka */ int x, f=0; /* stoixeio poy anazitoyme, poses fores vrethike */ double ta, tt; /* gia metrisi xronou */ printf("\nmegethos pinaka:"); scanf("%d", &N); Εισαγωγή στο MPI, #1 24 8
Παράλληλο πρόγραμμα (3 από 7) /* Dimioyrgia pinaka */ P = malloc( N * sizeof( int ) ); if ( P == NULL ) { printf("\n\npoly megalos pinakas..."); printf("\n\nto programma termatizei...\n\n"); return -1; //srand(time(null)); for (i=0; i<n; i++) P[i] = rand() % 10000; printf("\neisagofi stoixeiou pros anazitisi (0-->9999):"); scanf("%d", &x); Εισαγωγή στο MPI, #1 25 Παράλληλο πρόγραμμα (4 από 7) /* Metafora kommation pinaka sta worker nodes */ ta = MPI_Wtime(); /* arxi metrisis xronou */ part = N / (numprocs - 1); /* Dimioyrgia pinaka ypodoxis apotelesmaton */ R = malloc( (N / part) * sizeof( int ) ); /* Apostoli toy x kai part sta worker nodes */ for (i=1; i<numprocs; i++) MPI_Send(&part, 1, MPI_INT, i, 0, MPI_COMM_WORLD); for (i=1; i<numprocs; i++) MPI_Send(&x, 1, MPI_INT, i, 0, MPI_COMM_WORLD); /* Apostoli merous pinaka sta worker nodes */ // ti ginetai me to teleytaio node? for (i=1; i<numprocs; i++) MPI_Send(&P[(N/(numprocs-1)) * (i-1)], part, MPI_INT, i, 0, MPI_COMM_WORLD); Εισαγωγή στο MPI, #1 26 Παράλληλο πρόγραμμα (5 από 7) /* Lipsi apotelesmaton apo ta worker nodes */ for (i=1; i<numprocs; i++) { MPI_Recv(&R[i-1], 1, MPI_INT, i, i, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("\n\n se anamoni..."); printf("parelifthike %d apo ton %d", R[i-1], i); f += R[i-1]; tt = MPI_Wtime(); /* telos metrisis xronou */ printf("\n\nto %d yparxei ston pinaka %d fores", x, f); printf("\n\nxronos ektelesis: %.16f\n\n", tt-ta); Εισαγωγή στο MPI, #1 27 9
Παράλληλο πρόγραμμα (6 από 7) if (myid!= 0 ) { int *Pw; /* Pinakas ypodoxis sta worker nodes */ int i; int partworker, xw; int fw = 0; MPI_Recv(&partworker, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Recv(&xw, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); /* dimiourgia pinaka ypodoxis */ Pw = malloc( partworker * sizeof( int ) ); Εισαγωγή στο MPI, #1 28 Παράλληλο πρόγραμμα (7 από 7) /* anazitisi - mono apo a worker nodes */ MPI_Recv(&Pw[0], partworker, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); for (i=0; i<partworker; i++) if (Pw[i] == xw ) fw++; /* apostoli sto master node to plithos foron poy vrethike to steixioio */ MPI_Send(&fw, 1, MPI_INT, 0, myid, MPI_COMM_WORLD); MPI_Finalize(); return 0; Εισαγωγή στο MPI, #1 29 Αναζήτηση Απόδοση (1 από 2) Εισαγωγή στο MPI, #1 30 10
Αναζήτηση Απόδοση (2 από 2) Ν (x10,000, 000) /P P=1 P=2 P=3 P=4 P=5 P=6 10 0.291 0.323 0.234 0.195 0.262 0.457 20 0.470 0.642 0.429 0.384 0.427 0.690 30 0.714 1.134 0.636 0.576 0.687 1.207 40 0.998 1.290 0.955 0.758 0.951 1.606 50 1.227 1.590 1.156 0.953 1.180 1.915 60 1.454 1.926 1.364 1.163 1.308 2.145 70 1.652 2.661 1.476 1.334 1.655 2.380 80 1.884 3.538 1.698 1.519 1.910 2.808 90 2.121 4.668 1.903 1.693 2.173 2.939 Εισαγωγή στο MPI, #1 31 Ερωτήσεις; Τέλος της # 02 ενότητας Χρησιμοποιείστε το email για όποιες επιπλέον απορίες / ερωτήσεις: savvas@teilar.gr Σημειώσεις μαθήματος (και όχι μόνο): https://e-class.teilar.gr/courses/cs386/ Εισαγωγή στον παράλληλο προγραμματισμό 32 11