/************************************************************************************/
/* */
/* 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
END
Auf 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 */
}