EM 361: Παξάιιεινη Υπνινγηζκνί Φαξκαλδάξεο Βαγγέιεο, Τκήκα Δθαξκνζκέλωλ Μαζεκαηηθώλ Παλεπηζηήκην Κξήηεο, Φεηκεξηλό Δμάκελν 2010/11 Κεθάιαην 5: (A) Λνγηζκηθό, Βαζηθέο Δθαξκνγέο OpenMP Παξάιιειεο Γιώζζεο Γεδνκέλωλ (Fortran 90, C, C++). Βηβιηνζήθεο Αληαιιαγήο Μελπκάηωλ (Message Passing Interface, MPI), OpenMP, POSIX Threads. Παξάιιεινη Αιγόξηζκνη κε Φξήζε OpenMP.
Λνγηζκηθό Λνγηζκηθό γηα αλάπηπμε παξάιιεισλ πξνγξακκάησλ: Γηαζέζηκα παθέηα: γεληθήο ρξήζεσο ή εμεηδηθεπκέλνη αιγόξηζκνη. -- Υπέξ: Δύθνιε ιύζε. -- Καηά: Με-θαηαλόεζε ηνπ αιγόξηζκνπ θαη ηνπ πξνγξάκκαηνο. Αλάπηπμε θώδηθα από ηελ αξρή -- Υπέξ: Δπειημία, Πξνζαξκνζηηθόηεηα, Καηαλόεζε. -- Καηά: Μπνξεί λα είλαη πνιύ ρξνλνβόξα ιύζε. Γπλαηόηεηα ρξήζεο πξνγξακκάησλ από παξάιιειεο βηβιηνζήθεο: π.ρ. ρξήζε ησλ βηβιηνζεθώλ BLAS, ScaLAPack θ.α. -- Υπέξ: Οη βηβιηνζήθεο πεξηέρνπλ πνιύ γξήγνξνπο θαη δνθηκαζκέλνπο αιγόξηζκνπο. -- Καηά: Γύζθνιε θαηαλόεζε ηνπ αιγόξηζκνπ θαη ηνπ πξνγξάκκαηνο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 2
Λνγηζκηθό Παξάιιεινπ Πξνγξακκαηηζκνύ Γηεπηθάλεηα Πξνγξακκαηηζκνύ θαη Δθαξκνγώλ (Application Programming Interface) Παξάιιειεο Γιώζζεο Γεδνκέλσλ (Parallel Data Languages): Πξάμεηο κεηαμύ δηαλπζκάησλ, πηλάθσλ (π.ρ. Fortran 90, high Performance Fortran) Μνληέιν Γεζκώλ (Threads model): Πνιιαπιέο δηεξγαζίεο πνπ επηθνηλσλνύλ κέζσ ηνπ θπξίσο πξνγξάκκαηνο. Μνληέιν Μεηαθνξάο Μελύκαηνο (Message Passing model): νη δηεξγαζίεο επηθνηλσλνύλ κε αληαιιαγέο κελπκάησλ. Απηόκαηνο Παξαιιειηζκόο Απηόκαηε κεηαηξνπή ηνπ θώδηθα. Σπλήζσο κεηαηξνπή απιώλ επαλαιεπηηθώλ δηαδηθαζηώλ (loops). Δύθνινη ζηε ρξήζε αιιά κε πεξηνξηζκέλεο δπλαηόηεηεο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 3
Παξάιιειεο Γιώζζεο Γεδνκέλωλ Σπλήζσο εκπεξηέρνπλ ζύλνιν εληνιώλ πξνέθηαζεο ηεο θαλνληθήο (ζεηξηαθή) γιώζζαο. Fortran 90 θαη 95 (F90, F95): Πξάμεηο κεηαμύ δηαλπζκάησλ, πηλάθσλ Fortran Real x(100), y(100).. Do i = 1, 100 y(i) = y(i)*x(i) End do F90 Real :: x(100), y(100). y = y*x*z High Performance Fortran (HPF): Πεξηέρεη εηδηθέο εληνιέο (compiler directives) πνπ ιέλε ζηνλ compiler πώο λα θαηαλέκεη δεδνκέλα κεηαμύ ησλ επεμεξγαζηώλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 4
Παξάιιειεο Γιώζζεο Γεδνκέλωλ Πνιιέο παξαιιαγέο/επεθηάζεηο ηεο C. Οη πεξηζζόηεξεο από απηέο έρνπλ αλαπηπρζεί γηα ζπγθεθξηκέλεο αξρηηεθηνληθέο ππνινγηζηηθώλ ζπζηεκάησλ. C*: developed in ~ 1990 by Thinking Machines Corporation, for the connection machine (SIMD algorithms). Sequent C: parallel programming under DYNIX (a version of UNIX). ncube C + : επέθηαζε ηεο C θαηά ηελ νπνία έλα πξόγξακκα ηξέρεη νιόθιεξν ζε θάζε επεμεξγαζηή. Μνληέιν SPMD (Single Pogram Multiple Data). OCCAM: developd in ~ 1978 by Immos Limited for the Transputer series of processor. C-LINDA: consists of several operations that work on tople space, a speical form of shared memory. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 5
Μνληέιν Γεζκώλ (Threads model) Σην κνληέιν δεζκώλ παξάιιεινπ πξνγξακκαηηζκνύ κηα δηεξγαζία κπνξεί λα έρεη πνιιαπινύο, ηαπηόρξνλνπο δξόκνπο εθηέιεζεο (execution paths). Παξάδεηγκα: θύξην πξόγξακκα main.exe πνπ πεξηιακβάλεη ζεηξά από ππνξνπηίλεο. Μεηά από εθηέιεζε ελόο ζεηξηαθνύ κέξνπο ην main.exe δεκηνπξγεί κηα ζεηξά από εξγαζίεο (δέζκεο) νη νπνίεο κπνξνύλ λα εθηειεζηνύλ ηαπηόρξνλα. Κάζε εξγαζία έρεη ηνπηθά δεδνκέλα (local data) θαη κνηξάδεηαη ηα δεδνκέλα ηνπ main.exe. Καηόπηλ αλαηίζεηαη ζε δηαθνξεηηθό επεμεξγαζηή. Οη δέζκεο επηθνηλσλνύλ κεηαμύ ηνπο κέζα από ηελ γεληθή (global) θνηλή κλήκε. Τν main.exe είλαη ππεύζπλν γηα ηελ δεκηνπξγία ησλ δεζκώλ θαη ηελ παξνρή ησλ θνηλώλ δεδνκέλσλ πνπ ρξεηάδεηαη θάζε δέζκε. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 6
Μνληέιν Γεζκώλ (Threads model) Από πιεπξάο πξνγξακκαηηζκνύ ην κνληέιν δεζκώλ ζπλήζσο πεξηιακβάλεη Βηβιηνζήθε από ππνξνπηίλεο πνπ θαινύληαη από ην θπξίσο πξόγξακκα. Σεη από νδεγίεο γηα ηνλ compiler πνπ εκπεξηέρνληαη ζηνλ παξάιιειν θώδηθα (compiler directives). Καηάιιειν γηα ζπζηήκαηα κνηξαδόκελεο θνηλήο κλήκεο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 7
Μνληέιν Γεζκώλ (Threads model) Γηαθνξεηηθέο εθαξκνγέο ηνπ κνληέινπ δεζκώλ: POSIX Γέζκεο: Βαζίδεηαη ζε ζπλαξηήζεηο βηβιηνζήθεο. Γηαζέζηκν κόλν γηα ηελ C. Σπρλά αλαθέξεηαη θαη σο Pthreads. Πξνζθέξεη πνιύ εμεηδηθεπκέλν παξαιιειηζκό. Αξθεηά πνιύπινθν ζηελ ρξήζε. OpenMP: Βαζίδεηαη ζε compiler directives. Γηαζέζηκν ηόζν γηα C/C++ θαη Fortran. Μπνξεί λα είλαη πνιύ εύθνιν ζηελ ρξήζε, εηδηθά γηα παξαιιειηζκό επαλαιεπηηθώλ δηαδηθαζηώλ (loops). Πξνζνρή: ην κνληέιν δεζκώλ είλαη αξθεηά ηζρπξό γηα shared memory machines αιιά όρη γηα άιιεο αξρηηεθηνληθέο. Γύζθνιε ε κεηαθνξά ηνπ παξάιιεινπ θώδηθα ζε δηαθνξεηηθά ζπζηήκαηα. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 8
Μνληέιν Μεηαθνξάο Μελύκαηνο (Message Passing) Τν κνληέιν κεηαθνξάο κελύκαηνο έρεη ηα αθόινπζα ραξαθηεξηζηηθά: Υπάξρεη ζύλνιν από δηεξγαζίεο νη νπνίεο ρξεζηκνπνηνύλ ηελ δηθηά ηνπο κλήκε θαηά ηε δηάξθεηα ησλ ππνινγηζκώλ. Οη δηεξγαζίεο αληαιιάζνπλ δεδνκέλα ζηέιλνληαο θαη ιακβάλνληαο κελύκαηα. Οη δηαδηθαζία αληαιιαγήο ζπλήζσο ρξεηάδεηαη ζπλεξγαζία κεηαμύ ησλ δηεξγαζηώλ. Παξάδεηγκα ε απνζηνιή κελύκαηνο πξέπεη ζπλδπάδεηαη κε ηελ ιήςε ηνπ από άιιε δηεξγαζία. Η επηθνηλσλία γίλεηαη κέζα από βηβιηνζήθεο αληαιιαγήο κελπκάησλ (π.ρ. MPI, PVM) ηύπνπ SEND θαη RECEIVE. Η βηβιηνζήθε MPI (Message Passing Interface) είλαη ην δηεζλέο ζηάληαξη. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 9
Μνληέιν Μεηαθνξάο Μελύκαηνο (Message Passing) Από πιεπξάο πξνγξακκαηηζκνύ ν ρξήζηεο είλαη απνιύησο ππεύζπλνο γηα ηνλ πξνζδηνξηζκό ηεο παξάιιειεο δηαδηθαζίαο. Καηάιιειν ηόζν γηα ζπζηήκαηα θνηλήο αιιά θαη θαηαλεκεκέλεο κλήκεο. Οη θώδηθεο επεθηείλνληαη θαη κεηαθέξνληαη ζε ζπζηήκαηα δηαθνξεηηθήο αξρηηεθηνληθήο ζρεηηθά εύθνια. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 10
Απηόκαηνο Παξαιιειηζκόο Παξαιιειηζκόο ζεηξηαθνύ θώδηθα κέζσ απηόκαησλ παξάιιεισλ κεηαγισηηηζηώλ (parallel compilers). Δύθνινη ζηε ρξήζε: απαηηείηαη ιίγε έσο θαζόινπ δνπιεία από ηνλ ρξήζηε. Απηόκαηνο παξαιιειηζκόο επαλαιεπηηθώλ δηαδηθαζηώλ (loops): αλάζεζε θνκκαηηώλ ηεο επαλαιεπηηθήο δηαδηθαζίαο ζε δηαθνξεηηθνύο επεμεξγαζηέο. Μεηνλεθηήκαηα: Παξαιιειηζκόο δηεξγαζηώλ δελ είλαη εθηθηόο. Γελ είλαη επέιηθηνο. Μπνξεί λα παξάγεη ιάζνο απνηειέζκαηα. Γεληθά ηα απνηειέζκαηα είλαη πνιύ θησρά: ε πνιππινθόηεηα ησλ επαλαιεπηηθώλ δηαδηθαζηώλ δελ επηηξέπεη ηελ απηόκαηε παξαιειινπνίεζε ηνπο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 11
Κεθάιαην 5: Open Multi-Processing (OpenMP) Βαζηθή ηδέα: Φξεζηκνπνηώληαο έλα ζύλνιν εηδηθώλ εληνιώλ παξαιιειίδνπκε κέξε ηνπ ππάξρνληα ζεηξηαθνύ θώδηθα. Θα δνύκε πην αλαιπηηθά: Τη είλαη ην OpenMP; Δηζαγωγηθά. Έλα απιό πξόγξακκα ζε OpenMP. Παξαιιειηζκόο επαλαιεπηηθώλ δηαδηθαζηώλ (loops) ρξεζηκνπνηώληαο OpenMP. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 12
Τη Δίλαη ην OpenMP; To OpenMP είλαη κηα Γηεπηθάλεηα Πξνγξακκαηηζκνύ θαη Δθαξκνγώλ (Application Programming Interface) παξαιιειηζκνύ γηα ζπζηήκαηα θνηλήο κλήκεο (shared memory systems). Απνηειείηαη από: Compiler Directives Runtime Library Routines Environmental Variables Φαξαθηεξηζηηθά ηνπ OpenMP: Standard γηα ηα πεξηζζόηεξα ζπζηήκαηα θνηλήο κλήκεο, Δύθνιν ζηε ρξήζε, Απνηειεζκαηηθόηεηα, Φνξεηόηηηα. Σρεδηαζκέλν ην γηα C/C++ όζν θαη Fortran/ Fortran 90. Ιζηνξία θαη Δμέιημε: ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 13
Τη Δίλαη ην OpenMP; To OpenMP βαζίδεηαη ζηελ ύπαξμε πνιιαπιώλ δεζκώλ (multi-threaded) ζε δηεξγαζίεο θνηλήο κλήκεο. Τν πξόγξακκα ρσξίδεηαη ζε παξάιιεια θαη ζεηξηαθά κέξε. Κάζε OpenMP πξόγξακκα μεθηλά κε κηα αξρηθή δηεξγαζία (master thread) ε νπνία εθηειείηαη ζεηξηαθά έσο όηνπ θηάζνπκε ζηελ πξώηε παξάιιειε πεξηνρή. Compiler Directive based: ν παξαιιειηζκόο επηηπγράλεηαη κε ηελ ρξήζε θαηάιιεισλ νδεγηώλ πνπ εκπεξηέρνληαη ζηνλ θώδηθα (C/C++ ή Fortran). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 14
Program Hallo Παξάδεηγκα: Hello world πξόγξακκα Απιό πξόγξακκα ζε Fortran Integer :: NTHREADS, TID, OMP_GET_NUM_THREADS, OMP_GET_THREAD_NUM!Fork a team of threads with each thread having a private TID variable!$omp PARALLEL PRIVATE(TID)! Obtain and print thread id TID = OMP_GET_THREAD_NUM() PRINT *, 'Hello World from thread = ', TID! Only master thread does this IF (TID == 0) THEN NTHREADS = OMP_GET_NUM_THREADS() PRINT *, 'Number of threads = ', NTHREADS END IF! All threads join master thread and disband!$omp END PARALLEL Stop End ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 15
#include <omp.h> main () { int nthreads, tid; Παξάδεηγκα: Hello world πξόγξακκα Απιό πξόγξακκα ζε C /* Fork a team of threads with each thread having a private tid variable */ #pragma omp parallel private(tid) { /* Obtain and print thread id */ tid = omp_get_thread_num(); printf("hello World from thread = %d\n", tid); } /* Only master thread does this */ if (tid == 0) { nthreads = omp_get_num_threads(); printf("number of threads = %d\n", nthreads); } } /* All threads join master thread and terminate */ ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 16
Πεξηγξαθή Απινύ Πξνγξάκκαηνο Η δηάηαμε ησλ εληνιώλ/νδεγηώλ OpenMP (compiler directives) είλαη: Fortran:!$OMP directive.name [clause] Παξάδεηγκα:!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(BETA,PI) Τν end directive είλαη πξναηξεηηθό αιιά βνεζά ζηνλ έιεγρν ηνπ θώδηθα. Case Insensitive. Παξάδεηγκα:!$OMP directive [ structured block of code ]!$OMP end directive C/C++: #pragma omp directive.name [clause] Παξάδεηγκα: #pragma omp parallel default(shared) private(beta,pi) Case Sensitive. Γεληθά: Οη compilers εκπεξηέρνπλ κηα κεηαβιεηή ε νπνία θαηά ηε κεηάθξαζε ελεξγνπνηεί όιεο ηηο OpenMP εληνιέο (OpenMP directives). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 17
Γεκηνπξγία Παξάιιειεο Πεξηνρήο Η παξάιιειε πεξηνρή (parallel region) είλαη έλα θνκκάηη ηνπ θώδηθα πνπ κπνξεί λα εθηειεζηεί από πνιιαπιέο δέζκεο (threads). Δίλαη ε ζεκαληηθόηεξε εληνιή ηνπ OpenMP. Μόιηο ην πξόγξακκα ζπλαληά κηα εληνιή parallel δεκηνπξγεί πνιιαπιέο threads νη νπνίεο εθηεινύλ ηνλ ίδην θώδηθα. Format: Fortran:!$OMP PARALLEL [clause...] IF (scalar_logical_expression) PRIVATE (list) SHARED (list) DEFAULT (PRIVATE FIRSTPRIVATE SHARED NONE) FIRSTPRIVATE (list) REDUCTION (operator: list) COPYIN (list) NUM_THREADS (scalar-integer-expression) block!$omp END PARALLEL ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 18
Παξάιιειε Πεξηνρή Format: C: #pragma omp parallel [clause...] newline if (scalar_expression) private (list) shared (list) default (shared none) firstprivate (list) reduction (operator: list) copyin (list) num_threads (integer-expression) structured_block Η κεηαβιεηή πεξηβάιινληνο (environmental variable) OMP_NUM_THREADS θαζνξίδεη πόζεο threads ζα ρξεζηκνπνηεζνύλ. Σπλήζσο ν αξηζκόο ησλ threads είλαη ν αξηζκόο ησλ επεμεξγαζηώλ νπ ζπζηήκαηνο. Οη threads αξηζκνύληαη από 0 σο P-1. omp_get_thread_num(): επηζηξέθεη ηνλ αξηζκό ηεο ζπγθεθξηκέλεο thread. omp_get_num_threads(): επηζηξέθεη ηνλ ζπλνιηθό αξηζκό ησλ threads. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 19
Παξαιιειηζκόο Δπαλαιεπηηθώλ Γηαδηθαζηώλ Παξαιιειηζκόο επαλαιεπηηθώλ δηαδηθαζηώλ (loops) κε ηελ εληνιή!omp do. Format: C: #pragma omp for [clause...] newline schedule (type [,chunk]) for_loop Fortran:!$omp do [clause...] SCHEDULE (type [,chunk]) do_loop!$omp end do schedule: πεξηγξάθεη πσο θαηαλέκνληαη νη επαλαιήςεηο ηνπ loop. Ο ηύπνο (type) κπνξεί λα είλαη ζηαηηθόο (static) ή δπλακηθόο (dynamic). Κάζε θνκκάηη έρεη κέγεζνο chunk. Αλ ην κέγεζνο δελ νξίδεηαη νη επαλαιήςεηο ηζνθαηαλέκνληαη (αλ απηό είλαη δπλαηόλ) ζε θάζε επεμεξγαζηή. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 20
Παξάδεηγκα: Παξαιιειηζκόο Loop κε OpenMP #include <omp.h> #define CHUNKSIZE 100 #define N 1000 main () { int i, chunk; float a[n], b[n], c[n]; /* Some initializations */ for (i=0; i < N; i++) a[i] = b[i] = i * 1.0; chunk = CHUNKSIZE; #pragma omp parallel shared(a,b,c,chunk) private(i) { #pragma omp for schedule(dynamic,chunk) nowait for (i=0; i < N; i++) c[i] = a[i] + b[i]; } /* end of parallel section */ } ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 21
Πεξηζζόηεξεο Δληνιέο OpenMP OMP Section: Φξεζηκνπνηείηαη γηα παξαιιειηζκό κε επαλαιεπηηθήο δηαδηθαζίαο (όρη loop). Γειώλεη όηη ε αθόινπζε πεξηνρή ζα θαηαλεκεζεί ζε δηαθνξεηηθέο threads. Κάζε section εθηειείηαη από άιιε thread. Format: C: #pragma omp sections [clause...] newline { #pragma omp section newline block of code #pragma omp section newline block of code } Fortran:!$OMP SECTIONS [clause...]!$omp SECTION block of code!$omp SECTION block of code!$omp END SECTIONS ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 22
Πεξηζζόηεξεο Δληνιέο OpenMP OMP Master: Γειώλεη όηη ε αθόινπζε πεξηνρή ζα εθηειεζηεί κόλν από ηελ θεληξηθή thread (θεληξηθό επεμεξγαζηή). C: #pragma omp master Fortran:!$OMP MASTER OMP Single: Γειώλεη όηη ε αθόινπζε πεξηνρή ζα εθηειεζηεί κόλν από κία (νπνηαδήπνηε) thread. C: #pragma omp single Fortran:!$OMP SINGLE OMP PARALLEL DO/ parallel for: Σπλδπαζκόο 2 εληνιώλ OpenMP. Ιζνδύλακν κε ρξήζε 2 δηαδνρηθώλ εληνιώλ, δειαδή #pragma omp parallel for είλαη ηζνδύλακν κε έλα #pragma omp parallel πνπ αθνινπζείηαη από έλα #pragma omp for. Πνιιέο Αθόκε (Γείηε ην Manual ηνπ OpenMP). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 23
Βηβιηνγξαθία Parallel Programming, B. Wilkinson, M. Allen, Prentice Hall, 2nd Ed. 2005. Introduction to Parallel Computing, A. Grama, G. Karypis, V. Kumar, A. Gupta, Addison- Wesley, 2003. Parallel Computing: Theory and Practice, M. J. Quinn, McGraw-Hill, 1994. POSIX Threads: http://www.yolinux.com/tutorials/linuxtutorialposixthreads.html OpenMP: http://openmp.org/wp/ ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 24