Προγραμματισμός Συστημάτων Υψηλών Επιδόσεων (ΗΥ421) Εργασία Εξαμήνου

Σχετικά έγγραφα
Προγραμματισμός Συστημάτων Υψηλών Επιδόσεων (ΗΥ421) 3η Εργαστηριακή Άσκηση

Πανεπιστήμιο Θεσσαλίας Τμήμα Μηχανικών Η/Υ, Τηλεπικοινωνιών και Δικτύων

Συστήματα μνήμης και υποστήριξη μεταφραστή για MPSoC

ΣΥΣΤΗΜΑΤΑ ΠΑΡΑΛΛΗΛΗΣ ΕΠΕΞΕΡΓΑΣΙΑΣ 9o εξάμηνο ΗΜΜΥ, ακαδημαϊκό έτος

ΕΘΝΙΚΟ ΚΑΙ ΚΑΠΟΔΙΣΤΡΙΑΚΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΘΗΝΩΝ

ΠΡΟΗΓΜΕΝΟΙ ΜΙΚΡΟΕΠΕΞΕΡΓΑΣΤΕΣ PROJECT 2: MEMORY MANAGEMENT

Παράλληλος προγραμματισμός σε επεξεργαστές γραφικών

Παράλληλος Προγραμματισμός σε Επεξεργαστές Γραφικών

CUDA Compute Unified Device Architecture

Παράλληλος Προγραμματισμός σε Επεξεργαστές Γραφικών

Είναι το «μυαλό» του υπολογιστή μας. Αυτός κάνει όλους τους υπολογισμούς και τις πράξεις. Έχει δική του ενσωματωμένη μνήμη, τη λεγόμενη κρυφή

Παράλληλος Προγραμματισμός σε Επεξεργαστές Γραφικών

Οργάνωση επεξεργαστή (2 ο μέρος) ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική

lab13grades Άσκηση 2 -Σωστά απελευθερώνετε ολόκληρη τη λίστα και την κεφαλή

Αποθήκευση εδομένων. ομή ενός Σ Β. Εισαγωγή Το «εσωτερικό» ενός ΜΕΡΟΣ Β : Η (εσωτερική) αρχιτεκτονική ενός Σ Β είναι σε επίπεδα

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΘΕΜΑ PROJECT COMPILER FLAGS ΤΡΑΧΑΝΗΣ ΔΗΜΗΤΡΗΣ 6108 ΤΡΑΧΑΝΗΣ ΓΕΩΡΓΙΟΣ 5789

i Throughput: Ο ρυθμός ολοκλήρωσης έργου σε συγκεκριμένο χρόνο

Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών Κρυφές Μνήμες. (οργάνωση, λειτουργία και απόδοση)

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ

Παράλληλος Προγραμματισμός σε Επεξεργαστές Γραφικών

Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών Απόδοση ΚΜΕ. (Μέτρηση και τεχνικές βελτίωσης απόδοσης)

Πανεπιστήμιο Πειραιώς Τμήμα Πληροφορικής Πρόγραμμα Μεταπτυχιακών Σπουδών «Πληροφορική»

Προγραμματισμός Η/Υ (ΤΛ2007 )

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ. Άσκηση 5: Παράλληλος προγραμματισμός σε επεξεργαστές γραφικών

SMPcache. Ένα εργαλείο για προσομοίωση-οπτικοποίηση κρυφής μνήμης (Cache)

Στοιχεία από την αρχιτεκτονική των μικροϋπολογιστών

Ασκήσεις Caches

Ασκήσεις Caches

Άσκηση 1η. Θεωρήστε ένα σύστημα μνήμης με μία cache: 4 way set associative μεγέθους 256ΚΒ,

ΕΙΔΙΚΟΤΗΤΑ: ΤΕΧΝΙΚΟΣ ΕΦΑΡΜΟΓΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΜΑΘΗΜΑ: ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΗ

Οργάνωση Υπολογιστών (ΙI)

Ιεραρχία Μνήμης. Ιεραρχία μνήμης και τοπικότητα. Σκοπός της Ιεραρχίας Μνήμης. Κρυφές Μνήμες

