/*************************************************************************************************************************************/ /* */ /* C A L C U L D E L ' E N S E M B L E D E M A N D E L B R O T */ /* D A N S U N E M E M O I R E V I R T U E L L E D I S T R I B U E E : */ /* */ /* */ /* Author of '$xtc/nCube.22$c' : */ /* */ /* John F. Colonna (LACTAMME, AAAAMMJJhhmmss). */ /* */ /*************************************************************************************************************************************/ #include "nCube.21.I"
/*************************************************************************************************************************************/
/* */
/* C A L C U L D E L ' E N S E M B L E D E M A N D E L B R O T */
/* D A N S U N E M E M O I R E V I R T U E L L E D I S T R I B U E E : */
/* */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * ** * * * * * ** * */
/* * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * */
/* * * * * ** * * * * * ** */
/* * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* */
/* ATTENTION : */
/* */
/* Ce fichier ('$xtc/nCube.22$I') est */
/* reference dans '$xiMd/nCube.22$c.$m4' a */
/* a des fins de demonstration 'WWW'. */
/* */
/* Author of '$xtc/nCube.22$I' : */
/* */
/* John F. Colonna (LACTAMME, AAAAMMJJhhmmss). */
/* */
/*************************************************************************************************************************************/
/*************************************************************************************************************************************/
/* */
/* F O R M A T D E L ' I M A G E A G E N E R E R : */
/* */
/*************************************************************************************************************************************/
static int dimX=UNDEF;
#define Xmin \
RIEN
#define Xmax \
(Xmin + (dimX-UNITE))
/* Definition des abscisses. */
static int dimY=UNDEF;
#define Ymin \
RIEN
#define Ymax \
(Ymin + (dimY-UNITE))
/* Definition des ordonnees. */
/*************************************************************************************************************************************/
/* */
/* D E F I N I T I O N D E S D O N N E E S E N M E M O I R E V I R T U E L L E : */
/* */
/*************************************************************************************************************************************/
#define FORMAT_PLAN_COMPLEXE \
iLONGUEUR_caractere
#define LONGUEUR_PLAN_COMPLEXE \
(dimX*dimY)
#define PLAN_COMPLEXE \
IMPLANTATION_EN_MEMOIRE_VIRTUELLE((DEBUT_DE_LA_MEMOIRE_VIRTUELLE + LONGUEUR_DEBUT_DE_LA_MEMOIRE_VIRTUELLE) \
,FORMAT_DEBUT_DE_LA_MEMOIRE_VIRTUELLE \
,FORMAT_PLAN_COMPLEXE \
)
#define ACCES_PLAN_COMPLEXE(x,y) \
ADRESSAGE_EN_MEMOIRE_VIRTUELLE(PLAN_COMPLEXE,(((y)*dimX) + (x)))
/* Emplacement du plan complexe dans la memoire virtuelle. */
#define FORMAT_LIGNE_A_TRAITER \
iLONGUEUR_entier
#define LONGUEUR_LIGNE_A_TRAITER \
(dimY)
#define LIGNE_A_TRAITER \
IMPLANTATION_EN_MEMOIRE_VIRTUELLE((PLAN_COMPLEXE + LONGUEUR_PLAN_COMPLEXE) \
,FORMAT_PLAN_COMPLEXE \
,FORMAT_LIGNE_A_TRAITER \
)
#define ACCES_LIGNE_A_TRAITER(y) \
ADRESSAGE_EN_MEMOIRE_VIRTUELLE(LIGNE_A_TRAITER,(y))
/* Emplacement des indicateurs des lignes du plan complexe non encore traitees. */
#define FORMAT_LIGNE_ENTIEREMENT_TRAITEE \
iLONGUEUR_entier
#define LONGUEUR_LIGNE_ENTIEREMENT_TRAITEE \
(dimY)
#define LIGNE_ENTIEREMENT_TRAITEE \
IMPLANTATION_EN_MEMOIRE_VIRTUELLE((LIGNE_A_TRAITER + LONGUEUR_LIGNE_A_TRAITER) \
,FORMAT_LIGNE_A_TRAITER \
,FORMAT_LIGNE_ENTIEREMENT_TRAITEE \
)
#define ACCES_LIGNE_ENTIEREMENT_TRAITEE(y) \
ADRESSAGE_EN_MEMOIRE_VIRTUELLE(LIGNE_ENTIEREMENT_TRAITEE,(y))
/* Emplacement des indicateurs des lignes du plan complexe entierement traitees. */
#define FORMAT_VERROU \
iLONGUEUR_entier
#define LONGUEUR_VERROU \
(UNITE)
#define VERROU \
IMPLANTATION_EN_MEMOIRE_VIRTUELLE((LIGNE_ENTIEREMENT_TRAITEE + LONGUEUR_LIGNE_ENTIEREMENT_TRAITEE) \
,FORMAT_LIGNE_ENTIEREMENT_TRAITEE \
,FORMAT_VERROU \
)
#define ACCES_VERROU \
ADRESSAGE_EN_MEMOIRE_VIRTUELLE(VERROU,CLEAR)
/* Emplacement du verrou d'exclusion des phases critiques. */
/*************************************************************************************************************************************/
/* */
/* D E F I N I T I O N D E S I T E R A T I O N S : */
/* */
/*************************************************************************************************************************************/
#define NOMBRE_MAXIMAL_D_ITERATIONS \
(250) \
/* Definition du nombre maximal d'iterations. */
#define SEUIL \
(4.0)
/* Definition du seuil de fuite a l'infini du module de 'Zn'... */
#define NOIR \
(0)
#define BLANC \
(255)
/* Definition des niveaux extrema. */
#define LIGNE(x) \
(*(ligne + (x))) \
/* Acces a un point de la ligne courante... */
#define IMAGE_EXTERNE(x,y) \
(*(image_externe + (((y)*dimX) + (x)))) \
/* Acces a un point de l'image au format externe. */
#define Cn(n) \
((CHAR)(NOIR + (((FLOTTANT)(n-1)/(FLOTTANT)NOMBRE_MAXIMAL_D_ITERATIONS)*((FLOTTANT)(BLANC-NOIR))))) \
/* Definition de niveaux dans l'image... */
#define store_image(n,x,y) \
{ \
CHAR valeur=n; \
StoreC(ACCES_PLAN_COMPLEXE(x,y),valeur); \
} \
/* Rangement d'un point valide d'une image. */
#define XG \
(-2.00)
#define XD \
(0.50)
/* Extremites Gauche et Droite sur l'axe des 'X'. */
#define YB \
(-1.25)
#define YH \
(1.25)
/* Extremites Bas et Haut sur l'axe des 'Y'. */
/*************************************************************************************************************************************/
/* */
/* D E F I N I T I O N D E S N O M B R E S C O M P L E X E S : */
/* */
/*************************************************************************************************************************************/
typedef struct complexe {
FLOTTANT reelle;
FLOTTANT imaginaire;
} complexe;
/* 'struct' de definition d'un nombre complexe... */
#define Reelle(z) \
(z.reelle)
#define Imaginaire(z) \
(z.imaginaire)
#define Cinit(z,x1,y1) \
{ \
Reelle(z) = x1; \
Imaginaire(z) = y1; \
}
#define Cegal(z,z1) \
{ \
Reelle(z) = Reelle(z1); \
Imaginaire(z) = Imaginaire(z1); \
}
#define Csomme(z,z1,z2) \
{ \
Reelle(z) = Reelle(z1) + Reelle(z2); \
Imaginaire(z) = Imaginaire(z1) + Imaginaire(z2); \
}
#define Cproduit(z,z1,z2) \
{ \
Reelle(z) = (Reelle(z1)*Reelle(z2)) - (Imaginaire(z1)*Imaginaire(z2)); \
Imaginaire(z) = (Reelle(z2)*Imaginaire(z1)) + (Reelle(z1)*Imaginaire(z2)); \
}
#define Cmodule2(z) \
((Reelle(z)*Reelle(z)) + (Imaginaire(z)*Imaginaire(z)))
#define PETIT \
(1.0e-16)
#define GRAND \
(1.0e32)
#define deborde(x) \
{ \
if (((x) < -PETIT) || ((x) > PETIT)) \
{ \
} \
else \
{ \
x = (FLOTTANT)CLEAR; \
} \
\
if ((x) < -GRAND) \
{ \
x = -GRAND; \
} \
else \
{ \
} \
\
if ((x) > GRAND) \
{ \
x = GRAND; \
} \
else \
{ \
} \
}
#define Cdeborde(z) \
{ \
deborde(Reelle(z)); \
deborde(Imaginaire(z)); \
}
/*************************************************************************************************************************************/
/* */
/* C O D E D E T E S T D E S C L I E N T S A V E C L E */
/* C A L C U L D E L ' E N S E M B L E D E M A N D E L B R O T : */
/* */
/* */
/* Benchmark approximatif du 01/10/1993 : */
/* */
/* Celui-ci, pour des raisons de */
/* commodite, est obtenu en faisant */
/* la "difference" de deux commandes */
/* 'date'. Le test a ete conduit avec : */
/* */
/* */
/* LDb */
/* */
/* #define NOMBRE_MAXIMAL_D_ITERATIONS \ */
/* 2500 */
/* */
/* */
/* afin de faire plus de calculs que */
/* d'acces a la memoire virtuelle... */
/* */
/* */
/* ------------------------------------------------------------------------------- */
/* | | | avec | sans | */
/* | | | phase critique | phase critique | */
/* | | | | | */
/* | dimension | nombre | duree | duree | */
/* | de l'hypercube | de clients | (en secondes) | (en secondes) | */
/* | | | | | */
/* |-------------------|-------------------|-------------------|-------------------| */
/* | | | | | */
/* | 01 | 01 | 108 | 109 | */
/* | | | | | */
/* | 02 | 02 | 057 | 057 | */
/* | | | | | */
/* | 03 | 04 | 031 | 053 | */
/* | | | | | */
/* | 04 | 08 | 019 | 036 | */
/* | | | | | */
/* | 05 | 16 | 016 | 023 | */
/* | | | | | */
/* | 06 | 32 | 045 (!) | 015 | */
/* | | | | | */
/* ------------------------------------------------------------------------------- */
/* */
/* */
/* On notera qu'au debut il y a une relation */
/* presque lineaire entre la duree et l'inverse */
/* du nombre de clients, puis qu'il y a un fort */
/* ralentissement, puis enfin, une dramatique */
/* inversion... */
/* */
/* Enfin, la duree d'execution du programme */
/* 'v $xtd/mandel.11$c', dans les memes conditions */
/* a ete de 100 secondes. La version monoprocesseur */
/* de 'v $xtd/nCube.22$c' n'est donc penalisee que de */
/* de 8 secondes, ce qui est peu... */
/* */
/*************************************************************************************************************************************/
static int phase_critique=NOK;
/* Indique si l'acces aux lignes par les processeurs se fait via une phase critique (=OK), */
/* ou en fonction simplement du numero de processeur (#OK). */
client()
{
CHAR *ligne;
/* Definition de la ligne courante a generer... */
int x,y;
/* Definition des coordonnees. */
if (processeur_local == CLIENT_NATUREL(PREMIER_PROCESSEUR))
{
if (CLEAR)
/* Malheureusement, la fonction 'system(...)' n'est pas implementee... */
{
fprintf(stderr,"\n heure de debut sur le client maitre : ");
system("date '+%H:%M:%S'");
fprintf(stderr,"\n");
}
else
{
}
clock();
/* Chronometrage... */
}
else
{
}
Get(dimX,"dimX");
Get(dimY,"dimY");
/* Recuperation des dimensions en 'X' et en 'Y' de l'image a generer. */
unite_d_entrelacage = dimY;
/* L'unite d'entrelacage correspondra a une ligne... */
Malloc(ligne,dimY*iLONGUEUR_caractere);
/* Allocation de la ligne courante a generer... */
for (y=Ymin ; y<=Ymax ; y++)
{
int on_n_a_pas_trouve_de_ligne=OK;
int indicateur=CLEAR;
/* L'initialisation de 'indicateur' est faite sur 'CLEAR' et non point sur 'UNDEF' a cause */
/* du cas ou l'on ne passe pas ci-apres par une phase critique (voir 'phase_critique'). */
if (phase_critique == OK)
{
WaitVerrou(VERROU,phase_critique);
/* Tentative d'entree dans une phase critique de recherche d'une ligne 'y' non encore */
/* traitee par un autre processeur... */
LoadI(ACCES_LIGNE_A_TRAITER(y),indicateur);
if (indicateur == CLEAR)
{
on_n_a_pas_trouve_de_ligne++;
/* Cas ou l'on a trouve une ligne a traiter... */
indicateur++;
StoreI(ACCES_LIGNE_A_TRAITER(y),indicateur);
/* On indique que cette ligne va etre traitee... */
}
else
{
}
ClearVerrou(VERROU,phase_critique);
/* Sortie de la phase critique... */
}
else
{
int Ymin_local;
int Ymax_local;
int lignes_locales=(dimY/nombre_total_de_serveurs);
Ymin_local = Ymin + (lignes_locales*NUMERO_DE_PROCESSEUR__NUMERO_DE_SERVEUR(processeur_local));
Ymax_local = Ymin_local + lignes_locales - UNITE;
if ((y >= Ymin_local) && (y <= Ymax_local))
{
on_n_a_pas_trouve_de_ligne++;
indicateur++;
/* Cas ou l'on a trouve une ligne a traiter... */
}
else
{
}
}
if (on_n_a_pas_trouve_de_ligne != OK)
{
/* Lorsque l'on a trouve une ligne non encore traitee, on la prend et on la traite : */
FLOTTANT xg=((XD+XG)/2) - ((((XD-XG)*dimX)/dimY)/2);
FLOTTANT yb=YB;
FLOTTANT xd=((XD+XG)/2) + ((((XD-XG)*dimX)/dimY)/2);
FLOTTANT yh=YH;
/* Definition de la fenetre de calcul en fonction des proportions de l'image... */
complexe C;
complexe Zn;
complexe zt;
/* Definition de nombres complexes necessaires. */
for (x=Xmin ; x<=Xmax ; x++)
{
int index=UNITE;
int iterer=OK;
/* Variables d'iterations... */
Cinit(C
,((FLOTTANT)x / (FLOTTANT)dimX)*(xd-xg) + xg
,((FLOTTANT)y / (FLOTTANT)dimY)*(yh-yb) + yb
);
/* Initialisation du point complexe courant 'C' sur le point {x,y}. */
Cinit(Zn,0.0,0.0);
/* Initialisation de la suite Zn. */
while (iterer == OK)
{
Cproduit(zt,Zn,Zn);
Csomme(Zn,zt,C);
Cdeborde(Zn);
/* Iteration de la suite Zn. */
if ((index >= NOMBRE_MAXIMAL_D_ITERATIONS) || (Cmodule2(Zn) > SEUIL))
{
LIGNE(x) = Cn(index);
/* Memorisation locale du point courant (x) de la ligne courante (y)... */
iterer++;
/* Et l'iteration courante est terminee... */
}
else
{
index++;
}
}
}
if (unite_d_entrelacage == dimY)
{
MStoreC(ACCES_PLAN_COMPLEXE(Xmin,y),dimY*iLONGUEUR_caractere,LIGNE(Xmin));
}
else
{
for (x=Xmin ; x<=Xmax ; x++)
{
store_image(LIGNE(x),x,y);
}
}
StoreI(ACCES_LIGNE_ENTIEREMENT_TRAITEE(y),indicateur);
/* On indique que cette ligne a ete entierement traitee... */
}
else
{
/* Lorsque l'on a trouve une ligne deja traitee, on va voir la suivante... */
}
}
if (processeur_local == CLIENT_NATUREL(PREMIER_PROCESSEUR))
{
clock_t duree=clock();
CHAR *image_externe;
Malloc(image_externe,(dimY*dimX)*iLONGUEUR_caractere);
/* Definition de l'image a generer... */
if (CLEAR)
/* Malheureusement, la fonction 'system(...)' n'est pas implementee... */
{
fprintf(stderr,"\n heure de fin sur le client maitre : ");
system("date '+%H:%M:%S'");
fprintf(stderr,"\n");
}
else
{
}
fprintf(stderr,"\n duree du calcul sur le client maitre : %d milli-secondes",duree/(CLOCKS_PER_SEC/1000));
fprintf(stderr,"\n");
fprintf(stderr,"\n identite du client 'maitre' = %d",processeur_local);
fprintf(stderr,"\n nombre de serveurs = %d",nombre_total_de_serveurs);
fprintf(stderr,"\n nombre de clients = %d",nombre_total_de_clients);
fprintf(stderr,"\n dimension de l'image = %dx%d",dimX,dimY);
fprintf(stderr,"\n nombre d'iterations = %d",NOMBRE_MAXIMAL_D_ITERATIONS);
if (phase_critique == OK)
{
fprintf(stderr,"\n mode allocation dynamique des lignes (d'ou exclusion de phase critique)");
}
else
{
fprintf(stderr,"\n mode allocation statique des lignes (d'ou un temps de regroupement variable)");
}
if (unite_d_entrelacage == dimY)
{
fprintf(stderr,"\n mode emission bloquee des points de chaque ligne");
}
else
{
fprintf(stderr,"\n mode emission individuelle des points");
}
fprintf(stderr,"\n");
for (y=Ymin ; y<=Ymax ; y++)
{
int indicateur=CLEAR;
while (indicateur == CLEAR)
{
LoadI(ACCES_LIGNE_ENTIEREMENT_TRAITEE(y),indicateur);
/* On regarde si la ligne courante a ete traitee entierement ; si elle ne l'a pas ete, on */
/* attend qu'elle le soit. On notera qu'il ne s'agit pas ici d'une phase critique puisque */
/* l'on ne fait que lire 'ACCES_LIGNE_ENTIEREMENT_TRAITEE(y)'... */
}
if (unite_d_entrelacage == dimY)
{
MLoadC(ACCES_PLAN_COMPLEXE(Xmin,y),dimY*iLONGUEUR_caractere,IMAGE_EXTERNE(Xmin,y));
}
else
{
for (x=Xmin ; x<=Xmax ; x++)
{
LoadC(ACCES_PLAN_COMPLEXE(x,y),IMAGE_EXTERNE(x,y));
}
}
}
fprintf(stderr
,"\n duree du regroupement sur le client maitre : %d milli-secondes"
,(clock()-duree)/(CLOCKS_PER_SEC/1000)
);
/* ATTENTION : cette duree de regroupement des lignes de l'image est bien entendu */
/* independante du nombre de processeurs utilises. Malgre cela, l'impression ci-dessus */
/* donne une indication contradictoire lorsqu'il n'y a pas allocation dynamique des lignes */
/* (phase_critique == NOK). En effet, il apparait que vue la structure de l'ensemble de */
/* Mandelbrot, les processeurs travaillant sur les bandes centrales de l'image ont beaucoup */
/* plus de travail que ceux qui travaillent a la peripherie. Or le processeur maitre qui */
/* fait le regroupement travaille precisemment a la peripherie. Cela signifie que lorsqu'il */
/* a termine ses calculs, il doit attendre les autres ; c'est cette attente qui rend dans ce */
/* cas de non allocation dynamique des lignes, le temps de regroupement croissant lorsque le */
/* nombre de processeurs decroit... */
fprintf(stderr,"\n");
write(STANDARD_OUT,image_externe,dimX*dimY);
/* Sortie de l'image... */
free(image_externe);
}
else
{
}
return(OK);
}