EM 361: Παξάιιεινη Υπνινγηζκνί Φαξκαλδάξεο Βαγγέιεο, Τκήκα Δθαξκνζκέλσλ Μαζεκαηηθώλ Παλεπηζηήκην Κξήηεο, Φεηκεξηλό Δμάκελν 2010/11 Κεθάιαην 5: (B) Message Passing Interface (MPI)
Message Passing Interface (MPI) Βαζηθή ηδέα: Ο ρξήζηεο γξάθεη ηνλ θώδηθα (π.ρ. ζε C ή Fortran) θαη κεηά ρξεζηκνπνηεί ηηο εληνιέο ηεο θαηάιιειεο βηβιηνζήθεο γηα ηνλ παξαιιειηζκό ησλ δηεξγαζηώλ. Θα δνύκε πην αλαιπηηθά: Τη είλαη ην MPI; Δηζαγσγηθά. Έλα απιό πξόγξακκα ζε MPI. Υπνπξνγξάκκαηα Γηαρείξηζεο ηνπ MPI Παξάιιεινπ Πεξηβάιινληνο. Υπνπξνγξάκκαηα Δπηθνηλσλίαο ησλ Γηεξγαζηώλ. Τνπνινγία ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 2
Τη Δίλαη ην MPI; To MPI είλαη κηα βηβιηνζήθε ππνπξνγξακκάησλ αληαιιαγήο κελπκάησλ θαη κεηαθνξάο δεδνκέλσλ. Φαξαθηεξηζηηθά ηνπ MPI: Απνηειεζκαηηθόηεηα, Φνξεηόηηηα-Μεηαβηβαζηκόηεηα, Δπειημία. Αλεπηπγκέλν γηα πιεζώξα (ζρεδόλ όια) ππνινγηζηηθώλ ζπζηεκάησλ δηαθνξεηηθήο αξρηηεθηνληθήο. Σρεδηαζκέλν ην γηα C/C++ όζν θαη Fortran/ Fortran 90. Ιζηνξία θαη Δμέιημε: 1980 αξρέο 1990: Αλνκνηνγελέο ινγηζκηθό. Πξνβιήκαηα κεηαθνξάο πξνγξακκάησλ. Αλάγθε δεκηνπξγίαο δηεζλνύο πξνηύπνπ. 1992 1994: Καζηέξσζε ηνπ MPI σο δηεζλέο πξόηππν. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 3
Τη Δίλαη ην MPI; Λόγνη ρξεζηκνπνίεζεο ηνπ MPI: Γηεζλέο Πξόηππν: Τν MPI είλαη ε ζηάληαξη βηβιηνζήθε αληαιιαγήο κελπκάησλ. Υπνζηεξίδεηαη από όια ηα ππνινγηζηηθά ζπζηήκαηα HPC (High Performance Computing). Γηαζεζηκόηεηα: Υπάξρνπλ δηάθνξεο δηαζέζηκεο πινπνηήζεηο (implementations). Τν ινγηζκηθό είλαη ειεύζεξν. Απνηειεζκαηηθόηεηα: νη δηαθνξεηηθέο πινπνηήζεηο εθκεηαιιεύνληαη ραξαθηεξηζηηθά ηνπ hardware κε απνηέιεζκα ηελ θαιύηεξε απόδνζε ησλ πξνγξακκάησλ. Φνξεηόηηηα: νη θώδηθεο κεηαθέξνληαη εύθνια ζε δηαθνξεηηθά ζπζηήκαηα. Λεηηνπξγηθόηεηα: Σην MPI-1 ππάξρνπλ 128 ππνπξνγξάκκηα θαη ζην MPI-2 152. Τν MPI είλαη αλεπηπγκέλν γηα ζπζηήκαηα θνηλήο θαη θαηαλεκεκέλεο κλήκεο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 4
Γεληθή Γνκή ελόο Πξνγξάκκαηνο MPI ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 5
Παξάδεηγκα: Hello world πξόγξακκα Απιό πξόγξακκα ζε C #include <stdio.h> #include "mpi.h" int main(argc,argv) { int numtasks, rank, MPI_Init (&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Comm_rank(MPI_COMM_WORLD, &rank); printf ("Hello world from process %d of %d\n", rank, numtasks); MPI_Finalize(); } ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 6
Παξάδεηγκα: Hello world πξόγξακκα Απιό πξόγξακκα ζε Fortran program simple include 'mpif.h' integer numtasks, rank, ierr call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) print *, 'Hello world from process ', rank, 'of', numtasks call MPI_FINALIZE(ierr) stop end ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 7
Πεξηγξαθή Απινύ Πξνγξάκκαηνο Οη εληνιέο #include "mpi.h", include 'mpif.h' απαηηνύληαη από όια ηα πξνγξάκκαηα / ππνξνπηίλεο πνπ ρξεζηκνπνηνύλ MPI θαζώο είλαη απηέο πνπ παξέρνπλ πξόζβαζε ζηελ βηβιηνζήθε MPI. Η δηάηαμε ησλ ζπλαξηήζεσλ MPI είλαη: C/C++: MPI_Xxxxx (parameter, ) Παξάδεηγκα: MPI_Send (&buf, count, type, dest, comm) Όιεο νη ζπλαξηήζεηο C ηνπ MPI επηζηξέθνπλ δείθηεο ιαζώλ (error code) ηύπνπ αθεξαίνπ. Fortran: call MPI_XXXX (parameter,, ierr) Παξάδεηγκα: MPI_SEND (buf, count, type, dest, comm, ierr) Τα ππνπξνγξάκκαηα Fortran επηζηξέθνπλ δείθηεο ιαζώλ ηύπνπ αθεξαίνπ σο ην ηειεπηαίν όξηζκά ηνπο. Οη θνηλέο εληνιέο ηνπ πξνγξάκκαηνο (π.ρ. print *, 'Hello world from process ', rank, 'of', numtasks) είλαη ηνπηθέο, δειαδή εθηεινύληαη από θάζε επεμεξγαζηή. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 8
Πεξηγξαθή Απινύ Πξνγξάκκαηνο: Υπνπξνγξάκκαηα Γηαρείξηζεο Γηαρεηξηζηήο Δπηθνηλσλίαο (Γ.Δ.) - Communicator: Έλα ζύλνιν δηεξγαζηώλ πνπ κπνξνύλ λα ζηείινπλ/ιάβνπλ κελύκαηα. MPI_COMM_WORLD είλαη ν πξνθαζνξηζκέλνο Γ.Δ. Σπλήζσο ν αξηζκόο ησλ δηεξγαζηώλ ζπκπίπηεη κε ηνλ αξηζκό ησλ επεμεξγαζηώλ πνπ ζέινπκε λα ρξεζηκνπνηήζνπκε. Οη επεμεξγαζηέο κπνξεί λα είλαη νπνπδήπνηε. Ταμηλόκεζε: Μέζα ζηνλ Γ.Δ. θάζε δηεξγαζία αξηζκείηαη κε έλα αθέξαην αξηζκό (rank) μεθηλώληαο από ην 0. Γειαδή Ρ δηεξγαζίεο αξηζκνύληαη από 0 σο Ρ-1. Η ηαμηλόκεζε ρξεζηκνπνηείηαη από ηνλ ρξήζηε ζηελ επηθνηλσλία κεηαμύ ησλ δηεξγαζηώλ (π.ρ. if rank=0 do something / if rank=1 do something else). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 9
Υπνπξνγξάκκαηα-Σπλαξηήζεηο Γηαρείξηζεο MPI MPI_Init: Υπνδειώλεη ηελ έλαξμε ηνπ MPI. Πξέπεη λα θαιείηαη πξηλ από νπνηαδήπνηε άιιε εληνιή ηνπ MPI. C: MPI_Init (&argc, &argv); Fortran: call MPI_INIT(ierr) MPI_Comm_size: Πξνζδηνξίδεη ηνλ αξηζκό ησλ δηεξγαζηώλ-επεμξγαζηώλ πνπ ζρεηίδνληαη κε ηνλ ΓΔ. C: MPI_Comm_size (comm, &size); Fortran: call MPI_COMM_SIZE(comm, size, ierr) MPI_Comm_rank: Πξνζδηνξίδεη ηνλ αξηζκό ηεο δηεξγαζίαο πνπ θαιείηαη κέζα ζηνλ ΓΔ. C: MPI_Comm_rank (comm, &rank); Fortran: call MPI_COMM_RANK(comm, rank, ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 10
Υπνπξνγξάκκαηα Γηαρείξηζεο MPI MPI_Abort: Τεξκαηίδεη όιεο ηηο δηεξγαζίεο MPI πνπ ζρεηίδνληαη κε ηνλ Γ.Δ. C: MPI_Abort (comm, ierr); Fortran: call MPI_ABORT(comm, ierr) MPI_Get_processor_name: Δπηζηξέθεη ην όλνκα ηνπ επεμεξγαζηή θαζώο θαη ην κήθνο (αξηζκόο ραξαθηήξσλ) ηνπ νλόκαηνο. C: MPI_Get_processor_name (&name, &namelength); Fortran: call MPI_GET_PROCESSOR_NAME(name, namelength) MPI_Wtime: Δπηζηξέθεη ηνλ ρξόλν (wall time clock), ζε δεπηεξόιεπηα ελόο επεμεξγαζηή. Φξεζηκνπνηείηαη γηα κέηξεζε ηνπ ρξόλνπ εθηέιεζεο κηαο δηεξγαζίαο. C: MPI_Wtime (); Fortran: call MPI_WTIME() MPI_Finalize: Υπνδειώλεη ηε ιήμε ρξήζεο ηνπ MPI. Πξέπεη λα θαιείηαη ζην ηέινο. C: MPI_Finalize (&argc, &argv); Fortran: call MPI_FINALIZE(ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 11
Υπνπξνγξάκκαηα Δπηθνηλσλίαο MPI Βαζηθά ζηνηρεία: Πνηνο ζηέιλεη ην κήλπκα / πνπ ζηάιζεθε ην κήλπκα. Μέγεζνο Τύπνο ησλ δενκέλσλ πνπ ζηάιζεθαλ. Λήςε ηνπ κελύκαηνο Αλαγλώξηζε ησλ δεδνκέλσλ. Τύπνη επηθνηλσλίαο: Μηα-πξνο-κηα επηθνηλσλία (Point-to-Point Communication). Σπιινγηθή επηθνηλσλία (Collective Communication). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 12
Μηα-πξνο-κηα Δπηθνηλσλία Point-to-Point Communication Η απνζηνιή / ιήςε κελπκάησλ γίλεηαη αλάκεζα από κόλν δύν δηεξγαζίεο. Μηα δηεξγαζία εθηειεί ηελ απνζηνιή θαη κηα ηελ ιήςε. Γηάθνξνη ηύπνη ζπλαξηήζεσλ απνζηνιήο/ιήςεο κελπκάησλ: Σπγρξνληζκέλε απνζηνιή (Synchronous send). Πεξηνξηζκέλε απνζηνιή / πεξηνξηζκέλε ιήςε (Blocking send / Blocking receive). Με-πεξηνξηζκέλε απνζηνιή / Με-πεξηνξηζκέλε ιήςε (Non-blocking send / Nonblocking receive). Σπλδπαζκέλε απνζηνιή/ιήςε (Combined send/receive). Κάζε ηύπνο ζπλάξηεζεο απνζηνιήο κπνξεί λα ζπλδπαζηεί κε νπνηνδήπνηε ηύπν ζπλάξηεζεο ιήςεο. Υπάξρνπλ επίζεο αξθεηέο ζπλαξηήζεηο-ππνπξνγξάκκαηα παξαθνινύζεζεο θαη ειέγρνπ απνζηνιήο/ιήςεο κελπκάησλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 13
Point-to-Point Communication / Buffering Θεσξεηηθά θάζε εληνιή απνζηνιήο κπνξεί λα είλαη ζπγρξνληζκέλε κε ηελ εληνιή ιήςεο. Όκσο απηό είλαη πνιύ ζπάλην. Παξάδεηγκα: Μηα εληνιή απνζηνιήο εθηειείηαη 5 δεπηεξόιεπηα πξηλ ηελ αληίζηνηρε εληνιή ιήςεο. Πνπ βξίζθνληαη ηα δεδνκέλα θαηά ηε δηάξθεηα ηεο αλακνλήο; Πνιιαπιά κελύκαηα θηάλνπλ ζηε ίδηα δηεξγαζία. Τη γίλεηαη κε ηα δεδνκέλα πνπ βξίζθνληαη ζε αλακνλή; Η πινπνίεζε ηνπ MPI απνθαζίδεη ηη ζπκβαίλεη. Σπλήζσο δεζκεύεηαη έλαο Πξνζσξηλόο Φώξνο Μλήκεο Σπζηήκαηνο (ΠΦΜΣ) (System Buffer). Πξνζσξηλόο Φώξνο Μλήκεο Σπζηήκαηνο: Γηαρεηξίδεηαη από ην MPI, ν ρξήζηεο δελ έρεη πξόζβαζε ζε απηόλ. Έρεη κηθξή ρσξεηηθόηεηα. Φξεζηκνπνηείηαη από εληνιέο απνζηνιήο θαη ιήςεο. Βειηηώλεη ηελ απόδνζε ηνπ πξνγξάκκαηνο. Ο ρώξνο κλήκεο πνπ δεζκεύνπλ νη κεηαβιεηέο ηνπ θώδηθα νλνκάδεηαη Πξνζσξηλόο Φώξνο Μλήκεο Δθαξκνγήο (ΠΦΜΔ) (Application Buffer). ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 14
Πεξηνξηζκέλε/Με-πεξηνξηζκέλε Απνζηνιή/Λήςε Πεξηνξηζκέλε απνζηνιή/ιήςε κελπκάησλ: Μηα ζπλάξηεζε πεξηνξηζκέλεο απνζηνιήο ζα «ηεξκαηίζεη» (return) κόλν όηαλ ν ΠΦΜΔ κπνξεί λα επαλαρξεζηκνπνηεζεί. Μπνξεί λα είλαη ζπγρξνληζκέλε: ππάξρεη επηθνηλσλία κε ηελ δηεξγαζία πνπ ιακβάλεη γηα αζθαιή παξαιαβή ησλ δεδνκέλσλ. Μπνξεί λα είλαη αζύγρξνλε: αλ ν ΠΦΜΣ «θξαηάεη» ηα δεδνκέλα κέρξη απηά λα παξαδνζνύλ. Μηα ζπλάξηεζε πεξηνξηζκέλεο ιήςεο ζα «ηεξκαηίζεη» κόλν όηαλ ηα δεδνκέλα ιεθζνύλ θαη κπνξνύλ λα ρξεζηκνπνηεζνύλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 15
Πεξηνξηζκέλε/Με-πεξηνξηζκέλε Απνζηνιή/Λήςε Με-πεξηνξηζκέλε (Διεύζεξε) απνζηνιή/ιήςε κελπκάησλ: Οη ζπλαξηήζεηο ειεύζεξεο απνζηνιήο/ιήςεο «ηεξκαηίδνπλ» ακέζσο ρσξίο λα πεξηκέλνπλ θακία επηθνηλσλία επηβεβαίσζεο. Οη ζπλαξηήζεηο ειεύζεξεο απνζηνιήο/ιήςεο απιά «απαηηνύλ» από ηελ βηβιηνζήθε MPI ηελ εθηέιεζε ηεο επηθνηλσλίαο. Ο ρξήζηεο δελ γλσξίδεη πόηε απηό ζα γίλεη. Γελ είλαη αζθαιέο λα αιιάδνπκε ηνλ ΠΦΜΔ (δειαδή ηηο κεηαβιεηέο-δεδνκέλα) πξηλ βεβαησζνύκε όηη ε εληνιή απνζηνιήο/ιήςεο δηεθπεξαηώζεθε. Υπάξρνπλ θαηάιιειεο ζπλαξηήζεηο αλακνλήο (wait routines) πνπ βνεζνύλ ζε απηό. Σπλήζσο ρξεζηκνπνηνύληαη γηα ηελ πηζαλή βειηίσζε ηεο απόδνζεο κε ηαπηόρξνλε επηθνηλσλία θαη εθηέιεζε ησλ δηεξγαζηώλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 16
Σπλαξηήζεηο Μηα-πξνο-κηα Δπηθνηλσλίαο Πεξηνξηζκέλε Απνζηνιή: MPI_Send (buffer, count, type, dest, tag, comm). Πεξηνξηζκέλε Λήςε: MPI_Recv (buffer, count, type, source, tag, comm, status). Διεύζεξε Απνζηνιή: MPI_Isend (buffer, count, type, dest, tag, comm, request). Διεύζεξε Λήςε: MPI_Irecv (buffer, count, type, source, tag, comm, request). Οξίζκαηα: buffer: Τα δεδνκέλα πνπ ζα ζηαινύλ/ιεθζνύλ, ηα νλόκαηα ησλ κεηαβιεηώλ. count: Ο αξηζκόο ησλ δεδνκέλσλ. type: Ο ηύπνο ησλ δεδνκέλσλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 17
Τύπνη Οξηζκάησλ ηεο Βηβιηνζήθεο MPI MPI C Data Types MPI_CHAR signed char MPI_SHORT signed short int MPI_INT signed int MPI_LONG signed long int MPI_UNSIGNED_CHAR unsigned char MPI_UNSIGNED_SHORT unsigned short int MPI_UNSIGNED unsigned int MPI_UNSIGNED_LONG unsigned long int MPI_FLOAT float MPI_DOUBLE double MPI_LONG_DOUBLE long double MPI_BYTE 8 binary digits MPI_PACKED MPI_Pack(), MPI_Unpack() ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 18
Τύπνη Οξηζκάησλ ηεο Βηβιηνζήθεο MPI MPI Fortran Data Types MPI_CHARACTER character MPI_INTEGER integer MPI_REAL real, single precision MPI_DOUBLE_PRECISION real, double precision MPI_COMPLEX complex MPI_DOUBLE_COMPLEX double complex MPI_LOGICAL logical MPI_BYTE 8 binary digits MPI_PACKED MPI_Pack(), MPI_Unpack() Ο ρξήζηεο κπνξεί επίζεο λα θηηάμεη ηνπο δηθνύο ηνπ ηύπνπο. Οη ηύπνη MPI_BYTE, MPI_PACKED δελ αλήθνπλ ζηνπο ζπλήζεηο ηύπνπο ηεο C, Fortran. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 19
Πεξηγξαθή Οξηζκάησλ (ζπλέρεηα) dest: Φξεζηκνπνηείηαη ζηηο ζπλαξηήζεηο απνζηνιήο θαη δειώλεη ηνλ αξηζκό ηεο δηεξγαζίαο (επεμεξγαζηή) ζηελ νπνία ζα ζηαιεί ην κήλπκα. source: Φξεζηκνπνηείηαη ζηηο ζπλαξηήζεηο ιήςεο θαη δειώλεη ηνλ αξηζκό ηεο δηεξγαζίαο από ηελ νπνία ζα ιεθζεί ην κήλπκα. tag: Απζαίξεηνο ζεηηθόο αθέξαηνο (από 0-32767) ηνλ νπνίν ζέηεη ν ρξήζηεο θαη είλαη ε εηηθέηα ηνπ κελύκαηνο. Οη αληίζηνηρεο ζπλαξηήζεηο απνζηνιήο θαη ιήςεο πξέπεη λα έρνπλ ηελ ίδηα εηηθέηα. comm: Ο δηαρεηξηζηήο επηθνηλσλίαο. Πξνθαζνξηζκέλνο είλαη ν MPI_COMM_WORLD. status: Γηα κηα εληνιή ιήςεο δειώλεη ηελ πεγή θαη ηελ εηηθέηα ηνπ κελύκαηνο. request: Όξηζκα ηεο ειεύζεξεο απνζηνιήο/ιήςεο. Δθόζνλ ε ειεύζεξε απνζηνιή/ιήςε κπνξεί λα νινθιεξσζεί πξνηνύ δεζκεπηεί ν απαηηνύκελνο πξνζσξηλόο ρώξνο κλήκεο, δεκηνπξγνύκε έλαλ «αξηζκό απαίηεζεο». Ο ρξήζηεο κπνξεί αξγόηεξα λα ηνλ ρξεζηκνπνηήζεη (κέζσ κηαο ζπλάξηεζεο WAIT) γηα λα ειέγμεη ηελ νινθιήξσζε ηεο απνζηνιήο/ιήςεο. Σηε C ην όξηζκα απηό είλαη έλαο δείθηεο (pointer) ζηε δνκή MPI_Request ελώ ζηε Fortran είλαη αθέξαηνο. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 20
Σπλαξηήζεηο Πεξηνξηζκέλεο Απνζηνιήο/Λήςεο Πεξηνξηζκέλε Απνζηνιή: MPI_Send (buffer, count, type, dest, tag, comm). Πξόηππν ηεο ζπλάξηεζεο ζηελ C: int MPI_Send( void * buf /* input */, int count /* input */, MPI_Datatype type /* input */, int dest /* input */, int tag /* input */, MPI_Comm comm /* input */, ) Πεξηνξηζκέλε Λήςε: MPI_Recv (buffer, count, type, source, tag, comm, status). Πξόηππν ηεο ζπλάξηεζεο ζηελ C: int MPI_Recv( void * buf /* input */, int count /* input */, MPI_Datatype type /* input */, int source /* input */, int tag /* input */, MPI_Comm comm /* input */, MPI_Status * status /* output */ ) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 21
Παξάδεηγκα Φξήζεο Σπλαξηήζεσλ Πεξηνξηζκέλεο Απνζηνιήο/Λήςεο #include "mpi.h" #include <stdio.h> int main(int argc, char** argv) { int numtasks, rank, dest, source, rc, count, tag=1; char inmsg[5], outmsg[]= hello ; MPI_Status Stat; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); ΜPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { dest = 1; source = 1; MPI_Send(&outmsg, 5, MPI_CHAR, dest, tag, MPI_COMM_WORLD); MPI_Recv(&inmsg, 5, MPI_CHAR, source, tag, MPI_COMM_WORLD, &stat); } else if (rank == 1) { dest = 0; source = 0; MPI_Recv(&inmsg, 5, MPI_CHAR, source, tag, MPI_COMM_WORLD, &Stat); MPI_Send(&outmsg, 5, MPI_CHAR, dest, tag, MPI_COMM_WORLD); } MPI_Get_count(&Stat, MPI_CHAR, &count); printf("task %d: Received %d char(s) from task %d with tag %d \n", rank, count, Stat.MPI_SOURCE, Stat.MPI_TAG); MPI_Finalize(); } ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 22
Σπλαξηήζεηο Διεύζεξεο Απνζηνιήο/Λήςεο Διεύζεξε Απνζηνιή: MPI_Isend (buffer, count, type, dest, tag, comm, request). Πξόηππν ηεο ζπλάξηεζεο ζηελ C: int MPI_Isend( void * buf /* input */, int count /* input */, MPI_Datatype type /* input */, int dest /* input */, int tag /* input */, MPI_Comm comm /* input */, MPI_Request* request /* output */, ) Διεύζεξε Λήςε: MPI_Irecv (buffer, count, type, source, tag, comm, request). Πξόηππν ηεο ζπλάξηεζεο ζηελ C: int MPI_Irecv( void * buf /* input */, int count /* input */, MPI_Datatype type /* input */, int source /* input */, int tag /* input */, MPI_Comm comm /* input */, MPI_Request* request /* output */, ) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 23
Παξάδεηγκα Φξήζεο Σπλαξηήζεσλ Διεύζεξεο Απνζηνιήο/Λήςεο program ringtopo include 'mpif.h' integer numtasks, rank, next, prev, buf(2), tag1, tag2, ierr integer stats(mpi_status_size,4), reqs(4) tag1 = 1; tag2 = 2 call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) prev = rank 1; next = rank + 1 if (rank == 0) prev = numtasks 1 if (rank == numtasks - 1) next = 0 call MPI_IRECV(buf(1), 1, MPI_INTEGER, prev, tag1, MPI_COMM_WORLD, reqs(1), ierr) call MPI_IRECV(buf(2), 1, MPI_INTEGER, next, tag2, MPI_COMM_WORLD, reqs(2), ierr) call MPI_ISEND(rank, 1, MPI_INTEGER, prev, tag2, MPI_COMM_WORLD, reqs(3), ierr) call MPI_ISEND(rank, 1, MPI_INTEGER, next, tag1, MPI_COMM_WORLD, reqs(4), ierr) call MPI_WAITALL(4, reqs, stats, ierr) call MPI_FINALIZE(ierr) stop end ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 24
Σπιινγηθή Δπηθνηλσλία Collective Communication Η ζπιινγηθή επηθνηλσλία πεξηιακβάλεη απνζηνιή / ιήςε κελπκάησλ κεηαμύ όισλ ησλ δηεξγαζηώλ ζε έλα δηαρεηξηζηή επηθνηλσλίαο. Γηάθνξνη ηύπνη ζπλαξηήζεσλ-ππνπξνγξακκάησλ ζπιινγηθήο επηθνηλσλίαο: Σπγρξνληζκέλε επηθνηλσλία (Synchronization): νη δηεξγαζίεο πεξηκέλνπλ έσο όιε ε επηθνηλσλία βξεζεί ζην ζεκείν ζπγρξνληζκνύ. Μεηαθνξά Γεδνκέλσλ (Data Movement): εθπνκπή (broadcast), δηαζπνξά/ζπγθέληξσζε (scatter/gather), όινη ζε όινπο (all to all). Σπιινγηθή ππνινγηζκνί πεξηζηνιή (reduction): κηα δηεξγαζία ζπιιέγεη δεδνκέλα από όιεο ηηο άιιεο θαη εθηειέη κηα πξάμε (π.ρ. πξόζζεζε, πνιιαπιαζηαζκόο, θιπ.) ζε απηά ηα δεδνκέλα. Οη ζπιινγηθή επηθνηλσλία είλαη πεξηνξηζκέλνπ (blocking) ηύπνπ. Υπάξρνπλ επίζεο ζπλαξηήζεηο παξαθνινύζεζεο θαη ειέγρνπ απνζηνιήο/ιήςεο κελπκάησλ. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 25
Υπνπξνγξάκκαηα Σπιινγηθήο Δπηθνηλσλίαο MPI MPI_Barrier: Γεκηνπξγεί έλα ζεκείν ζπγρξνληζκνύ. Κάζε δηεξγαζία πνπ θηάλεη ζην ζεκείν πνπ ην MPI_Barrier θαιείηαη, πεξηκέλεη σο όηνπ όιεο νη δηεξγαζηέο θηάζνπλ ζε απηό ην ζεκείν C: MPI_Barrier (comm); Fortran: MPI_BARRIER(comm, ierr) MPI_Bcast: Δθπέκπεη έλα κήλπκα από ηελ δηεξγαζία κε αξηζκό root ζε όιεο ηηο άιιεο δηεξγαζίεο κέζα ζηνλ Γ.Δ. C: MPI_Bcast (&buffer, count, type, root, comm); Fortran: MPI_BCAST(buffer, count, type, root, comm, ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 26
Υπνπξνγξάκκαηα Σπιινγηθήο Δπηθνηλσλίαο MPI MPI_Scatter: Γηαζθνξπίδεη έλα κήλπκα από ηελ δηεξγαζία κε αξηζκό root ζε όιεο ηηο άιιεο δηεξγαζίεο κέζα ζηνλ Γ.Δ. C: MPI_Scatter (&sendbuf, sendcnt, sendtype, &recvbuf, recv, recvtype, root, comm); Fortran: MPI_SCATTER(sendbuf, sendcnt, sendtype, recvbuf, recv, recvtype, root, comm, ierr) MPI_Gather: Μαδεύεη έλα κήλπκα από θάζε δηεξγαζία ζηε δηεξγαζηα root. C: MPI_Gather (&sendbuf, sendcnt, sendtype, &recvbuf, recv, recvtype, root, comm); Fortran: MPI_SCATTER(sendbuf, sendcnt, sendtype, recvbuf, recv, recvtype, root, comm, ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 27
Υπνπξνγξάκκαηα Σπιινγηθήο Δπηθνηλσλίαο MPI MPI_Reduce: Δθαξκόδεη κηα πξάμε πεξηζηνιήο ζε όια ηα κέιε ηνπ Γ.Δ. θαη ζηέιλεη ην απνηέιεζκα ζηε δηεξγαζία κε αξηζκό root. C: MPI_Reduce (&buffer, count, type, op, root, comm); Fortran: call MPI_REDUCE(buffer, count, type, op, root, comm, ierr) Οη ζεκαληηθόηεξεο πξνθαζνξηζκέλεο πξάμεηο ηύπνπ MPI_Reduce είλαη: MPI Reduction Operation C Data Types Fortran Data Types MPI_MAX maximum integer, float integer, real, complex MPI_MIN minimum integer, float integer, real, complex MPI_SUM sum integer, float integer, real, complex MPI_PROD product integer, float integer, real, complex MPI_LAND logical AND integer logical MPI_MAXLOC max value and location float, double, long double real, complex, double precision MPI_MINLOC min value and location float, double, long double real, complex, double precision ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 28
Παξάδεηγκα Φξήζεο Υπνπξνγξακκάησλ Σπιινγηθήο Δπηθνηλσλίαο #include "mpi.h" #include <stdio.h> #define SIZE 4 int main(int argc, char** argv) { int numtasks, rank, sendcount, recvcount, source; float sendbuf[size][size] = { {1.0, 2.0, 3.0, 4.0}, {5.0, 6.0, 7.0, 8.0}, {9.0, 10.0, 11.0, 12.0}, {13.0, 14.0, 15.0, 16.0} }; float recvbuf[size]; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); if (numtasks == SIZE) { source = 1; sendcount = SIZE; recvcount = SIZE; MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcount,MPI_FLOAT,source,MPI_COMM_WORLD); printf("rank= %d Results: %f %f %f %f\n",rank,recvbuf[0],recvbuf[1],recvbuf[2],recvbuf[3]); } else printf("must specify %d processors. Terminating.\n",SIZE); MPI_Finalize(); } ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 29
Derived Datatypes Τα βαζηθά νξίζκαηα ηεο βηβιηνζήθεο MPI πνπ είδακε παξαπάλσ (primitive MPI Datatypes) επηηξέπνπλ κεηαθνξά απιώλ δεδνκέλσλ ή ζύλνιν κεηαβιεηώλ ηνπ ίδηνπ ηύπνπ νη νπνίεο είλαη ζπλερείο (contiguous) ζηε κλήκε. Derived Datatypes είλαη πην πνιύπινθα νξίζκαηα πνπ κπνξνύλ λα εκπεξηέρνπλ κεηαβιεηέο δηαθνξεηηθνύ είδνπο ή κεηαβιεηέο πνπ δελ είλαη ζπλερείο ζηε κλήκε. Τα νξίζκαηα MPI Derived Datatypes είλαη έλα ζύλνιν κεηαβιεηώλ ε θαζεκία από ηηο νπνίεο έρεη σο ηύπν έλα νπνηνδήπνηε primitive MPI Datatype. Λόγνη ρξήζεο: Δίλαη ν κόλνο ηξόπνο λα ζηείινπκε κε κηα πξάμε επηθνηλσλίαο (κηα απνζηνιή/ιήςε) κηα δνκή (structure), κέξνο ελόο πίλαθα (π.ρ. Sub-block of a matrix), ή έλα ζύλνιν δεδνκέλσλ δηαθνξεηηθνύ ηύπνπ (π.ρ. int. and float numbers). Υπάξρνπλ δηαθνξεηηθνί ηξόπνη νξηζκνύ ελόο MPI derived datatype: -- Contiguous -- Vector -- Indexed -- Struct ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 30
Υπνπξνγξάκκαηα-Σπλαξηήζεηο MPI Derived Datatypes -- Βαζηθά ππνπξνγξάκκαηα δεκηνπξγίαο νξηζκάησλ MPI derived datatype: MPI_Type_contiguous: ν απινύζηεξνο ηξόπνο. Γεκηνπξγεί έλα θαηλνύξην όξηζκα αληηγξάθνληαο ηα ήδε ππάξρνληα νξίζκαηα. C: MPI_Type_contiguous (count, oldtype, &newtype) Fortran: call MPI_TYPE_CONTIGUOUS (count, oldtype, newtype, ierr) MPI_Type_vector: παξόκνην κε ην contiguous αιιά επηηξέπεη θελά (stride) ζηηο κεηαθηλήζεηο (displacements) ησλ νξηζκάησλ. C: MPI_Type_vector (count, blocklength, stride, oldtype, &newtype) Fortran: call MPI_TYPE_VECTOR (count, blocklength, stride, oldtype, newtype, ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 31
Υπνπξνγξάκκαηα-Σπλαξηήζεηο MPI Derived Datatypes MPI_Type_struct: ν πην επέιηθηνο ηξόπνο. Ο ρξήζηεο ειέγρεη πιήσζ ηε δνκή ηνπ λένπ νξίζκαηνο.. C: MPI_Type_struct (count, blocklens[], offsets[], old_types, &newtype) Fortran: call MPI_TYPE_STRUCT (count,blocklens[],offsets[],old_types, newtype, ierr) MPI_Type_Extend: Δπηζηξέθεη ηνλ κέγεζνο (ζε bytes) ηνπ derived datatype νξίζκαηνο. C: MPI_Comm_rank (datatype, &extent); Fortran: call MPI_COMM_RANK(datatype, extent, ierr) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 32
Derived Datatypes Καηαζθεπή ελόο νξίζκαηνο derived datatype: Α) Οξηζκόο ηνπ νξίζκαηνο ρξεζηκνπνηώληαο κηα από ηηο παξαπάλσ ππνξνπηίλεο (MPI_Type_contiguous, MPI_Type_vector, MPI_Type_struct, ). B) Παξάδνζε ηνπ λένπ νξίζκαηνο. Τν θαηλνύξην όξηζκα «παξαδίδεηαη» θαιώληαο ηελ: MPI_Type_commit(&newtype) Δπίζεο πνιύ ζπρλά είλαη ρξήζηκν λα ειεπζεξώλεηε ε κλήκε από ηα θαηλνύξηα νξίζκαηα όηαλ απηά δελ ρξεηάδνληαη. Απηό γίλεηαη θαιώληαο ηελ ξνπηίλα: MPI_Type_free(&newtype) ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 33
Τνπνινγία Γηεξγαζηώλ Τύπνπ MPI Ο παξάιιεινο πξνγξακκαηηζκόο ηύπνπ MPI επηηξέπεη ηελ απνηύπσζε/δηεπζέηεζε (mapping/ordering) ησλ δηεξγαζηώλ ζε έλα γεσκεηξηθό ζρήκα. Οη δύν θπξηόηεξεο ηνπνινγίεο είλαη: Η Καξηεζηαλή (Grid) θαη ε Γξαθηθή (Graph). Οη ηνπνινγίεο δηεξγαζηώλ MPI είλαη εηθνληθέο: δελ ππάξρεη ζρέζε κε ηελ ηνπνινγία ησλ επεμεξγαζηώλ. Λόγνη ρξήζεο: Δπθνιία: Μπνξεί λα είλαη ρξήζηκεο γηα πξνβιήκαηα κε ζπγθεθξηκέλα πξνθίι επηθνηλσλίαο, π.ρ. ε Καξηεζηαλή ηνπνινγία είλαη θαηάιιειε γηα πξνβιήκαηα όπνπ απαηηείηαη επηθνηλσλία κηαο δηεξγαζίαο κε ηεο 4 γεηηνληθέο ηεο ζε κνξθή grid Απνδνηηθόηεηα: κηα ζπγθεθξηκέλε ηνπνινγία κπνξεί λα βειηηζηνπνηήζεη ηηο δηεξγαζίεο κε βάζε ηελ αξρηηεθηνληθή ηνπ παξάιιεινπ ζπζηήκαηνο. Παξάδεηγκα (4x4 Καξηεζηαλή ηνπνινγία): ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 34
Παξάδεηγκα Γεκηνπξγίαο Καξηεζηαλήο Τνπνινγίαο program cartesian include 'mpif.h' integer SIZE, UP, DOWN, LEFT, RIGHT parameter(size=16, UP=1, DOWN=2, LEFT=3, RIGHT=4) integer numtasks, rank, source, dest, outbuf, i, tag, ierr, inbuf(4), nbrs(4), dims(2), coords(2), integer stats(mpi_status_size, 8), reqs(8), cartcomm, periods(2), reorder data inbuf /MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL, MPI_PROC_NULL/ data dims /4,4/, tag /1/, periods /0,0/, reorder /0/ call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) if (numtasks== SIZE) then call MPI_CART_CREATE(MPI_COMM_WORLD, 2, dims, periods, reorder, cartcomm, ierr) call MPI_COMM_RANK(cartcomm, rank, ierr) call MPI_CART_COORDS(cartcomm, rank, 2, coords, ierr) print *,'rank= ',rank,'coords= ',coords call MPI_CART_SHIFT(cartcomm, 0, 1, nbrs(up), nbrs(down), ierr) call MPI_CART_SHIFT(cartcomm, 1, 1, nbrs(left), nbrs(right), ierr) outbuf = rank do i=1,4 dest = nbrs(i) source = nbrs(i) call MPI_ISEND(outbuf, 1, MPI_INTEGER, dest, tag, MPI_COMM_WORLD, reqs(i), ierr) call MPI_IRECV(inbuf(i), 1, MPI_INTEGER, source, tag, MPI_COMM_WORLD, reqs(i+4), ierr) end do call MPI_WAITALL(8, reqs, stats, ierr) print *,'rank= ',rank,' coords= ',coords, ' neighbors(u,d,l,r)= ',nbrs print *,'rank= ',rank,' ', ' inbuf(u,d,l,r)= ',inbuf else print *, 'Must specify',size,' processors. Terminating.' end if call MPI_FINALIZE(ierr) end ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 35
Βηβιηνγξαθία 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. Designing and Building Parallel Programs, Ian Foster, Addison-Wesley 1994. Parallel Computing: Theory and Practice, M. J. Quinn, McGraw-Hill, 1994. MPI: http://www.mpi-forum.org/ http://www.epcc.ed.ac.uk/library/documentation/training/: On-line courses include MPI, HPF, Mesh Generation, Introduction to Computational Science, HPC in Business. ΔΜ 361: Παξάιιεινη Υπνινγηζκνί 2010/11, Κεθάιαην 5 36