Μάθημα 3: Αρχιτεκτονική Υπολογιστών

Λειτουργικά Συστήματα. Τ.Ε.Ι. Ιονίων Νήσων Σχολή Διοίκησης και Οικονομίας - Λευκάδα

Προγραμματισμός συστημάτων UNIX/POSIX. Θέμα επιλεγμένο από τους φοιτητές: Προγραμματιστικές τεχνικές που στοχεύουν σε επιδόσεις

Το υλικό του υπολογιστή

Λιβανός Γιώργος Εξάμηνο 2017Β

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ

CloudBox!: Ένα εργαλείο cloud αποθήκευσης αρχείων με κατανεμημένο τρόπο

All Pairs Shortest Path

Κύρια μνήμη. Μοντέλο λειτουργίας μνήμης. Ένα τυπικό υπολογιστικό σύστημα σήμερα. Οργάνωση Υπολογιστών (ΙI)

Ανάπτυξη αλγόριθμου Closest Pair με CUDA API

ΚΕΦΑΛΑΙΟ 2: Χειρισµός εδοµένων

Ασκήσεις Caches. Αρχιτεκτονική Υπολογιστών. 5ο εξάμηνο ΣΗΜΜΥ ακ. έτος: Νεκ. Κοζύρης

Εισαγωγικά & Βασικές Έννοιες

Προγραμματισμός Ι (HY120)

Ασκήσεις στα Προηγμένα Θέματα Αρχιτεκτονικής Υπολογιστών

Ζητήµατα Απόδοσης. Ιεραρχία Μνήµης. Αναγκαιότητα για Ιεραρχία Μνήµης. Processor-DRAM Gap (latency) Ε-85: Ειδικά Θέµατα Λογισµικού

Τμήμα Λογιστικής. Εισαγωγή στους Ηλεκτρονικούς Υπολογιστές. Μάθημα 8. 1 Στέργιος Παλαμάς

Επιπλέον διδακτικό υλικό κρυφών μνημών: set-associative caches, πολιτικές αντικατάστασης, χειρισμός εγγραφών

ΥΠΟΥΡΓΕΙΟ ΠΑΙΔΕΙΑΣ ΚΑΙ ΠΟΛΙΤΙΣΜΟΥ ΔΙΕΥΘΥΝΣΗ ΑΝΩΤΕΡΗΣ ΚΑΙ ΑΝΩΤΑΤΗΣ ΕΚΠΑΙΔΕΥΣΗΣ ΥΠΗΡΕΣΙΑ ΕΞΕΤΑΣΕΩΝ ΠΑΓΚΥΠΡΙΕΣ ΕΞΕΤΑΣΕΙΣ 2012

Μάθημα 4: Κεντρική Μονάδα Επεξεργασίας

Διαφορές single-processor αρχιτεκτονικών και SoCs

Εικονικοποίηση. Λειτουργικά Συστήματα Υπολογιστών 7ο Εξάμηνο,

Εικονική Μνήμη (Virtual Μemory)

Το ολοκληρωμένο κύκλωμα μιας ΚΜΕ. «Φέτα» ημιαγωγών (wafer) από τη διαδικασία παραγωγής ΚΜΕ

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ ΣΧΟΛΗ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΜΗΧΑΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΤΟΜΕΑΣ ΤΕΧΝΟΛΟΓΙΑΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ

Προγραμματισμός Η/Υ (ΤΛ2007 )

Πολυπύρηνοι επεξεργαστές Multicore processors

Πανεπιστήµιο Θεσσαλίας Τµήµα Μηχανικών Η/Υ, Τηλεπικοινωνιών και ικτύων

Πανεπιστήμιο Θεσσαλίας Τμήμα Ηλεκτρολόγων Μηχανικών & Μηχανικών Υπολογιστών

Λειτουργικά Συστήματα (ΗΥ321)

Οργάνωση και Αρχιτεκτονική Υπολογιστών. Κεφάλαιο 7.4

Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών H/Y Department of Electrical and Computer Engineering. Εργαστήριο 8. Χειμερινό Εξάμηνο

