/************************************************************************************/ /* */ /* Summe im Ring als Pseudocode */ /* */ /************************************************************************************/ FOR p=0 TO n-1 DO IN PARALLEL id = p; /* besorge die eigene Prozessorkennung */ anz = n; /* besorge die Anzahl der Prozessoren */ odd = id % 2; /* lege fest, ob ungerade ID vorliegt */ /* Topologie festlegen: */ pre = LINK TO (id-1) % anz; /* Vorgaenger */ suc = LINK TO (id+1) % anz; /* Nachfolger */ /* parallele Summe berechnen: */ sum = id; /* vorlaeufige Summe */ out = id; /* naechster zu uebertragender Wert */ FOR z = 1 TO anz-1 DO /* anz-1 mal tue: */ IF (odd) /* falls ungerade ID */ RECV(pre, in ); /* erhalte vom Vorgaenger einen Wert fuer in */ SEND(suc, out); /* schicke zum Nachfolger den Wert von out */ ELSE /* falls gerade ID */ SEND(suc, out); /* schicke zum Nachfolger den Wert von out */ RECV(pre, in ); /* erhalte vom Vorgaenger den Wert fuer in */ sum += in; /* Summe erhoehen */ out = in; /* naechste Ausgabe vorbereiten */ END ENDAuf den nächsten Seiten wird dieser Pseudocode in der Syntax von PARIX, MPI und PVM formuliert.
/*********************************************************************************************/
/* */
/* Summe im Ring als Parix-Programm mit synchroner Kommunikation */
/* */
/*********************************************************************************************/
#include <sys/root.h>
#include <stdlib.h>
void main (int argc, char **argv)
{
int anz, id, odd, sum, in, out, z;
LinkCB_t *pre, *suc; /* Zeiger auf Link-Kontrollblocks */
int error; /* Variable fuer Fehlermeldung */
/* logische Topologie festlegen : */
anz = GET_ROOT()->ProcRoot->nProcs; /* Macro liefert Anzahl der Proz. */
id = GET_ROOT()->ProcRoot->MyProcID; /* Macro liefert Prozessor-ID */
odd = id % 2; /* lege fest, ob ungerade ID vorliegt */
/* die Kommunikationspartner muessen */
/* sich gleichzeitig mit derselben ID */
/* auf ein Link verstaendigen: */
if (odd) {
suc = ConnectLink((id+1+anz) % anz, 42, &error); /* definiere Link zum Nachfolger */
pre = ConnectLink((id-1+anz) % anz, 42, &error); /* definiere Link zum Vorgaenger */
} else {
pre = ConnectLink((id-1+anz) % anz, 42, &error); /* definiere Link zum Vorgaenger */
suc = ConnectLink((id+1+anz) % anz, 42, &error); /* definiere Link zum Nachfolger */
}
/* Parallele Summe berechnen: */
sum = out = id; /* initialisiere Variablen */
for (z = 1; z < anz; z++) { /* anz-1 mal tue: */
if (odd) {
RecvLink(pre, &in, sizeof(int)); /* ueber Link pre empfangen nach in */
SendLink(suc, &out, sizeof(int)); /* ueber Link suc versenden von out */
} else {
SendLink(suc, &out, sizeof(int)); /* ueber Link suc versenden von out */
RecvLink(pre, &in, sizeof(int)); /* ueber Link pre empfangen nach in */
}
sum += in; /* Summe erhoehen */
out = in; /* naechste Ausgabe vorbereiten */
}
exit(0); /* Programm beenden */
}
Nach Übersetzen der Quelle lautet der Aufruf von der Shell-Ebene für ein 4 × 4 -Gitter:
$ run -c 0 4 4 summe_im_ring.px
/****************************************************************************************/ /* */ /* Summe im Ring als Parix-Programm unter Verwendung einer virtuellen Topologie */ /* */ /****************************************************************************************/ #include <sys/root.h> #include <stdlib.h> #include <virt_top.h> void main (int argc, char **argv) { int anz, id, odd, sum, in, out, z; int ring, pre, suc; RingData_t *ring_data; /* Zeiger auf Topologiestruktur */ /* logische Topologie festlegen: */ anz = GET_ROOT()->ProcRoot->nProcs; /* Macro liefert Anzahl der Prozessoren */ ring = MakeRing(1, anz, MINSLICE, MAXSLICE, /* bilde Ring in ein 3D-Gitter ab */ MINSLICE, MAXSLICE, /* dabei soll jeweils pro Dimension */ MINSLICE, MAXSLICE); /* das gesamte Intervall genutzt werden */ ring_data = GetRing_Data(ring); /* besorge Topologieinformation */ id = ring_data->id; /* logische ID bzgl. des Rings */ odd = id % 2; /* lege fest ob ungerade */ suc = 1; /* Name fuer Nachfolgerlink bzgl. Ring */ pre = 0; /* Name fuer Vorgaengerlink bzgl. Ring */ /* Parallele Summe berechnen: */ sum = out = id; /* initialisiere Variablen */ for (z = 1; z < anz; z++) { /* anz-1 mal */ if (odd) { Recv(ring, pre, &in, sizeof(int)); /* ueber Link pre im Ring empfangen */ Send(ring, suc, &out, sizeof(int)); /* ueber Link suc im Ring verschicken */ } else { Send(ring, suc, &out, sizeof(int)); /* ueber Link suc im Ring verschicken */ Recv(ring, pre, &in, sizeof(int)); /* ueber Link pre im Ring empfangen */ } sum += in; /* Summe erhoehen */ out = in; /* naechste Ausgabe vorbereiten */ } FreeTop(ring); /* Programm beenden */ exit(0); }
/**************************************************************************************/ /* */ /* Summe im Ring als Parix-Programm unter Verwendung asynchroner Kommunikation */ /* */ /**************************************************************************************/ #include <sys/root.h> #include <stdlib.h> #include <virt_top.h> void main (int argc, char **argv) { int anz, id, odd, sum, in, out, z; int ring, pre, suc; RingData_t *ring_data; int result; anz = GET_ROOT()->ProcRoot->nProcs; ring = MakeRing(1, anz, MINSLICE, MAXSLICE, MINSLICE, MAXSLICE, MINSLICE, MAXSLICE); ring_data = GetRing_Data(ring); id = ring_data->id; odd = id % 2; suc = 1; pre = 0; AInit(ring, -1, -1); /* Vorbereitung fuer Threads */ /* welche die Kommunikation */ /* durchfuehren sollen */ sum = out = id; for (z = 1; z < anz; z++) { ASend(ring, suc, &out, sizeof(int), &result); /* asynchrones Verschicken */ ARecv(ring, pre, &in, sizeof(int), &result); /* asynchrones Empfangen */ ASync(ring, -1); /* Warten auf Abschluss der */ /* Kommunikation */ sum += in; out = in; } AExit(ring); exit(0); }
/**********************************************************************************/ /* */ /* Summe im Ring als MPI-Programm */ /* */ /**********************************************************************************/ #include "mpi.h" int main(int argc, char **argv) { int id, anz, odd, pre, suc, sum, in, out, z; MPI_Status status; MPI_Init ( &argc, &argv ); /* Initialisiere MPI */ /* logische Topologie festlegen: */ MPI_Comm_size ( MPI_COMM_WORLD, &anz ); /* besorge Anzahl der Prozessoren */ MPI_Comm_rank ( MPI_COMM_WORLD, &id ); /* besorge Prozessor-ID */ odd = anz % 2; /* lege fest, ob ungerade */ pre = ( id - 1 + anz ) % anz; /* ID des Vorgaengers */ suc = ( id + 1 ) % anz; /* ID des Nachfolgers */ /* Parallele Summe berechnen: */ sum = out = id; /* initialisiere Variablen */ for (z=1; z < anz; z++) { /* anz-1 mal */ if (odd) { MPI_Recv (&in, /* lege ab bei Adresse von in */ 1, /* ein Datum */ MPI_INT, /* nach Bauart MPI_INT */ pre, /* erhalten vom Vorgaenger */ 42, /* versehen mit dem Tag 42 */ MPI_COMM_WORLD, /* bzgl. des allgemeinen Kommunikators */ &status ); /* Adresse fuer Fehlerstatus */ MPI_Send (&out, /* entnehme beginnend bei Adresse out */ 1, /* ein Datum */ MPI_INT, /* nach Bauart MPI_INT */ suc, /* verschicke an Nachfolger */ 42, /* versehen mit Tag 42 */ MPI_COMM_WORLD ); /* bzgl. des allgemeinen Kommunikators */ } else { MPI_Send ( &out, 1, MPI_INT, suc, 42, MPI_COMM_WORLD ); MPI_Recv ( &in, 1, MPI_INT, pre, 42, MPI_COMM_WORLD, &status ); } sum += in; out = in; } MPI_Finalize (); /* Programm beenden */ }Nach Übersetzen der Quelle lautet der Aufruf von der Shell-Ebene für 16 Prozessoren:
/************************************************************************************/ /* */ /* Summe im Ring als MPI-Programm unter Verwendung von reduce */ /* */ /************************************************************************************/ #include "mpi.h" int main(int argc, char **argv) { int id, sum; MPI_Init ( &argc, &argv ); /* initialisiere MPI */ /* logische Topologie festlegen: */ MPI_Comm_rank ( MPI_COMM_WORLD, &id ); /* bestimme Prozessor-ID */ /* Parallele Summe berechnen: */ MPI_Allreduce ( &id, /* Eingabeparameter: id */ &sum, /* Ausgabeparameter: sum */ 1, /* 1 Datum */ MPI_INT, /* von der Bauart MPI_INT */ MPI_SUM, /* zu bestimmen ist die Summe */ MPI_COMM_WORLD ); /* innerhalb des globalen Kommunikators */ MPI_Finalize (); /* Programm beenden */ }
/****************************************************************************************/ /* */ /* Summe im Ring als PVM-Programm: Master */ /* */ /****************************************************************************************/ #include "pvm3.h" void main ( int argc, char **argv ) { int anz, z; int *tids; anz = atoi ( argv[1] ); /* besorge Anzahl der Prozessoren */ tids = (int*) malloc (anz*sizeof(int)); /* besorge Speicherplatz fuer Task-Id-Vektor */ pvm_spawn ( "slave", /* Starte das Programm slave */ (char **) NULL, /* ohne Argumente */ PvmTaskArch, /* eingeschraenkt auf eine Architektur */ "SUN4", /* vom Typ SUN4 */ anz, /* anz mal */ tids ); /* erhalte einen Vektor von Task-IDs zurueck */ /* globale Task-Informationen verteilen */ for ( z = 0; z < anz; z++ ) { /* anz mal */ pvm_initsend ( PvmDataRaw ); /* Sende-Puffer vorbereiten */ pvm_pkint ( &z, 1, 1 ); /* den Wert von z verpacken */ pvm_pkint ( &anz, 1, 1 ); /* den Wert von anz verpacken */ pvm_pkint ( tids, anz, 1 ); /* den Task-ID-Vektor verpacken */ pvm_send ( tids[z], 0 ); /* an den z-ten Prozessor verschicken */ } pvm_exit ( ); /* Task beenden */ }
$ gcc -o summe_im_ring master.c -lpvm3 $ gcc -o slave slave.c -lpvm3
$ summe_im_ring 16
/**************************************************************************************/ /* */ /* Summe im Ring als PVM-Programm: Slave */ /* */ /**************************************************************************************/ #include "pvm3.h" void main ( int argc, char **argv ) { int id, anz, odd, in, sum, out, pre, suc, z; int *tids; /* Logische Topologie festlegen: */ pvm_recv ( pvm_parent ( ), -1 ); /* erhalte vom aufspannenden Vater */ pvm_upkint ( &id, 1, 1 ); /* entpacke id */ pvm_upkint ( &anz, 1, 1 ); /* entpacke anz */ tids = (int*) malloc (anz*sizeof(int)); /* besorge Platz fuer Task-ID-Vektor */ pvm_upkint ( tids, anz, 1 ); odd = id % 2; /* lege fest, ob ungerade id vorliegt */ pre = tids[(id+anz-1)%anz]; /* Task-ID des Vorgaengers */ suc = tids[(id+1)%anz]; /* Task-ID des Nachfolgers */ /* Parallele Summe berechnen: */ sum = out = id; for ( z = 1; z < anz; z++ ) { /* anz-1 mal */ if ( odd ) { pvm_recv ( pre, -1 ); /* erhalte vom Vorgaenger */ pvm_upkint ( &in, 1, 1 ); /* entpacke nach in */ pvm_initsend ( PvmDataRaw ); /* initialisiere Ausgabepuffer */ pvm_psend ( suc, /* versende zum Nachfolger */ 0, /* mit dem Tag 0 */ &out, /* beginnend bei Adresse von out */ 1, /* ein Datum */ PVM_INT); /* nach Bauart PVM_INT */ } else { pvm_initsend ( PvmDataRaw ); pvm_psend ( suc, 0, &out, 1, PVM_INT ); pvm_recv ( pre, -1 ); pvm_upkint ( &in, 1, 1 ); } sum += in; /* Summe erhoehen */ out = in; /* naechsten Ausgabewert vorbereiten */ } pvm_exit ( ); /* Programm beenden */ }