Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπέρα σε όλη την κοινότητα,

 

θα ήθελα να κάνω μια μικρή ερώτηση προς όποιον ίσως γνωρίζει.

 

Προσπαθώ να παραλληλοποιήσω έναν κώδικα χρησιμοποιώντας την βιβλιοθήκη openmp.

Ο κώδικας είναι σε C.

 

Κάνω include αρχικά την βιβλιοθήκη. (#include <omp.h>)

Στην συνέχεια κάνω το πολύ απλό, να χρησιμοποιήσω σε κάθε φορ που βλέπω μέσα στον κώδικα

μία εντολή παραλληλοποίησής του. (πχ. κάτι σαν #pragma omp parallel for). Σύμφωνα με το manual του openmp

αυτή η εντολή θα έπρεπε να παραλληλοποιεί την λούπα for.

 

Το testing το κάνω σε ένα μόνο μηχάνημα που έχω το οποίο διαθέτει 10 επεξεργαστές. Παρατηρώ ότι είτε χρησιμοποιώ openmp είτε όχι (δηλαδή είτε κάνω τις παραπάνω αλλαγές που σας περιέγραψα είτε χωρίς αυτές τις αλλαγές), ο χρόνος που διαρκεί το τρέξιμο είναι ο ίδιος. Τον μετράω χρησιμοποιώντας την systime.h. Επίσης σε ένα πρόγραμμα που έχω βάλει το οποίο μου δείχνει ποιοι επεξεργαστές χρησιμοποιούνται και πόσο %, παρατηρώ ότι και όταν τρέχω τον σειριακό αλγόριθμο και τον παράλληλο, χρησιμοποιείται μόνο ένας επεξεργαστής κατά 100%!! Και σε γενικές γραμμές το usage όλης της CPU είναι περίπου 10% (λογικό αφού χρησιμοποιείται μόνο ένας).. Κάτι που μου φαίνεται περίεργο μιας και οι εντολές του openmp που έχω βάλει είναι σαν να μην υπάρχουν.

 

Υπάρχει κανείς σχετικός με openmp ο οποίος ξέρει τι μπορεί να φταίει? Σκέφτηκα ότι ίσως να είναι κάτι πολύ βασικό, το οποίο δεν γνωρίζω...

Δημοσ.

Καλησπέρα σε όλη την κοινότητα,

 

θα ήθελα να κάνω μια μικρή ερώτηση προς όποιον ίσως γνωρίζει.

 

Προσπαθώ να παραλληλοποιήσω έναν κώδικα χρησιμοποιώντας την βιβλιοθήκη 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

Δημοσ.

Καταρχήν θα πρέπει να είσαι βέβαιος ότι το openMP είναι ενεργοποιημένο.

Αυτό γίνεται θέτοντας κάποιο κατάλληλο flag στον compiler κατά τη μεταγλώτισση.

Οι compilers της MS και της Intel έχουν αυτή τη ρύθμιση στα project settings.

 

 

Από εκεί και πέρα, οι παράγοντες που επηρεάζουν τον παραλληλισμό με νήματα

- και ειδικά στο openMP - είναι πολλοί και δύσκολο να ελεγχθούν άμεσα.

Η κλιμάκωση που επιτυγχάνεται μοιράζοντας απλώς τις επαναλήψεις στα νήματα είναι

γενικώς μέτρια ή κακή.

Ενδεικτικά σου λέω ότι πριν πολύ καιρό είχα κάνει κάποιες δοκιμές σε μηχάνημα με 8 cpus.

Ο κόρος ερχόταν στα 12 νήματα, η επιτάχυνση δεν ήταν σταθερή με το μέγεθος του προβλήματος και

η απόδοση ήταν χονδρικά περίπου 65-70% (χωρίς προσπάθεια "λεπτών ρυθμίσεων").

 

Το κύριο πρόβλημα είναι η τοπικότητα των δεδομένων σε συνδυασμό με την ισοκατανομή του υπ. φορτίου.

Οι καλοί compilers έχουν βοηθήματα που διευκολύνουν σημαντικά τις βελτιστοποιήσεις.

Ο compiler της Intel έχει ακόμη και thread affinity interface (που όμως δεν είναι στάνταρ).

Η απόλυτη λύση είναι να χρησιμοποιηθεί τεχνική SPDM για την γραφή του προγράμματος που

δυστυχώς είναι πολύ πιο δύσκολη.

 

Το πρώτο βήμα πάντως είναι να βεβαιωθείς ότι το openmp είναι ενεργοποιημένο και

ότι μοιράζεις τις επαναλήψεις στα νήματα...

 

-

Δημοσ.

Οι περισσότεροι 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

Δημοσ.

Για ακομη μια φορα φαινεται οτι οταν προσθετεις πορους σε ενα κατανεμημενο συστημα, δεν σημαινει οτι μεγαλωνεις και την αποδοση !

 

Η σωστη κλιμακωση θελει προσοχη

Δημοσ.

 

Άπαξ και το έκανες αυτό σωστό, μερικές φορές πρέπει να πεις στο OpenMP πόσα threads θέλεις να έχει διαθέσιμα. Το κάνεις με την environment variable OMP_NUM_THREADS.

 

Πχ. σε unix-like:

$ OMP_NUM_THREADS=16 ./my_exec

 

σε windows-like?

Δημοσ.

Καλησπέρα ξανά,

 

έχω μπροστά μου έναν κώδικα ο οποίος είναι σχετικά μεγάλος και τον οποίο προσπαθώ να παραλληλοποιήσω.

 

Αυτό που προσπαθώ να κάνω σαν πρώτο βήμα είναι να παραλληλοποιήσω ένα μικρό μέρος του κώδικα το εξής:

 

(αρχικοποίηση τρισδιάστατου πίνακα)

 

>
  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 από πιο έξω?

Δημοσ.

Πρέπει να δημιουργήσεις το παράλληλο region όσο το δυνατόν πιο νωρίς. Ειδάλλως, απλά βλέπεις το overhead του fork/join.

Δημοσ.

Δεν το έχεις κάνει σωστά.

 

Καταρχήν, με 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 μην περιμένεις βελτίωση...

Καλή συνέχεια.

 

-

Δημοσ.

Δεν το έχεις κάνει σωστά.

 

Καταρχήν, με 3x3x3 δεν μπορεί να γίνει δοκιμή.

Ο πίνακας είναι πολύ μικρός και η επιβάρυνση από το fork-join της παραλληλοποίησης είναι

πιθανόν μεγαλύτερη απ' ότι αν το άφηνες σειριακό.

Αν ο πίνακας είναι τόσο μικρός, πιθανόν είναι ταχύτερο να αρχικοποιείται με vectorization.

 

 

 

Και μεγαλυτερος να ηταν ο πινακας παλι δεν θα εβλεπε διαφορα εφοσον και με ενα core η δουλεια ειναι τοσο απλη που η καθυστερηση θα ειναι λογου memory bus και οχι λογο cpu

Δημοσ.

Μα το θέμα δεν είναι να δω διαφορά στο 3*3*3. Θέλω να ξεκινήσω να χρησιμοποιώ το openmp

και ξεκίνησα από το πιο απλό σημείο που υπάρχει στο κώδικα. Τα υπόλοιπα είναι αρκετά

πολύπλοκα με πολλές μεταβλητές αν και έχω αρχίσει να τα αλλάζω και αυτά.

 

Ωστόσω μιας και δεν βγάζω άκρη είπα να δοκιμάσω να αλλάξω αυτό το σημείο μόνο για δοκιμή (σε μία παραδοτέα υλοποίηση δεν θα το πείραζα καθόλου προφανώς). Το πρόβλημα όπως σας είπα δεν είναι ότι αργεί παραπάνω, είναι ότι μένει για πάντα μέσα στην parallel region. Αυτό προσπαθώ να καταλάβω γιατί γίνεται μπας και αρχίσω να καταλαβαίνω μερικά πράγματα.

 

Απότι καταλαβαίνω με βάση αυτά που περιέγραψε ο Smirnov, έχει να κάνει με τις μεγαλύτερες περιοχές parallel που είθισται να ορίζουμε. Αυτή η μικρή περιοχή καλείται πολλές φορές μιας και η συνάρτηση που την περιέχει καλείται πολλές φορές. Οπότε δημιουργούνται πολλά αντίγραφα. Ωστόσω δεν μου είναι και τόσο ξεκάθαρο πως αυτό οδηγεί στο κόλλημα.

 

Smirnov, έκανα τις αλλαγές σου, και τα printf σταμάτησαν να εκτυπώνονται συνεχώς (for, collapse , nowait), ωστόσω παραμένει κολλημένο μέσα στο brucket της parallel. Τέλος πάντων θα ξεκινήσω να πειράζω πιο εξωτερικό σημείο του κώδικα (στην main) μήπως φύγει το κόλλημα...

Δημοσ.

Άμα δεν καταλαβαίνεις που κολλάει, σταμάτα να το πειράζεις για λίγο και σκέψου/κοίτα γιατί και που κολλάει. Ειδάλλως θα παλεύεις με το κόλλημα σε μη ντετερμινιστικό περιβάλλον (είναι πιο εύκολο να καταλάβεις τι κάνει ένα thread, παρά 2+).

 

Και για να μην έχουμε και αυταπάτες, το ότι έκανες ένα μικρό κομμάτι παράλληλο δεν σημαίνει τίποτα. Η αύξηση της απόδοσης (speedup) εξαρτάται από το σειριακό κομμάτι του κώδικα (νόμος Amdahl).

 

Εφόσον πρόκειται για υπάρχουσα εφαρμογή, πρώτα πρέπει να κάνεις ένα breakdown του χρόνου (πιο μέρος καθυστερεί, που είναι το bottleneck σου κλπ) και μετά να το παραλληλίσεις.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...