ΘΕΜΑ : ΗΛΕΚΤΡΟΝΙΚΗ ΜΝΗΜΗ ΚΑΙ ΜΙΚΡΟΕΛΕΓΚΤΕΣ. ΔΙΑΡΚΕΙΑ: 1 περίοδος

Πίνακες. 1 Πίνακες. 30 Μαρτίου 2014

Σχεδίαση Γλωσσών Προγραμματισμού. Εαρινό Εξάμηνο Lec03 18/02/2019

Αρχιτεκτονική υπολογιστών

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΠΟΛΥΤΕΧΝΙΚΗ ΣΧΟΛΗ ΤΜΗΜΑ ΜΗΧΑΝΙΚΩΝ Η/Υ ΤΗΛΕΠΙΚΟΙΝΩΝΙΩΝ ΚΑΙ ΔΙΚΤΥΩΝ. Διπλωματικη Εργασια. Γεωργία Ε. Κρόκου

Μεταγλωττιστές. Γιώργος Δημητρίου. Μάθημα 12 ο. Πανεπιστήμιο Θεσσαλίας - Τμήμα Ηλεκτρολόγων Μηχανικών & Μηχανικών Υπολογιστών

Υπάρχουν δύο τύποι μνήμης, η μνήμη τυχαίας προσπέλασης (Random Access Memory RAM) και η μνήμη ανάγνωσης-μόνο (Read-Only Memory ROM).

Ο Σ ο β ι ε τ ι κ ό ς Κ ρ υ π τ α λ γ ό ρ ι θ μ ο ς G O S T

Δομημένος Προγραμματισμός (ΤΛ1006)

3 η ΑΣΚΗΣΗ. Προηγμένα Θέματα Αρχιτεκτονικής Υπολογιστών

Εισαγωγικά & Βασικές Έννοιες

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ ΣΧΟΛΗ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΜΗΧΑΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΤΟΜΕΑΣ ΤΕΧΝΟΛΟΓΙΑΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ

Δομημένος Προγραμματισμός (ΤΛ1006)

Στοιχειώδης προγραμματισμός σε C++

Master Mind εφαρμογή στη γλώσσα προγραμματισμού C

Μικροεπεξεργαστές. Σημειώσεις Μαθήματος Υπεύθυνος: Δρ Άρης Παπακώστας,

Κεφάλαιο 1.6: Συσκευές αποθήκευσης

Ανάλυση Επιδόσεων Συστημάτων Πραγματικού Χρόνου

Αρχιτεκτονική Μνήμης

ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ ΣΧΟΛΗ ΗΛΕΚΤΡΟΛΟΓΩΝ ΜΗΧΑΝΙΚΩΝ ΚΑΙ ΜΗΧΑΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΤΟΜΕΑΣ ΤΕΧΝΟΛΟΓΙΑΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΥΠΟΛΟΓΙΣΤΩΝ

Προβλήματα ταυτόχρονης εκτέλεσης (για νήματα με κοινή μνήμη)

Κεφάλαιο 4 ο. Ο Προσωπικός Υπολογιστής

Αρχιτεκτονική Επεξεργαστών Ψ.Ε.Σ

Προγραμματισμός GPUs μέσω του περιβάλλοντος CUDA

Ταχύτερα compile με ccache και distcc

ΤΜΗΜΑΤΑ ΗΛΕΚΤΡΟΝΙΚΟΥ ΥΠΟΛΟΓΙΣΤΗ

Συστήματα Παράλληλης και Κατανεμημένης Επεξεργασίας

ΕΦΑΡΜΟΓΕΣ ΠΛΗΡΟΦΟΡΙΚΗΣ. Α Γενικού Λυκείου (Μάθημα Επιλογής)

Αρχιτεκτονική υπολογιστών

Η ιεραρχία της μνήμης

Αρχιτεκτονική Υπολογιστών II Ενδεικτικές απαντήσεις στα θέματα των εξετάσεων

Υποστήριξη Λ.Σ. ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική

Λειτουργικά συστήµατα. Λογισμικό Συστήματος 1

Κατανεμημένα Συστήματα

Το εσωτερικό ενός PC. Τεχνολογία Η/Υ & Πληροφοριών - 05 Κεντρική μονάδα Χουρδάκης Μανόλης

