babel47 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Καλησπέρα σε όλη την κοινότητα, θα ήθελα να κάνω μια μικρή ερώτηση προς όποιον ίσως γνωρίζει. Προσπαθώ να παραλληλοποιήσω έναν κώδικα χρησιμοποιώντας την βιβλιοθήκη openmp. Ο κώδικας είναι σε C. Κάνω include αρχικά την βιβλιοθήκη. (#include <omp.h>) Στην συνέχεια κάνω το πολύ απλό, να χρησιμοποιήσω σε κάθε φορ που βλέπω μέσα στον κώδικα μία εντολή παραλληλοποίησής του. (πχ. κάτι σαν #pragma omp parallel for). Σύμφωνα με το manual του openmp αυτή η εντολή θα έπρεπε να παραλληλοποιεί την λούπα for. Το testing το κάνω σε ένα μόνο μηχάνημα που έχω το οποίο διαθέτει 10 επεξεργαστές. Παρατηρώ ότι είτε χρησιμοποιώ openmp είτε όχι (δηλαδή είτε κάνω τις παραπάνω αλλαγές που σας περιέγραψα είτε χωρίς αυτές τις αλλαγές), ο χρόνος που διαρκεί το τρέξιμο είναι ο ίδιος. Τον μετράω χρησιμοποιώντας την systime.h. Επίσης σε ένα πρόγραμμα που έχω βάλει το οποίο μου δείχνει ποιοι επεξεργαστές χρησιμοποιούνται και πόσο %, παρατηρώ ότι και όταν τρέχω τον σειριακό αλγόριθμο και τον παράλληλο, χρησιμοποιείται μόνο ένας επεξεργαστής κατά 100%!! Και σε γενικές γραμμές το usage όλης της CPU είναι περίπου 10% (λογικό αφού χρησιμοποιείται μόνο ένας).. Κάτι που μου φαίνεται περίεργο μιας και οι εντολές του openmp που έχω βάλει είναι σαν να μην υπάρχουν. Υπάρχει κανείς σχετικός με openmp ο οποίος ξέρει τι μπορεί να φταίει? Σκέφτηκα ότι ίσως να είναι κάτι πολύ βασικό, το οποίο δεν γνωρίζω...
migf1 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Καλησπέρα σε όλη την κοινότητα, θα ήθελα να κάνω μια μικρή ερώτηση προς όποιον ίσως γνωρίζει. Προσπαθώ να παραλληλοποιήσω έναν κώδικα χρησιμοποιώντας την βιβλιοθήκη openmp. Ο κώδικας είναι σε C. Κάνω include αρχικά την βιβλιοθήκη. (#include <omp.h>) Στην συνέχεια κάνω το πολύ απλό, να χρησιμοποιήσω σε κάθε φορ που βλέπω μέσα στον κώδικα μία εντολή παραλληλοποίησής του. (πχ. κάτι σαν #pragma omp parallel for). Σύμφωνα με το manual του openmp αυτή η εντολή θα έπρεπε να παραλληλοποιεί την λούπα for. Το testing το κάνω σε ένα μόνο μηχάνημα που έχω το οποίο διαθέτει 10 επεξεργαστές. Παρατηρώ ότι είτε χρησιμοποιώ openmp είτε όχι (δηλαδή είτε κάνω τις παραπάνω αλλαγές που σας περιέγραψα είτε χωρίς αυτές τις αλλαγές), ο χρόνος που διαρκεί το τρέξιμο είναι ο ίδιος. Τον μετράω χρησιμοποιώντας την systime.h. Επίσης σε ένα πρόγραμμα που έχω βάλει το οποίο μου δείχνει ποιοι επεξεργαστές χρησιμοποιούνται και πόσο %, παρατηρώ ότι και όταν τρέχω τον σειριακό αλγόριθμο και τον παράλληλο, χρησιμοποιείται μόνο ένας επεξεργαστής κατά 100%!! Και σε γενικές γραμμές το usage όλης της CPU είναι περίπου 10% (λογικό αφού χρησιμοποιείται μόνο ένας).. Κάτι που μου φαίνεται περίεργο μιας και οι εντολές του openmp που έχω βάλει είναι σαν να μην υπάρχουν. Υπάρχει κανείς σχετικός με openmp ο οποίος ξέρει τι μπορεί να φταίει? Σκέφτηκα ότι ίσως να είναι κάτι πολύ βασικό, το οποίο δεν γνωρίζω... Καλησπέρα! Για κώδικα δεν μπορώ να σε βοηθήσω, γιατί δεν τα έχω καθόλου φρέσκα τα περί parallelization, αλλά εφόσον λες πως τα έχεις σωστά για τσεκάρισε το affinity setting ... σε Win7 είσαι; Αν ναι: http://www.techrepub...mance-edge/5322
V.I.Smirnov Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Καταρχήν θα πρέπει να είσαι βέβαιος ότι το openMP είναι ενεργοποιημένο. Αυτό γίνεται θέτοντας κάποιο κατάλληλο flag στον compiler κατά τη μεταγλώτισση. Οι compilers της MS και της Intel έχουν αυτή τη ρύθμιση στα project settings. Από εκεί και πέρα, οι παράγοντες που επηρεάζουν τον παραλληλισμό με νήματα - και ειδικά στο openMP - είναι πολλοί και δύσκολο να ελεγχθούν άμεσα. Η κλιμάκωση που επιτυγχάνεται μοιράζοντας απλώς τις επαναλήψεις στα νήματα είναι γενικώς μέτρια ή κακή. Ενδεικτικά σου λέω ότι πριν πολύ καιρό είχα κάνει κάποιες δοκιμές σε μηχάνημα με 8 cpus. Ο κόρος ερχόταν στα 12 νήματα, η επιτάχυνση δεν ήταν σταθερή με το μέγεθος του προβλήματος και η απόδοση ήταν χονδρικά περίπου 65-70% (χωρίς προσπάθεια "λεπτών ρυθμίσεων"). Το κύριο πρόβλημα είναι η τοπικότητα των δεδομένων σε συνδυασμό με την ισοκατανομή του υπ. φορτίου. Οι καλοί compilers έχουν βοηθήματα που διευκολύνουν σημαντικά τις βελτιστοποιήσεις. Ο compiler της Intel έχει ακόμη και thread affinity interface (που όμως δεν είναι στάνταρ). Η απόλυτη λύση είναι να χρησιμοποιηθεί τεχνική SPDM για την γραφή του προγράμματος που δυστυχώς είναι πολύ πιο δύσκολη. Το πρώτο βήμα πάντως είναι να βεβαιωθείς ότι το openmp είναι ενεργοποιημένο και ότι μοιράζεις τις επαναλήψεις στα νήματα... -
dop Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Οι περισσότεροι mainstream compilers θέλουν επιπλέον επιλογή για το OpenMP όπως λέει ο V.I.Smirnov. Μια καλή λίστα είναι στο http://openmp.org/wp/openmp-compilers/ Άπαξ και το έκανες αυτό σωστό, μερικές φορές πρέπει να πεις στο OpenMP πόσα threads θέλεις να έχει διαθέσιμα. Το κάνεις με την environment variable OMP_NUM_THREADS. Πχ. σε unix-like: $ OMP_NUM_THREADS=16 ./my_exec
ChRis6 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Για ακομη μια φορα φαινεται οτι οταν προσθετεις πορους σε ενα κατανεμημενο συστημα, δεν σημαινει οτι μεγαλωνεις και την αποδοση ! Η σωστη κλιμακωση θελει προσοχη
babel47 Δημοσ. 13 Ιουλίου 2012 Μέλος Δημοσ. 13 Ιουλίου 2012 Εντάξει παιδιά το έφτιαξα. Ευχαριστώ όλους για τις απαντήσεις. Ακολούθησα τις οδηγίες του βίντεο -> http://www.youtube.com/watch?v=p0woqF2XCeg Tώρα να δούμε εάν θα τα καταφέρω με τον κώδικα...
babel47 Δημοσ. 13 Ιουλίου 2012 Μέλος Δημοσ. 13 Ιουλίου 2012 Άπαξ και το έκανες αυτό σωστό, μερικές φορές πρέπει να πεις στο OpenMP πόσα threads θέλεις να έχει διαθέσιμα. Το κάνεις με την environment variable OMP_NUM_THREADS. Πχ. σε unix-like: $ OMP_NUM_THREADS=16 ./my_exec σε windows-like?
dop Δημοσ. 13 Ιουλίου 2012 Δημοσ. 13 Ιουλίου 2012 Νομίζω αναθέτεις environments variables με set OMP_NUM_THREADS=16
παπι Δημοσ. 13 Ιουλίου 2012 Δημοσ. 13 Ιουλίου 2012 Εχει και api για c εκτος απο το shell δες το http://msdn.microsoft.com/en-us/library/d8wkzt26.aspx
babel47 Δημοσ. 17 Ιουλίου 2012 Μέλος Δημοσ. 17 Ιουλίου 2012 Καλησπέρα ξανά, έχω μπροστά μου έναν κώδικα ο οποίος είναι σχετικά μεγάλος και τον οποίο προσπαθώ να παραλληλοποιήσω. Αυτό που προσπαθώ να κάνω σαν πρώτο βήμα είναι να παραλληλοποιήσω ένα μικρό μέρος του κώδικα το εξής: (αρχικοποίηση τρισδιάστατου πίνακα) > for (i=0; i<3; i++) for ( j=0; j<3; j++) for ( k=0; k<3; k++) myarray[i][j][k]=0; το οποίο γίνεται: > #pragma omp parallel private(i,j,k) { #pragma omp for schedule(guided,2) for (i=0; i<3; i++) for ( j=0; j<3; j++) for ( k=0; k<3; k++) myarray[i][j][k]=0; } Παρατηρώ ότι στο τρέξιμο κολλάει για πάντα στο νέο brucket που έχει δημιουργηθεί για την παραλληλοποίηση. Βάζοντας ένα printf μέσα, παρατήρησα ότι εκτυπώνεται άπειρες φορές. Μήπως έχει να κάνει με το ότι το σημείο αυτό βρίσκεται μέσα σε μία συνάρτηση η οποία καλείται πολλές φορές στο πρόγραμμα και αυτό δεν είναι πρακτικό. Δηλαδή μήπως πρέπει να ξεκινήσω να κόβω κομμάτια για parallel από πιο έξω?
dop Δημοσ. 18 Ιουλίου 2012 Δημοσ. 18 Ιουλίου 2012 Πρέπει να δημιουργήσεις το παράλληλο region όσο το δυνατόν πιο νωρίς. Ειδάλλως, απλά βλέπεις το overhead του fork/join.
V.I.Smirnov Δημοσ. 18 Ιουλίου 2012 Δημοσ. 18 Ιουλίου 2012 Δεν το έχεις κάνει σωστά. Καταρχήν, με 3x3x3 δεν μπορεί να γίνει δοκιμή. Ο πίνακας είναι πολύ μικρός και η επιβάρυνση από το fork-join της παραλληλοποίησης είναι πιθανόν μεγαλύτερη απ' ότι αν το άφηνες σειριακό. Αν ο πίνακας είναι τόσο μικρός, πιθανόν είναι ταχύτερο να αρχικοποιείται με vectorization. Eν πάση περιπτώση, έστω ότι έχεις πίνακα 100x100x100. Η omp parallel παράγει απλώς αντίγραφα του περιεχόμενου κώδικα. Δεν κατανέμει την δουλειά στα νήματα. Αυτό το κάνει η omp for. Αλλά αυτή μοιράζει τις επαναλήψεις μόνον του πρώτου βρόχου εκατέρωθέν της. Συνεπώς, στο απόσπασμά σου μοιράζονται μόνον οι επαναλήψεις του βρόγχου για το i (και φυσικά ότι περιέχει κάθεμιά τους), δηλ. οι 100. Κάθε νήμα λαμβάνει 100/4=25, όχι 1000000/4 όπως πιθανόν θα περίμενες. Για να μοιραστούν όλες ο χώρος των επαναλήψεων απαιτείται να είναι ενιαίος : πρέπει είτε να "ξεδιπλώσεις" τον βρόγχο και να τον γράψεις ενιαία, (ήτοι do i=0,999999 κλπ) είτε να χρησιμοποιήσεις την οδηγία collapse (εφόσον δουλεύεις openMP 3.0) που κάνει αυτή τη δουλειά. Επιπλέον, μπορείς να βγάλεις το έμμεσο φράγμα που θέτει κάθε omp for με την nowait. Όπως είπε και o dop, το άνοιξε-κλείσε παράλληλων περιοχών πρέπει όσο το δυνατόν να αποφεύγεται. Ο κανόνας είναι οι παράλληλες περιοχές να είναι όσο το δυνατόν μεγαλύτερες (coarse grained parallelism). Tέλος, αν καλείς ρουτίνες μέσα από παράλληλες περιοχές, πρέπει να έχεις μια σαφή εικόνα ποιές μεταβλητές-ορίσματα είναι κοινές και ποιές όχι και να λάβεις τα μέτρα σου, αλλιώς θα γίνουν data races - κοινώς μπάχαλο ! Πριν ξεκινήσεις να εφαρμόζεις το OpenMP, πρέπει να ξεκαθαρίσεις την συμπεριφορά των βασικών οδηγιών και των μεταβλητών. Και να έχεις μια ιδέα για τους βασικούς παράγοντες που επηρεάζουν την ταχύτητα όταν χρησιμοποιείς νήματα. Με το να βάζεις απλώς την omp parallel μην περιμένεις βελτίωση... Καλή συνέχεια. -
παπι Δημοσ. 18 Ιουλίου 2012 Δημοσ. 18 Ιουλίου 2012 Δεν το έχεις κάνει σωστά. Καταρχήν, με 3x3x3 δεν μπορεί να γίνει δοκιμή. Ο πίνακας είναι πολύ μικρός και η επιβάρυνση από το fork-join της παραλληλοποίησης είναι πιθανόν μεγαλύτερη απ' ότι αν το άφηνες σειριακό. Αν ο πίνακας είναι τόσο μικρός, πιθανόν είναι ταχύτερο να αρχικοποιείται με vectorization. Και μεγαλυτερος να ηταν ο πινακας παλι δεν θα εβλεπε διαφορα εφοσον και με ενα core η δουλεια ειναι τοσο απλη που η καθυστερηση θα ειναι λογου memory bus και οχι λογο cpu
babel47 Δημοσ. 18 Ιουλίου 2012 Μέλος Δημοσ. 18 Ιουλίου 2012 Μα το θέμα δεν είναι να δω διαφορά στο 3*3*3. Θέλω να ξεκινήσω να χρησιμοποιώ το openmp και ξεκίνησα από το πιο απλό σημείο που υπάρχει στο κώδικα. Τα υπόλοιπα είναι αρκετά πολύπλοκα με πολλές μεταβλητές αν και έχω αρχίσει να τα αλλάζω και αυτά. Ωστόσω μιας και δεν βγάζω άκρη είπα να δοκιμάσω να αλλάξω αυτό το σημείο μόνο για δοκιμή (σε μία παραδοτέα υλοποίηση δεν θα το πείραζα καθόλου προφανώς). Το πρόβλημα όπως σας είπα δεν είναι ότι αργεί παραπάνω, είναι ότι μένει για πάντα μέσα στην parallel region. Αυτό προσπαθώ να καταλάβω γιατί γίνεται μπας και αρχίσω να καταλαβαίνω μερικά πράγματα. Απότι καταλαβαίνω με βάση αυτά που περιέγραψε ο Smirnov, έχει να κάνει με τις μεγαλύτερες περιοχές parallel που είθισται να ορίζουμε. Αυτή η μικρή περιοχή καλείται πολλές φορές μιας και η συνάρτηση που την περιέχει καλείται πολλές φορές. Οπότε δημιουργούνται πολλά αντίγραφα. Ωστόσω δεν μου είναι και τόσο ξεκάθαρο πως αυτό οδηγεί στο κόλλημα. Smirnov, έκανα τις αλλαγές σου, και τα printf σταμάτησαν να εκτυπώνονται συνεχώς (for, collapse , nowait), ωστόσω παραμένει κολλημένο μέσα στο brucket της parallel. Τέλος πάντων θα ξεκινήσω να πειράζω πιο εξωτερικό σημείο του κώδικα (στην main) μήπως φύγει το κόλλημα...
dop Δημοσ. 24 Ιουλίου 2012 Δημοσ. 24 Ιουλίου 2012 Άμα δεν καταλαβαίνεις που κολλάει, σταμάτα να το πειράζεις για λίγο και σκέψου/κοίτα γιατί και που κολλάει. Ειδάλλως θα παλεύεις με το κόλλημα σε μη ντετερμινιστικό περιβάλλον (είναι πιο εύκολο να καταλάβεις τι κάνει ένα thread, παρά 2+). Και για να μην έχουμε και αυταπάτες, το ότι έκανες ένα μικρό κομμάτι παράλληλο δεν σημαίνει τίποτα. Η αύξηση της απόδοσης (speedup) εξαρτάται από το σειριακό κομμάτι του κώδικα (νόμος Amdahl). Εφόσον πρόκειται για υπάρχουσα εφαρμογή, πρώτα πρέπει να κάνεις ένα breakdown του χρόνου (πιο μέρος καθυστερεί, που είναι το bottleneck σου κλπ) και μετά να το παραλληλίσεις.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα