Παράλληλη Επεξεργασία — Ιανουάριος 2025 — Θέματα 2ο–3ο¶
Μεταγραφή από τα IMG_5630, IMG_5636 και IMG_5633 (Εξεταστική Ιανουαρίου 2025).
IMG_5630.jpg¶
Τμήμα Μηχ. Η/Υ και Πληροφορικής, Πανεπιστήμιο Πατρών
Παράλληλη Επεξεργασία¶
Εξεταστική Περίοδος: Ιανουαρίου 2025
Θέμα 1ο (3 μονάδες) [απαντήστε εδώ]¶
1.1 Η οδηγία single nowait του OpenMP:¶
- [ ] a. περιέχει φράγμα εκτέλεσης
- [ ] b. είναι ισοδύναμη με την οδηγία master
- [ ] c. παρέχει αμοιβαίο αποκλεισμό
- [ ] d. τίποτα από τα υπόλοιπα
1.2 Εάν το 20% ενός κώδικα δεν μπορεί να παραλληλοποιηθεί τότε η μέγιστη δυνατή χρονοβελτίωση είναι:¶
- [ ] a. 2
- [ ] b. 5
- [ ] c. 10
- [ ] d. τίποτα από τα υπόλοιπα
1.3 Η εντολή export OMP_DYNAMIC=FALSE απενεργοποιεί:¶
- [ ] a. τη δημιουργία και εκτέλεση tasks
- [ ] b. την εκτέλεση των επαναλήψεων με δυναμικό τρόπο
- [ ] c. την εκτέλεση των επαναλήψεων με στατικό τρόπο
- [ ] d. τίποτα από τα υπόλοιπα
1.4 Για ποια συστήματα δεν είναι κατάλληλο το μοντέλο προγραμματισμού MPI;¶
- [ ] a. συστήματα κοινής μνήμης
- [ ] b. συστήματα ομοιόμορφης προσπέλασης μνήμης (UMA)
- [ ] c. συστήματα κατανεμημένης μνήμης
- [ ] d. μπορεί να εκτελεστεί σε όλα τα παραπάνω
1.5 Δίνεται ο παρακάτω κώδικας OpenMP.¶
int test_var = 1;
#pragma omp parallel num_threads(4) reduction(*:test_var)
{
test_var = omp_get_thread_num() - omp_get_num_threads();
}
1.6 Δίνεται ο παρακάτω κώδικας OpenMP.¶
int main(int argc, char *argv[]) {
int b,c;
#pragma omp parallel shared(c) private(b)
{
int d;
#pragma omp task
{
int e;
// σημείο αναφοράς εντός του task
}
}
// more code here
return 0;
}
IMG_5636.jpg¶
Θέμα 2ο (3 μονάδες)¶
| 2.1 Δίνεται ο παρακάτω κώδικας OpenMP. | 2.2 Δίνεται το παρακάτω τμήμα κώδικα MPI. |
|---|---|
c<br>int A[12];<br>omp_set_num_threads(4);<br>#pragma omp parallel for schedule(static,3)<br>for (int i = 0; i < 12; i++) {<br> A[i] = omp_get_thread_num();<br>}<br> |
c<br>int rank, size;<br>MPI_Comm_rank(MPI_COMM_WORLD, &rank);<br>MPI_Comm_rank(MPI_COMM_WORLD, &size);<br><br>int var1 = rank + 1 - size;<br>int var2 = 0, var3 = 0;<br>MPI_Allreduce(&var1, &var2, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);<br>MPI_Reduce(&var2, &var3, 1, MPI_INT, MPI_PROD, 0, MPI_COMM_WORLD);<br><br>printf("%d : %d\n", rank, var3);<br> |
| a. Περιγράψτε τι κάνει ο παραπάνω παράλληλος κώδικας. b. Ποιες θα είναι οι τελικές τιμές του διανύσματος A; Εξηγήστε. |
a. Τι τιμές εκτυπώνει ο παραπάνω κώδικας όταν εκτελεστεί με 3 διεργασίες (mpirun -n 3 <executable>); b. Εξηγήστε την απάντησή σας. |
IMG_5633.jpg¶
Τμήμα Μηχ. Η/Υ και Πληροφορικής, Πανεπιστήμιο Πατρών
Θέμα 3ο (2 μονάδες)¶
Στον παρακάτω κώδικα, η συνάρτηση initialize θέτει τιμές σε ένα διάνυσμα Α διάστασης Ν, χρησιμοποιώντας τη εξαιρετικά γρήγορη συνάρτηση work, που είναι υλοποιημένη κάπου αλλού. Θεωρήστε πως η διάσταση Ν είναι ι[Λείπει από τη φωτογραφία: υπόλοιπο της πρότασης] a. Εξηγήστε πώς διαμοιράζονται οι επαναλήψεις του βρόγχου στα νήματα. b. Αναφέρετε πιθανά προβλήματα απόδοσης του κώδικα και προτείνετε μια λύση.
extern double work(int i);
void initialize(double *A, int N)
{
#pragma omp parallel for schedule(dynamic, 3)
for (int i = 0; i < N; i++) {
A[i] = work(i);
}
}
Θέμα 4ο (2 μονάδες)¶
Ο παρακάτω σειριακός κώδικας αρχικοποιεί το διάνυσμα Α διάστασης Ν και μετά υπολογίζει ένα ειδικό άθροισμα τω[Λείπει από τη φωτογραφία: ν στοιχείων] του. Θεωρήστε πως η διάσταση Ν μπορεί να είναι αυθαίρετα μεγάλη. Βελτιστοποιήστε και παραλληλοποιήστε απ[Λείπει από τη φωτογραφία: ό τον παρακάτω] κώδικα με χρήση του μοντέλου MPI.
| /* Κώδικας */ | /* Βοηθητικά στοιχεία του MPI */ |
|---|---|
#include <stdio.h> // printf#include <stdlib.h> // malloc#include <math.h> // sqrt#define N (1024*1024)// υλοποιημένη κάπου αλλούextern double initialize(int i);int main (int argc, char **argv){double b[2] = {5.0, 10.0};double *A = (double *)malloc(N*sizeof(double));for (int i = 0; i < N; i++) A[i] = initialize(i);Χρήστης#1320 = 0.0;for (int i = 0; i < N; i++)s += b[0]*sqrt(A[i]) + b[1];printf("sum=%lf\n", s);free(A);return 0;} |
int MPI_Init(int *argc, char ***argv);int MPI_Finalize();int MPI_Comm_size(MPI_Comm comm, int *size);int MPI_Comm_rank(MPI_Comm comm, int *rank);int MPI_Send(const void *buf, int count, MPI_Datatype datatype,int dest, int tag, MPI_Comm comm);int MPI_Recv(void *buf, int count, MPI_Datatype datatype,int source, int tag, MPI_Comm comm, MPI_Status *s[Λείπει από τη φωτογραφία: ...]int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,int root, MPI_Comm comm);int MPI_Reduce(void *sendbuf, void *recvbuf, int count,MPI_Datatype datatype, MPI_Op op, int root,MPI_Comm comm);int MPI_Allreduce(void *sendbuf, void *recvbuf, int count,MPI_Datatype datatype, MPI_Op op,MPI_Comm comm);Constants: MPI_COMM_WORLD Elementary Datatypes: MPI_CHAR, MPI_SHORT, MPI_INT, MPI_LO[Λείπει από τη φωτογραφία: NG] MPI_FLOAT, MPI_DOUBLE, MPI_BYTE Reduction Operations: MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD |
Διάρκεια Εξέτασης: 2 ώρες
Λύσεις (🟡 community)
Κατάσταση: 🟡 community Πηγή: χειρόγραφη λύση φοιτητή (φωτογραφία IMG_6261.jpg)
Προσοχή
Το μεταγραφικό σημειώνει session_hint 2025-06· η αντιστοίχιση στη συνεδρία 2025-01 γίνεται από τον κώδικα (A[12], schedule(static,3)) που εμφανίζεται στη συνεδρία. Τα ερωτήματα a) και b) της εκφώνησης είναι δυσανάγνωστα στη φωτογραφία· η λύση δεν μπορεί να ελεγχθεί πλήρως ως προς αυτά. Στο MPI μέρος, το var3 των rank 1 και 2 είναι 0 ως αρχική τιμή του καταχωρητή· το MPI_Reduce δεν ορίζει το recvbuf των μη-ριζικών διεργασιών, άρα το 0 δεν είναι αποτέλεσμα.
Λύσεις — Παράλληλη Επεξεργασία — Ιανουάριος 2025¶
IMG_6261.jpg¶
int A[12]
omp_set_num_threads(4);
#pragma omp parallel for schedule(static,3)
for (int i=0; i<12; i++) {
A[i] = omp_get_thread_num();
}
[Σχήμα: αγκύλη που ομαδοποιεί δύο ερωτήματα] a) [δυσανάγνωστο] ο [δυσανάγνωστο]; b) Ποιες είναι οι [δυσανάγνωστο] του A;
Λύση
Χρησιμοποιούμε 4 threads. Το loop for μοιράζεται με schedule(static,3) = κάθε thread παίρνει 3 συνεχόμενες επαναλήψεις. Το omp_get_thread_num() επιστρέφει τον αριθμό του τρέχοντος thread. Ο πίνακας A [δυσανάγνωστο] που δείχνουν ποιο thread έγραψε σε κάθε θέση.
| thread | Επεξεργάζεται τις θέσεις A[i] |
|---|---|
| 0 | i=0, 1, 2 |
| 1 | i=3, 4, 5 |
| 2 | i=6, 7, 8 |
| 3 | i=9, 10, 11 |
A[0]=0, A[1]=0, A[2]=0, A[3]=1, A[4]=1, A[5]=1, A[6]=2, A[7]=2, A[8]=2, A[9]=3, A[10]=3, A[11]=3
A = {0,0,0,1,1,1,2,2,2,3,3,3}
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int var1 = rank + 1 - size;
int var2 = 0, var3 = 0;
MPI_Allreduce(&var1, &var2, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
MPI_Reduce(&var2, &var3, 1, MPI_INT, MPI_PROD, 0, MPI_COMM_WORLD);
printf("%d : %d\n", rank, var3);
[Σχήμα: αγκύλη με σημείωση «[δυσανάγνωστο] 3 διεργασίες», «mpirun -n 3
» και «[δυσανάγνωστο]»]
var1 = rank + 1 − 3
| rank | var1 |
|---|---|
| 0 | 0 + 1 − 3 = −2 |
| 1 | 1 + 1 − 3 = −1 |
| 2 | 2 + 1 − 3 = 0 |
Βήμα 2: var2 = −2 + (−1) + 0 = −3. Άρα και τα 3 processes έχουν var2 = −3.
Βήμα 3: var3 = (−3)(−3)(−3) = −27. Μόνο το process με rank=0 παίρνει το αποτέλεσμα στο var3, στα άλλα δύο (rank=1,2) θα έχουν var3=0 (δεν συνεισφέρουν σε αυτά).
Βήμα 4: - rank=0 → −27 - rank=1 → 0 - rank=2 → 0
Η σειρά [δυσανάγνωστο] διαφέρει αναλόγως της εκτέλεσης.
Σημείωση: ολόκληρη η σελίδα είναι γραμμένη με το χέρι (και η εκφώνηση και η λύση), δεν υπάρχει τυπωμένο κείμενο. Σημείωση: η φωτογραφία περιέχει χειρόγραφες απαντήσεις φοιτητή.