Transcript:

Προγραμματισμός Συστημάτων Υψηλών Επιδόσεων (ΗΥ421) Εργασία Εξαμήνου ΟΜΑΔΑ: Ιωαννίδης Σταύρος ΑΕΜ: 755 Ντελής Γιώργος ΑΕΜ: 726 Επιλογή της Εργασίας Για την εργασία μας επιλέξαμε την βελτιστοποίηση της απόδοσης, με εκτέλεση τμημάτων κώδικα σε GPU, του kernel FFT από την σουίτα παραλλήλων benchmarks splash2. Ο κώδικας του FFT εφαρμόζει τον αλγόριθμο του Fast Fourier Tranform πάνω σε πίνακα που περιέχει ψευδοτυχαίους αριθμούς. Χρησιμοποιήσαμε την παράλληλη υλοποίηση του κώδικα. Για να έχουμε έναν αισθητό χρόνο εκτέλεσης, εκτελέσαμε τον FFT με παράμετρο m=26 που ορίζει την τάξη μεγέθους του προβλήματος. Τις λοιπές παραμέτρους τις αφήσαμε στις προεπιλεγμένες τους τιμές. Για ένα νήμα (p=1) πήραμε συνολικό χρόνο εκτέλεσης 17,6sec. Στις περιοδικές μας μετρήσεις χρησιμοποιήσαμε (για τον nvcc) βαθμό βελτιστοποιήσεων -Ο4 διότι έδωσε ελάχιστα ταχύτερη εκτέλεση από τις άλλες επιλογές. Επίσης για να έχουμε μια καλύτερη εικόνα των επιπτώσεων που έχουν οι αλλαγές μας στον χρόνο εκτέλεσης: 1. απενεργοποιήσαμε τις L1 και L2 caches 2. πήραμε τοπικές μετρήσει χρόνου με gettimeofday (αντί του συνολικού χρόνου εκτέλεσης) 3. προσθέσαμε dummy kernel ο χρόνος του οποίου κυμαίνεται από 200ms μέχρι 500ms. Μετά από κάθε μας αλλαγή στον κώδικα ελέγξαμε την ορθότητα των αποτελεσμάτων με την χρήση του μηχανισμού checksum testing που υπήρχε στον κώδικα (επιλογή -t κατά την εκτέλεση). Για μεγαλύτερη σιγουριά βάλαμε τον αντίστροφο FFT (όπου direction=-1) που χρησιμοποιείται στο testing, να γίνεται πάντα στην CPU. Χαρακτηριστικά της GPU μας (devicequery) Για την ανάπτυξη της εργασίας μας χρησιμοποιήσαμε τον inf-zeus1 και την GeForce GTX 480 τα χαρακτηριστικά της οποίας είναι:

Profiling Το VTUNE έδειξε την FFD1DOnce (55% του χρόνου εκτέλεσης) και την Transpose (38%) ως τις πιο αργές συναρτήσεις: Το GPROF έδειξε και το πλήθος των εκτελέσεων για κάθε μια από αυτές τις συναρτήσεις όπως φαίνεται στο παρακάτω σχήμα που πήραμε με το gprof2dot: Compile με NVCC Για την μεταγλώττιση με nvcc χρησιμοποιήσαμε τα αρχικά Makefiles και φτιάξαμε το παραδοτέο Makefile, στο οποίο θα πρέπει να τροποποιηθεί κατάλληλα το path του BASEDIR ώστε να δείχνει στον φάκελο splash2. Η εκτέλεση γίνεται δίνοντας:./fft -m26 -p1 -n65536 -l4 Ο τροποποιημένος κώδικάς μας βρίσκεται στο αρχείο fft.c. Για την μεταγλώττιση και εκτέλεση του αρχικού κώδικα του fft μετονομάστε το αρχείο original_fft_code_dot_c σε fft.c.

