Ε-85: Ειδικά Θέµατα Λογισµικού Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων Χειµερινό Εξάµηνο 2009-10 «Επαναληπτικές Ασκήσεις» Παναγιώτης Χατζηδούκας (Π.Δ. 407/80) E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 1
ΠρογραµµατισµόςΝηµάτων E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 2
Αρχικοποίησηµιας Φοράς pthread_once_t once_block = PTHREAD_ONCE_INIT; pthread_mutex_t mutex; /* Initialization routine */ void once_init_routine(void) pthread_mutex_init(&mutex, NULL); /* Thread start routine that calls pthread_once */ void *thread_routine(void *arg) pthread_once(&once_block, once_init_routine);... int main() pthread_create(&t, NULL, thread_routine, NULL); pthread_once(&once_block, once_init_routine);... E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 3
Ιδιωτικά εδοµένα Νηµάτων pthread_key_t key; pthread_once_t key_once = PTHREAD_ONCE_INIT; void once_routine(void) pthread_key_create(&key, NULL); void routine() long *value; value = pthread_setspecific(key); void *thread_routine(void *) long *value; pthread_once(&key_once, once_routine); value = malloc(sizeof(long)); *value = (long)pthread_self(); pthread_setspecific(key, value); routine(); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 4
ΑκύρωσηΝηµάτων pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; void *test_wait(void *arg) pthread_setcancelstate(pthread_cancel_enable, NULL); pthread_setcanceltype(pthread_cancel_asynchronous, NULL); pthread_mutex_lock(&mut); /* already locked */ return NULL; int main()... pthread_mutex_lock(&mut); pthread_create(&pth, NULL, test_wait, NULL); sleep(5); pthread_cancel(pth); /* cancel blocked thread */ pthread_mutex_unlock(&mut); pthread_join(pth, NULL); /* join cancelled thread */ E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 5
Fibonacci (1/3) int fib(int n) if (n <= 1) return n; else return fib(n-1) + fib(n-2); void fib(int n, int *res) int r1, r2; if (n <= 1) *res = n; else fib(n-1, &r1); fib(n-2, &r2); *res = r1 + r2; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 6
Fibonacci (2/3) struct fib_arg int n; int res; ; void fib(struct arg *a) struct fib_arg a1, a2; int r1, r2; if (a->n <= 1) a->res = a->n; else a1->n = a->n-1; a2->n = a->n-2; fib(&a1); fib(&a2); a->res = a1.res + a2.res; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 7
Fibonacci (3/3) struct fib_arg int n; int res; ; void *fib(void *arg) struct fib_arg *a = (struct fib_arg *) arg; struct fib_arg a1, a2; pthread_t t1, t2; int r1, r2; if (a->n <= 1) a->res = a->n; else a1->n = a->n-1; a2->n = a->n-2; pthread_create(&t1, NULL, fib, (void *) &a1); pthread_create(&t2, NULL, fib, (void *) &a2); pthread_join(t1, NULL); pthread_join(t2, NULL); a->res = a1.res + a2.res; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 8
ΣειράΕκτέλεσης (1/2) #define N 10 void *routine(void *arg) long j; int id = (int) arg; printf("hello from thread:%d\n", id); return 0; int main() int i; pthread_t t[n]; for (i = 0; i < N; i++) pthread_create(&t[i], NULL, routine, (void *)i); for (i = 0; i < 10; i++) pthread_join(t[i], NULL); return 0; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 9
pthread_mutex_t m[n]; pthread_cond_t c[n]; void *routine(void *arg) long j; int id = (int) arg; ΣειράΕκτέλεσης (2/2) if (id > 0) pthread_mutex_lock(&m[id]); pthread_cond_wait(&m[id], &c[id]); printf("hello from thread:%d\n", id); if (id > 0) pthread_mutex_unlock(&m[id]); if (id < N) pthread_cond_signal(&c[id+1]); return 0; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 10
ΑναδροµικέςΚλειδαριές (1/4) int int int int othr_init_nest_lock(othr_nest_lock_t *lock); othr_destroy_nest_lock(othr_nest_lock_t *lock); othr_set_nest_lock(othr_nest_lock_t *lock); othr_unset_nest_lock(othr_nest_lock_t *lock); typedef struct pthread_mutex_t lock; /* real lock */ pthread_mutex_t ilock; /* data lock */ pthread_cond_t cond; int count; othr_t owner; othr_nest_lock_t; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 11
ΑναδροµικέςΚλειδαριές (2/4) int othr_init_nest_lock(othr_nest_lock_t *lock) pthread_mutex_init(&lock->ilock, NULL); pthread_mutex_init(&lock->lock, NULL); lock->count = 0; pthread_cond_init(&lock->cond, 0); return (0); int othr_destroy_nest_lock(othr_nest_lock_t *lock) pthread_mutex_destroy(&lock->lock); pthread_cond_destroy(&lock->cond); pthread_mutex_destroy(&lock->ilock); return (0); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 12
ΑναδροµικέςΚλειδαριές (3/4) int othr_set_nest_lock(othr_nest_lock_t *lock) pthread_mutex_lock(&lock->ilock); if (pthread_mutex_trylock(&lock->lock) == 0) /* lock it */ lock->owner = pthread_self(); /* Get ownership */ lock->count++; else if (pthread_equal(lock->owner, pthread_self())) /* mine */ lock->count++; else /* someone else */ while ( pthread_mutex_trylock(&lock->lock) ) pthread_cond_wait(&lock->cond, &lock->ilock); lock->owner = pthread_self(); lock->count++; pthread_mutex_unlock(&lock->ilock); return (0); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 13
ΑναδροµικέςΚλειδαριές (4/4) int othr_unset_nest_lock(othr_nest_lock_t *lock) pthread_mutex_lock(&lock->ilock); if (pthread_equal(lock->owner,pthread_self()) && lock->count > 0) lock->count--; if (lock->count == 0) pthread_mutex_unlock(&lock->lock); pthread_cond_signal(&lock->cond); pthread_mutex_unlock(&lock->ilock); return (0); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 14
ΜέγιστοΠίνακα (1/4) double find_max(double *A, int N) int i; double maxi; maxi = A[0]; for (i = 0; i < N; i++) if (maxi < A[i]) maxi = A[i]; return maxi; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 15
struct thr_arg double *A; int N; double *gmax; pthread_mutex_t *lock; int *flag; int id; int nthr; ; ΜέγιστοΠίνακα (2/4) void compute_bounds(int N, int me, int nthr, int *low, int *high) *low = me*(n/nthr); *high = (me+1)*(n/nthr); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 16
ΜέγιστοΠίνακα (3/4) void *find_max_(void *arg) struct thr_arg *a = (struct thr_arg *) arg; double *A = a->a; int N = a->n, me = a->id, nthr = a->nthr; int low, high; double lmax; int i; compute_bounds(n, me, nthr, &low, &high); lmax = A[low]; for (i = low+1; i < high; i++) if (lmax < A[i]) lmax = A[i]; pthread_mutex_lock(a->lock); if (*a->flag == 0) *a->flag = 1; *a->gmax = lmax; else if (*a->gmax < lmax) *a->gmax = lmax; pthread_mutex_unlock(a->lock); return 0; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 17
double find_max(double *A, int N) int i; double maxi; int nthr = 2; int flag = 0; struct thr_arg *a; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; pthread_t t[2]; for (i = 0; i < 2; i++) a = malloc(sizeof(struct thr_arg)); a->a = A; a->n = N; a->gmax = &maxi; a->lock = &m; a->flag = &flag; a->id = i; a->nthr = 2; pthread_create(&t[i], NULL, find_max_, a); for (i = 0; i < 2; i++) pthread_join(t[i], NULL); return maxi; ΜέγιστοΠίνακα (4/4) E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 18
ΜοντέλοΠρογραµµατισµού OpenMP E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 19
Χρησιµότητα οµών ιαµοίρασης Ακολουθιακός κώδικας for(i=0;i<n;i++) a[i] = a[i] + b[i]; Παράλληλο τµήµα OpenMP #pragma omp parallel int id, i, Nthrds, istart, iend; id = omp_get_thread_num(); Nthrds = omp_get_num_threads(); istart = id * N / Nthrds; iend = (id+1) * N / Nthrds; for(i=istart;i<iend;i++) a[i] = a[i] + b[i]; Παράλληλο τµήµα OpenMP µε omp for για διαµοίραση έργου #pragma omp parallel #pragma omp for schedule(static) for(i=0;i<n;i++) a[i] = a[i] + b[i]; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 20
Πρόγραµµαπ Ακολουθιακή έκδοση static long num_steps = 100000; double step; void main () int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; for (i=1;i<= num_steps; i++) x = (i-0.5)*step; sum = sum + 4.0/(1.0+x*x); pi = step * sum; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 21
Έκδοσηµε Παράλληλο Τµήµα #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () int i; double x, pi, sum[num_threads]; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads) #pragma omp parallel double x; int id; id = omp_get_thread_num(); for (i=id, sum[id]=0.0;i< num_steps; i=i+num_threads) x = (i+0.5)*step; sum[id] += 4.0/(1.0+x*x); for(i=0, pi=0.0;i<num_threads;i++) pi += sum[i] * step; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 22
Έκδοσηµε οµή ιαµοίρασης Έργου #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () int i; double x, pi, sum[num_threads]; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads) #pragma omp parallel double x; int id; id = omp_get_thread_num(); sum[id] = 0.0; #pragma omp for for (i=id, i< num_steps; i++) x = (i+0.5)*step; sum[id] += 4.0/(1.0+x*x); for(i=0, pi=0.0;i<num_threads;i++) pi += sum[i] * step; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 23
Έκδοσηµε reduction #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads) #pragma omp parallel for reduction(+:sum) private(x) for (i=1;i<= num_steps; i++) x = (i-0.5)*step; sum = sum + 4.0/(1.0+x*x); pi = step * sum; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 24
Περιβάλλον εδοµένων Παράδειγµα µε χρήση των PRIVATE και FIRSTPRIVATE int A, B, C; A = B = C = 1; #pragma omp parallel private(b) firstprivate(c) Μέσα στο παράλληλο τµήµα : Το A είναι κοινό µεταξύ των νηµάτων και ίσο µε 1 Τα B και C είναι ιδιωτικά σε κάθε νήµα. Το B έχει ακαθόριστη αρχική τιµή Το C έχει αρχική τιµή 1 Μετά το παράλληλο τµήµα : Οι τιµές των Β και C είναι ακαθόριστες E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 25
Τιτυπώνει το παρακάτω πρόγραµµα; #include <stdio.h> #include <omp.h> int main() int x = 2; #pragma omp parallel num_threads(2) shared(x) if (omp_get_thread_num() == 0) x = 5; else printf("1: Thread# %d: x = %d\n", omp_get_thread_num(),x ); #pragma omp barrier if (omp_get_thread_num() == 0) printf("2: Thread# %d: x = %d\n", omp_get_thread_num(),x ); else printf("3: Thread# %d: x = %d\n", omp_get_thread_num(),x ); return 0; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 26
Παράδειγµα #include <omp.h> void sub(float *x, int npoints) int iam, nt, ipoints, istart; #pragma omp parallel private(iam,nt,ipoints,istart) iam = omp_get_thread_num(); nt = omp_get_num_threads(); ipoints = npoints / nt; /* size of partition */ istart = iam * ipoints; /* starting array index */ if (iam == nt-1) /* last thread may do more */ ipoints = npoints - istart; subdomain(x, istart, ipoints); void main() float array[10000]; sub(array, 10000); void subdomain(float *x, int istart, int ipoints) int i; for (i = 0; i < ipoints; i++) x[istart+i] = 123.456; E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 27
Παράδειγµα nowait #include <math.h> void a8(int n, int m, float *a, float *b, float *y, float *z) int i; #pragma omp parallel #pragma omp for nowait for (i=1; i<n; i++) b[i] = (a[i] + a[i-1]) / 2.0; #pragma omp for nowait for (i=0; i<m; i++) y[i] = sqrt(z[i]); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 28
int counter = 0; #pragma omp threadprivate(counter) int increment_counter() counter++; return(counter); Παράδειγµα threadprivate int increment_counter_2() static int counter_2 = 0; #pragma omp threadprivate(counter_2) counter_2++; return(counter_2); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 29
Εµφωλευµένοςπαραλληλισµός void work(int i, int j) void good_nesting(int n) int i, j; #pragma omp parallel default(shared) #pragma omp for for (i=0; i<n; i++) #pragma omp parallel shared(i, n) #pragma omp for for (j=0; j < n; j++) work(i, j); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 30
Συναρτησιακόςπαραλληλισµός (1/2) V = alpha(); W = beta(); X = gamma(v, W); Y = delta(); printf( %f\n, epsilon(x,y)); #pragma omp parallel sections #pragma omp section V = alpha(); #pragma omp section W = beta(); #pragma omp section Y = delta(); X = gamma(v, W); printf( %f\n, epsilon(x,y)); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 31
Συναρτησιακόςπαραλληλισµός (2/2) #pragma omp parallel #pragma omp sections #pragma omp section V = alpha(); #pragma omp section W = beta(); #pragma omp sections #pragma omp section X = gamma(v, W); #pragma omp section Y = delta(); printf( %f\n, epsilon(x,y)); E-85: Ε.Θ.Λ: Προγραµµατισµός Συστηµάτων Υψηλών Επιδόσεων 32