/*************************************************************************************************************************************/ /* */ /* G E S T I O N " E X T E R N E " D U P A R A L L E L I S M E : */ /* */ /* */ /* Utilisation : */ /* */ /* Cette commande s'utilisera par exemple */ /* de la facon suivante : */ /* */ /* if (`$xcg/parallele.01$X parallele=VRAI fichier=FICHIER` == $EXIST) then */ /* <BRANCHE_PARALLELE> */ /* else */ /* <BRANCHE_ALTERNATIVE> */ /* endif */ /* */ /* ou '<BRANCHE_PARALLELE>' represente ce */ /* qui peut etre parallelise puisque le verrou */ /* 'FICHIER$VERROU' a pu etre approprie par une */ /* MACHINE. En ce qui concerne les autres MACHINEs, */ /* elles continuent sur '<BRANCHE_ALTERNATIVE>' */ /* (eventuellement vide...). Cela correspond alors */ /* a l'ordonnancement suivant (par exemple) : */ /* */ /* */ /* | | | */ /* MACHINE_1 : | MACHINE_2 : | MACHINE_3 : | */ /* | | | */ /* ---------------------------+-----------------------------+-----------------------------+... */ /* | | | */ /* if (...) then | if (...) then | if (...) then | */ /* <SEQUENCE_1> | else | else | */ /* else | <RIEN> | <RIEN> | */ /* endif | endif | endif | */ /* | | | */ /* | | | */ /* if (...) then | if (...) then | if (...) then | */ /* else | <SEQUENCE_2> | else | */ /* <RIEN> | else | <RIEN> | */ /* endif | endif | endif | */ /* | | | */ /* | | | */ /* if (...) then | if (...) then | if (...) then | */ /* else | else | <SEQUENCE_3> | */ /* <RIEN> | <RIEN> | else | */ /* endif | endif | endif | */ /* | | | */ /* */ /* */ /* ou donc {<SEQUENCE_1>,<SEQUENCE_2>,<SEQUENCE_3>,...} */ /* s'executent en parallele sur {MACHINE_1,MACHINE_2,MACHINE_3,...}. */ /* */ /* */ /* Une autre utilisation est la suivante (introduite */ /* le 20070420094135) : */ /* */ /* if (`$xcg/parallele.01$X unique=VRAI fichier=FICHIER` == $EXIST) then */ /* <BRANCHE_UNIQUE> */ /* Fverrou FICHIER */ /* else */ /* endif */ /* */ /* ou '<BRANCHE_UNIQUE>' represente la branche */ /* qui doit etre a execution unique. Initialement, */ /* le fichier de nom 'FICHIER' n'existe pas ; la */ /* MACHINE qui s'approprie la branche via 'FICHIER$VERROU' */ /* doit, a la fin de "<BRANCHE_UNIQUE>" creer le fichier */ /* 'FICHIER' (en general en mode 'ro'...) via : */ /* */ /* Fverrou FICHIER */ /* */ /* en general. Les autres MACHINEs, pendant le temps */ /* d'execution de '<BRANCHE_UNIQUE>', sont en attente */ /* sur l'existence et le mode du fichier 'FICHIER'. */ /* Cela correspond alors a l'ordonnancement suivant */ /* (par exemple) : */ /* */ /* */ /* | | | */ /* MACHINE_1 : | MACHINE_2 : | MACHINE_3 : | */ /* | | | */ /* ---------------------------+-----------------------------+-----------------------------+... */ /* | | | */ /* | | | */ /* if (...) then | if (...) then | if (...) then | */ /* <SEQUENCE> | else | else | */ /* else | <ATTENTE> | <ATTENTE> | */ /* endif | endif | endif | */ /* | | | */ /* */ /* */ /* ou donc '<SEQUENCE>' ne s'execute que sur 'MACHINE_1', */ /* tandis que {MACHINE_2,MACHINE_3,...} attendent que */ /* 'MACHINE_1' ait fini l'execution de '<SEQUENCE>'. */ /* */ /* */ /* Nota : */ /* */ /* Dans l'etat actuel des choses (a la */ /* date du 1995051600), on peut considerer */ /* que l'on dispose des puissances de calcul */ /* suivantes : */ /* */ /* LACT12 SYSTEME_SGIND4GA_IRIX_CC : 1 */ /* LACT27 SYSTEME_SGIND524_IRIX_CC : 2 */ /* LACT28 SYSTEME_SGPCM801_IRIX_CC : 2 */ /* */ /* puis a la date du 19970212085116, des puissances */ /* de calcul suivantes (on notera que l'amelioration */ /* des performances de 'LACT27' remonte en fait a la */ /* date du 1996060400, lors de son passage a 250 MHz) : */ /* */ /* LACT12 SYSTEME_SGIND4GA_IRIX_CC : 1 */ /* LACT27 SYSTEME_SGIND524_IRIX_CC : 4 */ /* LACT28 SYSTEME_SGPCM801_IRIX_CC : 2 */ /* LACT29 SYSTEME_SGO200A1_IRIX_CC : 8 */ /* */ /* ou les valeurs numeriques (1, 2,...) donnent une */ /* quantite de travail dans une unite arbitraire... */ /* */ /* */ /* Nota : */ /* */ /* L'alias 'Gverrou' ('v $Fdivers Gverrou') permet */ /* de lister le contenu de chaque verrou '$v' */ /* et donc de savoir "qui a fait quoi...". */ /* */ /* */ /* ATTENTION : */ /* */ /* La commande '$xcg/parallele.01$X' ne */ /* doit pas s'utiliser avec les programmes */ /* faisant des calculs aleatoires, et par */ /* exemple : */ /* */ /* $xci/fract_2D.01$X, */ /* $xci/fract_3D.01$X, */ /* */ /* puisqu'en effet, les generateurs aleatoires */ /* de '$ximf/aleatoires$FON' sont tres dependants */ /* des machines ; le risque est donc d'avoir alors */ /* des resultats incompatibles entre-eux... */ /* */ /* */ /* Author of '$xcg/parallele.01$K' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, 1995??????????). */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* I N T E R F A C E ' listG ' : */ /* */ /* */ /* :Debut_listG: */ /* :Fin_listG: */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* D I R E C T I V E S S P E C I F I Q U E S D E C O M P I L A T I O N : */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* F I C H I E R S D ' I N C L U D E S : */ /* */ /*************************************************************************************************************************************/ #include INCLUDES_MINI /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* P A R A M E T R E S : */ /* */ /*===================================================================================================================================*/ #define FAIRE_DU_PARALLELISME \ VRAI \ /* Faut-il faire du parallelisme ('VRAI') ou pas ('FAUX') ? */ #define EXECUTER_UNE_SEQUENCE_EN_PARALLELE \ VRAI \ /* Si 'IL_FAUT(faire_du_parallelisme)' s'agit-il d'executer une sequence en parallele */ \ /* ('VRAI') ou bien de garantir l'execution unique d'une sequence ('FAUX') ? Ceci fut */ \ /* introduit le 20070420094135... */ #if ( (defined(CMAP28)) \ ) /* Introduit le 20070423134356... */ # define PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES \ VRAI \ /* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */ \ /* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */ \ /* 20070423121234... */ #Aif ( (defined(CMAP28)) \ ) # define PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES \ FAUX \ /* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */ \ /* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */ \ /* 20070423121234... */ #Eif ( (defined(CMAP28)) \ ) #define TESTER_LE_MODE_DU_FICHIER \ VRAI #define MODE_ATTENDU_POUR_LE_FICHIER \ Ftest_fichier_____MODE_r__ /* La possibilite de tester le mode du fichier, en plus de son existence, a ete introduite */ /* le 20070420152629. On notera que l'on choisi de tester par defaut l'existence du fichier */ /* 'nom_verrou_sans_le_postfixe_VERROU' avec en plus le mode 'r__' car, en effet, il s'agit */ /* de la solution la plus sure puisqu'un fichier peut etre cree en plusieurs fois, alors */ /* que son changement de mode (mode 'ro') est unique et ne peut avoir lieu qu'une fois le */ /* fichier completement cree... */ #define TEMPORISATION_D_ATTENTE_DE_LA_FIN_DE_LA_BRANCHE_A_EXECUTION_UNIQUE \ UN \ /* Temporisation d'attente de la fin de la branche a execution unique... */ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* M A C R O S U T I L E S : */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* G E S T I O N " E X T E R N E " D U P A R A L L E L I S M E : */ /* */ /*************************************************************************************************************************************/ BCommande(nombre_d_arguments,arguments) /*-----------------------------------------------------------------------------------------------------------------------------------*/ Bblock DEFV(CHAR,INIC(POINTERc(nom_verrou_sans_le_postfixe_VERROU),NOM_UNDEF_VIDE)); /* Nom du verrou a tester sans le postfixe '$VERROU'... */ DEFV(Logical,INIT(faire_du_parallelisme,FAIRE_DU_PARALLELISME)); /* Faut-il faire du parallelisme ('VRAI') ou pas ('FAUX') ? */ DEFV(Logical,INIT(executer_une_sequence_en_parallele,EXECUTER_UNE_SEQUENCE_EN_PARALLELE)); /* Si 'IL_FAUT(faire_du_parallelisme)' s'agit-il d'executer une sequence en parallele */ /* ('VRAI') ou bien de garantir l'execution unique d'une sequence ('FAUX') ? Ceci fut */ /* introduit le 20070420094135... */ DEFV(Logical,INIT(pre_mettre_a_jour_le_cache_des_directories,PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES)); /* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */ /* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */ /* 20070423121234... */ DEFV(Logical,INIT(tester_le_mode_du_fichier,TESTER_LE_MODE_DU_FICHIER)); DEFV(Positive,INIT(mode_attendu_pour_le_fichier,MODE_ATTENDU_POUR_LE_FICHIER)); /* La possibilite de tester le mode du fichier, en plus de son existence, a ete introduite */ /* le 20070420152629. On notera que l'on choisi de tester par defaut l'existence du fichier */ /* 'nom_verrou_sans_le_postfixe_VERROU' avec en plus le mode 'r__' car, en effet, il s'agit */ /* de la solution la plus sure puisqu'un fichier peut etre cree en plusieurs fois, alors */ /* que son changement de mode (mode 'ro') est unique et ne peut avoir lieu qu'une fois le */ /* fichier completement cree. */ /* */ /* On notera au passage les quelques modes utiles suivants : */ DEFV(Positive,INIT(mode_r__,Ftest_fichier_____MODE_r__)); DEFV(Positive,INIT(mode_r_x,Ftest_fichier_____MODE_r_x)); DEFV(Positive,INIT(mode_rw_,Ftest_fichier_____MODE_rw_)); DEFV(Positive,INIT(mode_rwx,Ftest_fichier_____MODE_rwx)); /* Pour aider... */ DEFV(Positive,INIT(temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique ,TEMPORISATION_D_ATTENTE_DE_LA_FIN_DE_LA_BRANCHE_A_EXECUTION_UNIQUE ) ); /* Temporisation d'attente de la fin de la branche a execution unique... */ /*..............................................................................................................................*/ GET_ARGUMENTS_(nombre_d_arguments ,BLOC(GET_ARGUMENT_C("verrou=""v=""fichier=""V=",nom_verrou_sans_le_postfixe_VERROU); GET_ARGUMENT_L("parallelisme=",faire_du_parallelisme); GET_ARGUMENT_L("parallele=""multiple=",executer_une_sequence_en_parallele); GET_ARGUMENT_N("unique=",executer_une_sequence_en_parallele); GET_ARGUMENT_L("pmajcd=""pmaj=""cache_des_directories=",pre_mettre_a_jour_le_cache_des_directories); GET_ARGUMENT_L("tm=""tester_mode=",tester_le_mode_du_fichier); GET_ARGUMENT_X("mode=",mode_attendu_pour_le_fichier); /* La procedure 'GET_ARGUMENT_X(...)' a remplace 'GET_ARGUMENT_I(...)' le 20070420185512... */ GET_ARGUMENT_Y("mode_r__=",mode_r__); GET_ARGUMENT_Y("mode_r_x=",mode_r_x); GET_ARGUMENT_Y("mode_rw_=",mode_rw_); GET_ARGUMENT_Y("mode_rwx=",mode_rwx); /* Pour aider a utiliser l'argument "mode=" (introduit le 20070424085256)... */ GET_ARGUMENT_I("temporisation=""tempo=""t=" ,temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique ); ) ); Test(IFNE_chaine(nom_verrou_sans_le_postfixe_VERROU,NOM_UNDEF_VIDE)) Bblock ePARALLELE(BLOC(CAL2(Prin1("%d",Gval("EXIST")));) /* On edite '$EXIST' si la branche "sequence_fondamentale" (ou "parallele") a ete empruntee, */ /* c'est-a-dire si le fichier 'nom_verrou_sans_le_postfixe_VERROU$VERROU' n'existait pas et */ /* a donc pu etre cree... */ /* */ /* On notera que l'on utilise 'Prin1(...)' (et non par 'Prer1(...)') a cause de l'usage qui */ /* est fait de cette edition. On verra par exemple : */ /* */ /* xivPdf 7 1 / 018363_018490 */ /* */ /* a ce propos... */ ,BLOC( Test(IL_FAUT(executer_une_sequence_en_parallele)) /* Cas de l'execution d'une sequence en parallele pour la branche "sequence_alternative" : */ /* */ /* cette branche rend alors la main immediatement (apres avoir edite "NEXIST" ci-apres). */ Bblock Eblock ATes Bblock /* Cas de l'execution unique d'une sequence pour la branche "sequence_alternative" : */ /* */ /* cette branche ne fait alors qu'attendre que la branche a execution unique soit terminee */ /* ce qui se manifeste par l'existence du fichier 'nom_verrou_sans_le_postfixe_VERROU'... */ DEFV(Logical,INIT(attendre_la_fin_de_la_branche_a_execution_unique,VRAI)); /* A priori, on va attendre... */ Tant(IL_FAUT(attendre_la_fin_de_la_branche_a_execution_unique)) Bblock Test(PAS_D_ERREUR(Ftest_fichier_avec_pre_mise_a_jour_du_cache_des_directories (nom_verrou_sans_le_postfixe_VERROU ,pre_mettre_a_jour_le_cache_des_directories ,NE_PAS_EDITER_LES_MESSAGES_D_ERREUR_DES_FICHIERS ) ) ) /* Le 20070423095209 je note que si le fichier 'nom_verrou_sans_le_postfixe_VERROU' n'est */ /* pas local, mais appartient a un volume 'NFS', l'operation 'Ftest_fichier(...)' est une */ /* "lecture" dans un directory. Or les directories "distants" de type 'NFS' sont caches */ /* localement et ne sont pas mis a jour en temps reel (si une autre MACHINE que cette */ /* MACHINE locale ecrit dedans, et en particulier sur 'nom_verrou_sans_le_postfixe_VERROU'). */ /* Il semblerait que la mise a jour des directories "distants" de type 'NFS' soient faites */ /* systematiquement et periodiquement (toutes les 'N' secondes : 10, 20,... ?), peut-etre */ /* tout simplement par invalidation de leur contenu, provoquant ainsi leur relecture lors */ /* d'un acces a eux. Cela pourrait expliquer donc que le 'Ftest_fichier(...)' puisse */ /* renvoyer une erreur pendant plusieurs secondes (30 secondes sur 'sumix??.cluster) alors */ /* que le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe malgre tout. */ /* */ /* En ce qui concerne les ecritures dans les directories, elles sont faites en temps reel */ /* sur les volumes 'NFS'. Ainsi, le 'Fstore_fichier_non_formatte(...)' que l'on trouve */ /* dans 'v $xig/defin_2$vv$DEF ePARALLELE', lui n'attend pas. */ /* */ /* Ainsi pour resumer : les ecritures 'NFS' dans les directories sont faites en temps reel, */ /* alors que les lectures (qui sont donc cachees) demandent un certain temps (plusieurs */ /* secondes...) pour etre valides... */ /* */ /* Le 20070423103314 je note qu'une solution pour eviter ce "delai" lors des lectures de */ /* directories dans 'Ftest_fichier(...)' pourrait etre de faire preceder le test d'existence */ /* de 'nom_verrou_sans_le_postfixe_VERROU' par l'ecriture d'un fichier temporaire situe dans */ /* le meme directory que le fichier 'nom_verrou_sans_le_postfixe_VERROU', ce qui forcerait */ /* alors la mise a jour du cache des directories. Cela fut introduit le 20070423121234 via */ /* la fonction 'Ftest_fichier_avec_pre_mise_a_jour_du_cache_des_directories(...)'. */ Bblock /* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe : */ Test(IL_FAUT(tester_le_mode_du_fichier)) Bblock Test(EST_VALIDE(Ftest_fichier_____informations_utiles)) /* Test introduit le 20070424085256... */ Bblock Test(IFEQ(Ftest_fichier_____mode,mode_attendu_pour_le_fichier)) Bblock EGAL(attendre_la_fin_de_la_branche_a_execution_unique,FAUX); /* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe et a le mode attendu : on */ /* doit arreter d'attendre... */ Eblock ATes Bblock Eblock ETes Eblock ATes Bblock PRINT_ERREUR("les informations concernant le fichier sont invalides"); CAL1(Prer1("(il s'agit du fichier '%s')\n",nom_verrou_sans_le_postfixe_VERROU)); Eblock ETes Eblock ATes Bblock EGAL(attendre_la_fin_de_la_branche_a_execution_unique,FAUX); /* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe et ou le mode est */ /* indifferent : on doit arreter d'attendre... */ Eblock ETes Eblock ATes Bblock Eblock ETes Test(IL_FAUT(attendre_la_fin_de_la_branche_a_execution_unique)) Bblock DODO(temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique); /* Cas ou l'on doit attendre... */ Eblock ATes Bblock Eblock ETes Eblock ETan Eblock ETes CAL2(Prin1("%d",Gval("NEXIST"))); ) /* On edite '$NEXIST' si c'est la branche "sequence_alternative" qui a ete empruntee, */ /* c'est-a-dire si le fichier 'nom_verrou_sans_le_postfixe_VERROU$VERROU' pre-existait... */ /* */ /* On notera que l'on utilise 'Prin1(...)' (et non par 'Prer1(...)') a cause de l'usage qui */ /* est fait de cette edition. On verra par exemple : */ /* */ /* xivPdf 7 1 / 018363_018490 */ /* */ /* a ce propos... */ ,faire_du_parallelisme ,nom_verrou_sans_le_postfixe_VERROU ); Eblock ATes Bblock PRINT_ERREUR("le nom du verrou doit obligatoirement etre defini"); Eblock ETes RETU_Commande; Eblock ECommande