Port σε GPU της πιο αργής συνάρτησης: FFD1DOnce Ξεκινώντας με την FFD1DOnce που είναι και η πιο αργή συνάρτηση του κώδικα, παρατηρήσαμε ότι υπάρχουν 2 for μέσα από τα οποία καλείται συνολικά 2*8192 φορές (μέσα στο σώμα της συνάρτησης FFT1D): Αν τρέξουμε με ένα νήμα τότε αυτό αναλαμβάνει και τις 2*8192 εκτελέσεις και επεξεργάζεται όλον τον πίνακα εισόδου, ενώ με περισσότερα κάθε νήμα αναλαμβάνει την επεξεργασία ενός μόνο τμήματος του αρχικού πίνακα (π.χ. Για 4 νήματα το κάθε νήμα εκτελεί 2048 φορές την FFD1DOnce σε κάθε for). Η επεξεργασία αυτή του κάθε νήματος γίνεται παράλληλα οπότε η πρώτη μας κίνηση ήταν η μετατροπή της συνάρτησης FFD1DOnce σε global και η εκτέλεσή της σε GPU με 8192 threads, με κάθε thread να αναλαμβάνει την δουλειά μίας μόνο εκτέλεσης της FFD1DOnce: Έτσι αντικαταστήσαμε αρχικά μόνο το πρώτο for με αυτόν τον kernel, κάνοντας φυσικά και τις απαραίτητες δεσμεύσεις/αποδεσμεύσεις και μεταφορές μνήμης. Οι πρώτες μετρήσεις στον χρόνο εκτέλεσης έδειξαν: CudaMalloc 0,3 CudaFree 13 CudaMemcpy to Device 341 CudaMemcpy to Host 324 CudaMemcpy Total 665 FFD1DOnce on GPU 2567 1000 FFD1DOnce on CPU 5497 0 Speedup 1,7x on GPU on CPU *οι χρόνοι είναι σε msec *στον υπολογισμό του speedup περιλαμβάνεται ο χρόνος εκτέλεσης σε GPU και ο χρόνο μεταφοράς δεδομένων από και προς αυτήν ενώ δεν περιλαμβάνεται ο χρόνος δέσμευσης/αποδέσμευσης μνήμης Για την αντικατάσταση και του δεύτερου for που καλεί την FFT1DOnce με τον παραπάνω kernel, θα πρέπει να μεταφέρουμε στην device τον πίνακα x. Για να γλιτώσουμε τις περιττές δεσμεύσεις και αποδεσμεύσεις μνήμης και μιας και οι πίνακες scratch και x είναι ίδιου μεγέθους, απλά θα χρησιμοποιήσουμε τον χώρο που ήδη είχαμε δεσμεύσει με cudamalloc για τον scratch, αλλά αυτή την φορά θα τοποθετήσουμε εκεί τα δεδομένα του x. Οι χρόνοι για τον δεύτερο kernel είναι: Χρόνος σε msec 6000 5000 4000 3000 2000 execution memory transfers CudaMemcpy to Device 341 CudaMemcpy to Host 324 CudaMemcpy Total 665 FFD1DOnce on GPU 2561 FFD1DOnce on CPU 2640 Speedup 0,818x Χρόνος σε msec 3500 3000 2500 2000 1500 1000 500 0 on GPU on CPU execution memory transfers

