Non-blocking Επικοινωνίεσ και Buffering Κώςτασ Διαμαντάρασ ΤΕΙ Θεςςαλονίκθσ 2011
Η χριςθ buffer Ροφ πάνε τα δεδομζνα μετά το send? Διεργασία 1 Διεργασία 2 A Buffer Δίκτσο Buffer B 2 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Χωρίσ buffer Διεργασία 1 Διεργασία 2 A Δίκτσο B Δφο επιλογζσ: 1. Το send δεν επιςτρζφει αν δεν παραδοκοφν τα δεδομζνα 2. Το send επιςτρζφει πριν παραδοκοφν τα δεδομζνα. Ζλεγχοσ παράδοςθσ αργότερα 3 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Blocking/non blocking επικοινωνίεσ Μζχρι τώρα είδαμε τθ χριςθ blocking επικοινωνιών: MPI_Send: δεν ολοκλθρώνεται μζχρι ο buffer να αδειάςει (ζτοιμοσ για να ξαναχρθςιμοποιθκεί) MPI_Recv: δεν ολοκλθρώνεται μζχρι ο buffer να γεμίςει (ζτοιμοσ για να χρθςιμοποιθκεί) Non-blocking επικοινωνίεσ: MPI_Isend MPI_Irecv 4 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Non-blocking επικοινωνίεσ Οι non-blocking λειτουργίεσ επιςτρζφουν αμζςωσ «request handles». Μια διεργαςία μπορεί να κάνει ερώτθςθ (query) ι αναμονι (wait) ςε ζνα request. MPI_Isend(start, count, datatype, dest, tag, comm, request) MPI_Irecv(start, count, datatype, dest, tag, comm, request) MPI_Wait(request, status) Ζλεγχοσ (test) χωρίσ wait: MPI_Test( request, flag, status) 5 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Isend Ξεκινάει ζνα non-blocking send #include "mpi.h" int MPI_Isend( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request ) Παράμετροι Εισόδου buf = αρχικι διεφκυνςθ του send buffer count = πλικοσ ςτοιχείων ςτον send buffer datatype = τφποσ δεδομζνων των ςτοιχείων του send buffer dest = rank του προοριςμοφ tag = tag του μθνφματοσ comm = communicator Παράμετροι Εξόδου request = communicator request 6 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Irecv non-blocking receive #include "mpi.h" int MPI_Irecv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request ) Παράμετροι Εισόδου buf = αρχικι διεφκυνςθ του receive buffer count = πλικοσ ςτοιχείων ςτον receive buffer datatype = τφποσ δεδομζνων των ςτοιχείων του buffer source = rank αποςτολζα tag = tag μθνφματοσ comm = communicator Παράμετροι Εξόδου request = communication request 7 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Wait Αναμζνει τθν ολοκλιρωςθ ενόσ non-blocking read ι write int MPI_Wait(MPI_Request *request, MPI_Status *status) Παράμετροι Εισόδου request = αίτθςθ επικοινωνίασ Παράμετροι Εξόδου status = αντικείμενο status 8 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Test Ελζγχει τθν ολοκλιρωςθ ενόσ non-blocking read ι write int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) Παράμετροι Εισόδου request = αίτθςθ επικοινωνίασ Παράμετροι Εξόδου flag = true αν θ λειτουργία ολοκλθρώκθκε status = αντικείμενο status 9 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Ρολλαπλζσ αναμονζσ Είναι ςυχνά επικυμθτό να περιμζνουμε τθν ολοκλιρωςθ πολλών request. Ρχ. ςε ζνα περιβάλλον master/slave, ο master περιμζνει ζνα ι περιςςότερουσ slaves να του ςτείλουν μινυμα. MPI_Waitall(count, array_of_requests, array_of_statuses) MPI_Waitany(count, array_of_requests, index, status) MPI_Waitsome(incount, array_of_requests, outcount, array_of_indices, array_of_statuses) 10 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Waitall Ρεριμζνει όλεσ τισ δοςμζνεσ επικοινωνίεσ να ολοκλθρωκοφν #include "mpi.h" int MPI_Waitall( int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[] ) Παράμετροι Εισόδου count = μικοσ λίςτασ array_of_requests = array αιτιςεων επικοινωνίασ Παράμετροι Εξόδου array_of_statuses = πίνακασ αντικειμζνων status 11 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Waitany Ρεριμζνει κάποια από τισ δοςμζνεσ επικοινωνίεσ να ολοκλθρωκεί #include "mpi.h" int MPI_Waitany( int count, MPI_Request array_of_requests[], int *index, MPI_Status *status ) Παράμετροι Εισόδου count = μικοσ λίςτασ array_of_requests = array αιτιςεων επικοινωνίασ Παράμετροι Εξόδου index = δείκτθσ τθσ αιτιςεωσ που ολοκλθρώκθκε (μεταξφ 0 και count- 1). status = αντικείμενο status 12 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Waitsome Ρεριμζνει κάποιεσ από τισ δοςμζνεσ επικοινωνίεσ να ολοκλθρωκοφν #include "mpi.h" int MPI_Waitsome( int incount, MPI_Request array_of_requests[], int *outcount, int array_of_indices[], MPI_Status array_of_statuses[] ) Παράμετροι Εισόδου incount = μικοσ array_of_requests array_of_requests = array αιτιςεων επικοινωνίασ Παράμετροι Εξόδου outcount = πλικοσ ολοκλθρωμζνων requests array_of_indices = πίνακασ δεικτών ολοκλθρωμζνων requests array_of_statuses = πίνακασ αντικειμζνων status 13 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Γιατί non-blocking επικοινωνίεσ? Πταν ο χρόνοσ επικοινωνίασ είναι μεγάλοσ τον εκμεταλλευόμαςτε κάνοντασ υπολογιςμοφσ. Ρχ. ςε ζνα 2-Δ πλζγμα, θ μετακίνθςθ δεδομζνων ςτα όρια του πλζγματοσ γίνεται παράλλθλα με πράξεισ ςτο εςωτερικό MPI_Irecv(... each edge... ); MPI_Isend(... data for each edge... );... compute on interior while (still some uncompleted requests) { MPI_Waitany(... requests... ) if (request is a receive)... compute on that edge... } 14 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Δίκαιθ κατανομι επικοινωνιών: Ρρόβλθμα (1) #include "mpi.h" #include <stdio.h> int main(argc, argv) int argc; char **argv; { int rank, size, i, buf[1]; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); 15 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Δίκαιθ κατανομι επικοινωνιών: Ρρόβλθμα (2) if (rank == 0) { for (i=1; i<size; i++) { for (j=0; j<100; j++) { MPI_Recv( buf, 1, MPI_INT, i, MPI_ANY_TAG, MPI_COMM_WORLD, &status ); printf( "Msg from %d with tag %d\n", status.mpi_source, status.mpi_tag ); } } } else { for (i=0; i<100; i++) MPI_Send( buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD ); } MPI_Finalize(); } 16 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Δίκαιθ κατανομι επικοινωνιών: Μια λφςθ #define large 128 MPI_Request requests[large]; MPI_Status statuses[large]; int indices[large]; int buf[large]; for (i=1; i<size; i++) MPI_Irecv( buf+i, 1, MPI_INT, i, MPI_ANY_TAG, MPI_COMM_WORLD, &requests[i-1] ); while(not done) { MPI_Waitsome( size-1, requests, &ndone, indices, statuses ); for (i=0; i<ndone; i++) { j = indices[i]; printf( "Msg from %d with tag %d\n", statuses[i].mpi_source, statuses[i].mpi_tag ); MPI_Irecv( buf+j, 1, MPI_INT, j, MPI_ANY_TAG, MPI_COMM_WORLD, &requests[j] ); } } 17 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
Τρόποι επικοινωνιών Το MPI προςφζρει πολλοφσ τρόπουσ (modes) αποςτολισ μθνυμάτων: Σφγχρονοσ τρόποσ ( MPI_Ssend): Το send δεν ολοκλθρώνεται μζχρι να εκκινιςει ζνα ταιριαςτό receive. Buffered τρόποσ ( MPI_Bsend): ο χριςτθσ ορίηει τον buffer για να χρθςιμοποιθκεί από το ςφςτθμα. Ready τρόποσ ( MPI_Rsend): ο χριςτθσ εγγυάται ότι ζνα ταιριαςτό receive ζχει ιδθ εκκινιςει. Επιτρζπει γριγορα πρωτόκολλα επικοινωνίασ Απροςδιόριςτθ ςυμπεριφορά αν το receive δεν ζχει εκκινιςει Non-blocking εκδοχζσ: MPI_Issend, MPI_Irsend, MPI_Ibsend Το MPI_Recv λαμβάνει μθνφματα ςταλμζνα με οποιοδιποτε τρόπο send. 18 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Bsend Βαςικό send με user-specified buffering #include "mpi.h" int MPI_Bsend( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm ) Παράμετροι Εισόδου buf = αρχικι διεφκυνςθ του send buffer count = πλικοσ ςτοιχείων ςτον send buffer datatype = τφποσ δεδομζνων των ςτοιχείων του send buffer dest = rank του προοριςμοφ tag = tag του μθνφματοσ comm = communicator Παράμετροι Εξόδου - 19 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Bsend (ςυν.) Τοπικι εκτζλεςθ: θ ολοκλιρωςθ τθσ εντολισ δεν εξαρτάται από το αν ζχει εκδοκεί ζνα αντίςτοιχο ταιριαςτό receive. Αν ξεκινιςει ζνα Bsend και δεν ζχει εκδοκεί αντίςτοιχο ταιριαςτό receive από τον παραλιπτθ θ διεργαςία πρζπει να βάλει το μινυμα ςτον buffer. Ο χριςτθσ ορίηει ο ίδιοσ χώρο buffer με MPI_Buffer_attach. Ο χώροσ buffer δεν είναι διακζςιμοσ για επόμενο MPI_Bsend εκτόσ αν λθφκεί το μινυμα. Ανά πάςα χρονικι ςτιγμι μπορεί να υπάρχει μόνο ζνασ buffer. Ρρζπει να προβλεφκεί να είναι αρκετά μεγάλοσ ώςτε να χωράει το ι τα μθνφματα που δεν ζχουν ταιριαςτό receive. Σε αντίκετθ περίπτωςθ προκφπτει ςφάλμα. 20 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης
MPI_Bsend (ςυν.) Ο παρακάτω κώδικασ δε δίνει αρκετό χώρο buffer. Χώροσ buffer για ζνα μόνο send. Το επόμενο MPI_Bsend μπορεί να ξεκινιςει πριν τελειώςει το πρώτο MPI_Bsend τθ χριςθ του buffer. MPI_Buffer_attach( b, n*sizeof(double) + MPI_BSEND_OVERHEAD ); for (i=0; i<m; i++) { MPI_Bsend( buf, n, MPI_DOUBLE,... ); } Μποροφμε να εξαναγκάςουμε τα μθνφματα να παραδοκοφν MPI_Buffer_detach( &b, &n ); MPI_Buffer_attach( b, n ); (Η MPI_Buffer_detach δε κα ολοκλθρωκεί μζχρι όλα τα buffered μθνφματα να παραδοκοφν.) 21 Κ. Διαμαντάρας ΤΕΙ Θεσσαλονίκης