Παιδάκης Θεοδόσης - 1115201500118
Παπαχρήστου Δημήτρης - 1115201500124
1)ΟΔΗΓΊΕΣ ΜΕΤΑΓΛΩΤΙΣΣΗΣ ΚΑΙ ΕΚΤΈΛΕΣΗΣ
MPI version:
$ mpicc -o mpi_convolution mpi_convolution.c $ mpiexec -n [processors] ./mpi_convolution [image.raw] [width] [height] [repetitions] [grey,rgb]
Παράδειγμα: $ mpiexec -n 4 ./mpi_convolution waterfall_1920_2520.raw 1920 2520 40 rgb
OPENMP version:
$ mpicc -openmp -o mpi_convolution mpi_convolution.c $ Ίδιο με του mpi
CUDA version:
$ make $ ./cuda_convolution [image.raw] [width] [height] [repetitions] [grey,rgb]
2) ΠΑΡΑΔΟΧΕΣ
Πρώτο μέλημα μας είναι να σιγουρευτούμε ότι οι τιμές που δόθηκαν στην γραμμή εκτέλεσης ως παράμετροι είναι σωστές. Έπειτα παίρνουμε τις τιμές των μεταβλητών που μας ενδιαφέρουν και τις κάνουμε broadcast(BCAST)
Ανάλογα τον αριθμό των διαθέσιμων διεργασιών που έχουμε, χωρίζουμε την εικόνα σε μέρη (RowsDivision()) και η κάθε διεργασία λαμβάνει και επεξεργάζεται το κομμάτι που της αναλογεί. Αυτό επιταχύνει σημαντικά το πρόγραμμα, μιας και η κάθε διεργασία διαβαζει αποκλειστικά το κομμάτι εικόνας που της αναλογεί.
Η διαδικασία της συνέλιξης όπως είναι φυσικό, διαφέρει ως ένα βαθμό, ανάλογα με το αν η εικόνα είναι grey ή rgb.
Γίνεται χρήση μονοδιάστατου πίνακα, καθώς αποδείχθηκε αποτελεσματικότερος. Ακόμα, με αυτλην την υλοποίηση η διαμέριση διευκολύνεται σημαντικά.
3) ΕΠΙΚΟΙΝΩΝΙΑ ΜΕΤΑΞΥ ΔΙΕΡΓΑΣΙΩΝ
Οι διεργασίες μοιράζονται έτσι στο πλέγμα, ώστε να είναι η μία δίπλα στην άλλη με αύξουσα σειρά. Αυτό διευκολύνει στην ανεύρεση των γειτονικών διεργασιών. Ιδιάιτερη περίπτωση αποτελούν οι διεργασίες που βρίσκονται στην περιφέρεια του πλέγματος. Σε αυτήν την περίπτωση γειτονικές διεργασίες θεωρούνται αυτές που βρίσκονται στην κατάλληλη εκτός ορίων απέναντι πλευρά.
Προχωρώντας τώρα σε θέματα κώδικα σαν επιλογή έχουμε αποφασίσει να χρησιμοποιήσουμε nonblocking αποστολές και λήψεις μηνυμάτων μπορώντας με αυτόν τον τρόπο να κάνουμε συνέλιξη για τα κεντρικά κομμάτια του πίνακα (inner data) και αφήνοντας για αργότερα τον υπολογισμό των περιφερειακών κομματιών(outer and corner data). Αυτό δίνει την δυνατότητα σε μια διεργασία να ασχολείται με μια εργασία όσο περιμένει να έρθουν τα γειτονικά κελιά του πίνακα. Όταν ολοκληρωθεί η εργασία αυτή αν έχουν έρθει τα δεδομένα που περιμένει προχωράει στην εκτέλεση των απαιτούμενων νέων εργασιών αλλιώς εξακολουθεί να περιμένει την λήψη των απαιτούμενων δεδομένων.
Για την αποστολή και την λήψη, αποφασίσαμε να γίνουν με την βοήθεια Datatypes δεδομένων όπου ήταν εφικτό.
Γενικό μοτίβο υλοποίησης:
for loop
ISend
IRecv
Inner Data Computations
Wait(RRecv)
Outer Data Computations
Wait(RSend)
end for
Σκοπός εδώ είναι κομμάτια που εκτελούνται τοπικά, να παραλληλοποιηθούν με τη χρήση thread μέσω του OpenMP, ώστε να βελτιώνεται η ήδη υλοποιημένη εκδοχή του MPI. Συγκεκριμένα στην άσκηση, αλλάχθηκε το σημείο, στο οποίο διατρέχουμε με επανάληψη τον τοπικό πίνακα διεργασίας.
Το πρόγραμμα βασίστηκε στις προηγούμενες υλοποιήσεις (MPI).
Περιληπτική περιγραφή:
Δεσμεύσεις χώρου στην κάρτα γραφικών. Αντιγραφές πινάκων (host -> device και device -> host) Δημιουργία και κλήση της συνάρτησης global Απελευθέρωση δεδομένων (free) Τέλος, οι μετρήσεις έγιναν σε υπολογιστή με λογισμικό Manjaro Linux και κάρτα γραφικών MSI GEFORCE GTX 970 4GB.
Παρατηρώντας το MPI και OpenMP, φαίνεται ότι σε λίγα δεδομένα αρκούν λίγες διεργασίες, γιατι όσο μεγαλώνει ο αριθμός τους, αυξάνει το κόστος κατασκευής τους.
Παρατηρώντας το CUDA, βλέπουμε πως οι χρόνοι αυξάνονται για τα πιο μεγάλα μεγέθη. Αντίθετα, σε χαμηλά μεγέθη πληρώνουμε το κόστος δημιουργίας του thread, μιας και το πρόγραμμα μπορεί να δουλέψει πιο βέλτιστα με λιγότερα.