Παρά το γεγονός ότι ο χρόνος εκτέλεσης χειροτερεύει, θα κρατήσουμε την αλλαγή αυτή διότι είναι πολύ πιθανό ο χρόνος να βελτιωθεί αρκετά στην συνέχεια και να δώσει speedup μεγαλύτερο του 1x. Λόγω των πολλών καταχωρητών που χρησιμοποιεί η FFD1DOnce αλλά και λόγο του ότι δεν γίνεται κάποια προφανής εκμετάλλευση της block-wise αρχιτεκτονικής της GPU, δοκιμάσαμε διάφορες διαστάσεις για τα blocks και ταχύτερη αποδείχθηκε η 64 threads ανά block. Παρατηρούμε πως αρκετός χρόνος ξοδεύεται στα memory transfers διότι ο πίνακας scratch που χρειάζεται η FFD1Donce είναι λίγο μεγαλύτερος από 1GB. Πέρα από τον scratch, υπάρχουν άλλοι δύο πίνακες του ίδιου μεγέθους οι x και umain2 που χρησιμοποιούνται στην FFD1D. Παρακάτω φαίνονται πιο αφαιρετικά οι συναρτήσεις με τη σειρά που καλούνται από την FFD1D καθώς και ποιοι από τους 3 αυτούς (μεγάλους) πίνακες (scratch, x και umain2) χρειάζεται η κάθε μια: FFD1D: Transpose(... x, scratch,... ); FFT1DOnce(... scratch,...); TwiddleOneCol(... umain2, scratch,... ); Transpose(... scratch, x,... ); FFT1DOnce(... x,... ); Scale(... x,...); Transpose(... x, scratch,... ); CopyColumn(... scratch, x,... ); Όπως είναι λογικό, κάθε κλήση της FFD1DOnce απαιτεί 2 μεταφορές της τάξης του 1GB: μια του πίνακα εισόδου προς την device πριν την κλήση και μια του τροποποιημένου πίνακα προς τον host μετά την κλήση. Ακόμα και αν τρέχαμε στην GPU όλες τις ενδιάμεσες συναρτήσεις που περιλαμβάνονται μεταξύ των δύο κλήσεων της FFD1DOnce αποφεύγοντας της ενδιάμεσες περιττές μεταφορές, δεν θα ήταν δυνατόν να έχουμε και τους τρεις αυτούς πίνακες αποθηκευμένους στην global memory την ίδια χρονική στιγμή μιας και ξεπερνούν τα 3GB συνολικά (ενώ η device έχει μόνο 1,5GB). Συνεπώς τα περιττά memory transers δεν γίνεται να αναληφθούν στην παρούσα φάση. Μετατροπή από double σε single precision Μια δοκιμή που κάναμε ήταν η χρήση float αριθμών αντί για doubles που χρησιμοποιούνταν στην αρχική υλοποίηση του FFT. Εκτελώντας για διάφορες τιμές της παραμέτρου m, και ενεργοποιώντας την λειτουργία του checksum testing, είδαμε πως το μεγαλύτερο checksum difference που πήραμε ήταν 2 για m=24 (διαφορά στα checksums μικρότερη του 0,000001%) το οποίο θα μπορούσαμε να το θεωρήσουμε αμελητέο. Οι επιπτώσεις της χρήσης των floats στον χρόνο εκτέλεσης ήταν θετικές, αφού ο χρόνος δέσμευσης μνήμης μειώθηκε κατά 25% και ο χρόνος μεταφορών κατά 50%, αποτέλεσμα λογικό αφού πλέον μεταφέρεται ακριβώς η μισή ποσότητα δεδομένων από πριν. Ο χρόνος της global FFD1DOnce μειώθηκε ελάχιστα από 2,56sec σε 2,50sec. Στην προσπάθειά μας να ερμηνεύσουμε την τόσο μικρή βελτίωση στον χρόνο εκτέλεσης, καταλήξαμε στο συμπέρασμα ότι οι Fermi αρχιτεκτονικές υποστηρίζουν πλήρως double precision πράξεις, ο χρόνος εκτέλεσης των οποίων είναι παραπλήσιος αυτού των single precision. Μετά τις αναβαθμίσεις μάλιστα του λογισμικού που έγιναν στον inf-zeus1 τον Αύγουστο, δεν είναι καν απαραίτητη η χρήση της παραμέτρου -arch=sm_11 κατά την μεταγλώττιση (με nvcc) κώδικα που περιέχει double precision πράξεις.

Βελτισποποιήσεις σχετικές με off-chip memory Η χρήση των floats έδωσε χώρο για περισσότερες βελτιστοποιήσεις. Παρατηρούμε πως ο πίνακας upriv που χρησιμοποιεί η FFT1DOnce έχει τώρα μέγεθος 64ΚΒ και επίσης δεν τροποποιείται από την συνάρτηση (είναι δηλαδή read-only). Για τον λόγο αυτό δοκιμάσαμε να τον τοποθετήσουμε στην constant memory της device. Πήραμε μια μικρή βελτίωση που φαίνεται στους παρακάτω χρόνους: Πίνακας upriv στην Global Memory Constant Memory Εκτέλεση 1η 2η Σύνολο 1η 2η Σύνολο CudaMemcpy to Device 170 170 340 170 170 340 CudaMemcpy to Host 162 162 324 162 162 324 CudaMemcpy Total 332 332 664 332 332 664 FFD1DOnce on GPU 2502 2513 5015 2260 2255 4515 FFD1DOnce on CPU 5497 2640 8137 5497 2640 8137 Speedup 1,94x 0,93x 1,43x 2,12x 1,02x 1,57x Βελτιστοποιήσεις σχετικές με on-chip memory Στην προσπάθειά μας να εκμεταλλευτούμε την shared memory της device, παρατηρήσαμε ότι κάθε thread μπορεί να προσπελάσει κάποιες θέσεις του πίνακα εισόδου της FFD1DOnce, μέσα σε ένα φάσμα 64KB: το οποίο είναι αρκετά μεγάλο για να χωρέσει στην shared memory κάθε block. Ακόμα όμως και αν η shared memory ήταν αρκετά μεγάλη (πιθανώς σε μελλοντικές κάρτες γραφικών) δεν θα ήταν σοφό να την χρησιμοποιήσουμε αφού τα threads ενός block θα έπρεπε να φέρουν (συνεργατικά) στην shared αυτά τα 64ΚΒ ενώ μπορεί να χρησιμοποιήσουν πολύ πολύ λιγότερα. Ακόμα λόγω της παράλληλης υλοποίησης του FFT, κάθε thread πειράζει διαφορετικές θέσεις του πίνακα εισόδου οπότε κάθε byte από αυτά τα 64ΚΒ θα μπορεί να προσπελαστεί το πολύ μια φορά και από ένα μόνο thread. Το μόνο που μπορούμε να κάνουμε για να εκμεταλλευτούμε κάποια on-chip memory είναι στο τέλος όλων των βελτιστοποιήσεων μας, να ενεργοποιήσουμε το caching και να δώσουμε περισσότερο χώρο στην L1 cache.

Βελτιστοποιήσεις της global FFD1DOnce Το πρώτο που κοιτάξαμε στην υλοποίηση της global FFD1DOnce ήταν η χρήση καταχωρητών για την αποθήκευση δεδομένων που διαβάζονται από την global memory και χρησιμοποιούνται περισσότερες από μια φορές, όμως αυτό ήταν ήδη υλοποιημένο στον αρχικό κώδικα του FFT. Αντικαταστήσαμε τις πολλαπλές και χρονοβόρες πράξεις πολλαπλασιασμού και διαίρεσης με ολισθήσεις, όπου αυτό ήταν δυνατόν. Πήραμε μια μικρή βελτίωση στον χρόνο εκτέλεσης του kernel από 2,26sec σε 2,24sec. Port σε GPU της 2ης πιο αργής συνάρτησης: Transpose Μετά την αλλαγή σε floats, κάθε ένας από τους πίνακες scratch, x και umain2 έχει το μισό μέγεθος από πριν δηλαδή λίγο περισσότερο από 0,5GB. Τώρα μπορούμε να έχουμε δύο από αυτούς τους πίνακες αποθηκευμένους στην device την ίδια χρονική στιγμή. Αυτό μας επιτρέπει να προχωρήσουμε στην μετατροπή και εκτέλεση στην GPU συναρτήσεων που χρησιμοποιούν δύο από αυτούς τους πίνακες. Επιλέξαμε να κάνουμε global την συνάρτηση Transpose διότι είναι η δεύτερη πιο αργή συνάρτηση και καταλαμβάνει ένα σημαντικό ποσοστό του χρόνου εκτέλεσης. Η χωρισμός του νέου μας kernel σε blocks είναι ίδιος με πριν δηλαδή 64 threads ανά block. Δοκιμάσαμε να αντικαταστήσουμε με τον νέο μας kernel τις δύο πρώτες φορές που καλείται η Transpose ενώ αφήσαμε την τρίτη της εκτέλεση να γίνεται στην CPU. Παρατηρήσαμε πως κατά την πρώτη κλήση της Transpose ο πίνακας scratch είναι μηδενισμένος, συνεπώς για να γλιτώσουμε την μεταφορά, μετά την δέσμευσή του χρησιμοποιήσαμε την cudamemset για να τον μηδενίσουμε στην device. Επειδή στις Fermi αρχιτεκτονικές οι kernels εκτελούνται παράλληλα, χρησιμοποιήσαμε την cudathreadsynchronize μετά τις κλήσεις της Transpose για να εξαναγκάσουμε τους kernel της Transpose και της FFD1DOnce να εκτελεστούν σειριακά ο ένας μετά τον άλλον. Δεν χρειάστηκε να κάνουμε το ίδιο και μεταξύ της πρώτης κλήσης της FFD1DOnce και της δεύτερης της Transpose διότι παρεμβάλλεται πράξη cudamemcpy που όπως γνωρίζουμε είναι σύγχρονη. Οι μετρήσεις χρόνου για την Transpose χωρίς μεταφορές μνήμης δείχνουν βελτιωμένο χρόνο από 1,1sec (στη CPU) σε 0,1sec (στη GPU). Στην προσπάθειά μας να απαλείψουμε τα cudathreadsynchronize, ενοποιήσαμε τους δύο kernel μας Transpose και FFD1DOnce σε έναν, προσπαθώντας να ελαχιστοποιήσουμε ταυτόχρονα και τον αριθμό των χρησιμοποιούμενων καταχωρητών επαναχρησιμοποιώντας τους όπου ήταν εφικτό. Δεν ήταν δυνατόν να πάρουμε μέτρηση χρόνου με την gettimeofday λόγω του ότι η κλήση του kernel επέστρεφε άμεσα εξ αιτίας της έλλειψης των cudathreadsynchronize, οπότε χρησιμοποιήσαμε την time κατά την εκτέλεση του προγράμματος. Παραδόξως η υλοποίηση με τους δύο ξεχωριστούς kernel ήταν ταχύτερη με χρόνο περίπου 13,5sec ενώ η υλοποίηση με τον ενοποιημένο kernel έδωσε χρόνο 14,6 sec. Συνεπώς κρατήσαμε την παλιά μας υλοποίηση. Έχοντας φτάσει σε έναν αρκετά μικρό χρόνο για την Transpose, ξαναενεργοποιήσαμε τις L1 και L2 caches και δώσαμε 48ΚΒ στην L1 cache με την εντολή cudafuncsetcacheconfig. Μετρήσαμε τον συνολικό χρόνο με την time ο οποίος βελτιώθηκε από 13sec σε 11,3 sec. Το συνολικό speedup που έχουμε επιτύχει από τα 17,6sec του αρχικού κώδικα είναι 1,558x (φυσικά στον χρόνο αυτόν περιλαμβάνονται και οι χρόνοι του dummy kernel, των cudamalloc και cudafree).

Στο παρακάτω γράφημα φαίνονται συγκεντρωτικά οι θετικές επιδράσεις που είχαν οι βελτιστοποιήσεις μας (με τη σειρά που τις εφαρμόσαμε) στον συνολικό αλλά και στους επιμέρους χρόνους: 20000 18000 16000 14000 12000 Χρόνος σε msec 10000 8000 6000 4000 rest FFT1DOnce execution Transpose execution cuda memcpy to host cuda memcpy to device cuda malloc and free 2000 0 CPU Port of FFD1DOnce Double to Float Using Constant mult/div to shift Port of Transpose Using L1/L2 Βελτιστοποιήσεις με την σειρά που εφαρμόστηκαν Δοκιμάσαμε να τρέξουμε και για μικρότερες τιμές του m και να συγκρίνουμε τα αποτελέσματα με αυτά του αρχικού κώδικα του FFT, τα οποία φαίνονται στο παρακάτω γράφημα: 100 10 4,2 2,5 17,6 11,3 1 0,2 0,3 0,2 0,8 0,7 on CPU on GPU 0,1 0,05 0,01 18 20 22 24 26 Παρατηρώντας το γράφημα γίνεται εύκολα αντιληπτό πως σε μελλοντικές κάρτες γραφικών με μεγαλύτερες μνήμες (όπου θα μπορούμε να τρέξουμε για m>26) θα παίρνουμε ακόμα μεγαλύτερα Speedup από αυτά που έχουμε ήδη πάρει.