, 65: cout << "P" << rank << ": " 66: << "somme locale " << m <<, vol.64

, Reduce, Finalize, ?) imposent aux processus de s'attendre mutuellement. Toutefois, avant d'afficher le résultat final du calcul de la moyenne, il est préférable de s'assurer que tous les processus ont fini d'écrire les informations de debuggage (lignes 65 à 68). Pour cela, il suffit de poser une barrière (ligne 70), c'est-à-dire une opération collective qui ne fait rien de plus que d'empêcher un processus de poursuivre tant que tous les autres processus ne, Il est à noter que chaque processus travaille à son rythme. Toutefois, les opérations collectives (Init

. L&apos;usage-de-barrières-est-pratique, puisqu'il permet de synchroniser l'exécution des processus, toutefois -et l'analogie avec la barrière est très pertinente -cela les ralentis également. Ainsi, mettre une barrière juste avant l'opération de réduction ne présente aucun intérêt puisque la réduction elle-même fait office de barrière. De même, si le code de debuggage (lignes 65 à 68) est à terme supprimé

, Seul le processus de rang 0 (ligne 72) va donc diviser la somme globale par le nombre de valeurs (ligne 73 ; je rappelle à toutes fins utiles que nous avons garanti que argc est supérieur ou égal à 2 -ligne 36 -et donc que (argc -1) est non nul). Enfin, ce processus va afficher la moyenne sur la sortie standard. 72: if (!rank) { 73: m2 /= (argc -1), vol.74

, Il reste à remercier une fois de plus la fonction atexit de faire le travail de finalisation de la communication MPI tout en renvoyant 0 au système d'exploitation pour lui signifier que le programme s'est correctement exécuté. 77: return 0; 78: } Compilons maintenant ce programme : $ mpic++ -Wall -ansi -pedantic -std=c++11 moyenne-mpi.cpp -o moyenne-mpi

, Cela semble fonctionner (c'est heureux)

, Essayons maintenant dans l'environnement MPI, avec un seul processus

, On obtient le même résultat, ce qui est plutôt rassurant

A. Le-nombre-de-processus, si possible avec une valeur qui ne soit pas un diviseur de 8 pour éviter de tomber dans un cas, p.28

, On peut vérifier que nos 8 valeurs sont correctement réparties sur les 3 instances. On s'aperçoit également que seul le processus de rang 0 connaît la valeur de m2 (tous les autres n'ont pas modifié la valeur par défaut de m2 -quelle bonne habitude de programmation que de systématiquement initialiser ses variables

, Eh bien, théoriquement ça fonctionne, puisque dans ce cas, les premiers processus auront une seule valeur à traiter et les suivants n'en auront pas, La question que nous avons jusqu'alors passé sous silence est de savoir ce qu'il se passe si nous exécutons notre programme avec plus d'instances que de valeurs, p.28

, Cela fonctionne encore. C'était un petit pas dans le calcul de la moyenne

, OpenMP ou Open MPI

, Je pourrais faire une réponse de normand en expliquant que cela dépend du contexte, et c'est finalement la seule véritable bonne réponse, mais dans le cas présent, l'objectif est d'illustrer les deux paradigmes. Par conséquent, la réponse sera pour cet article de ne pas les opposer

, $ patch --input mpi2hybride.patch --output moyenne-hybride.cpp patching file moyenne-hybride.cpp (read from moyenne-mpi

, $ mpic++ -Wall -ansi -pedantic -std=c++11 moyenne-hybride.cpp -fopenmp -o moyenne-hybride Puis à exécuter notre programme

, P1: somme locale 12, somme globale 0 P2: somme locale 13, p.28

, That's (presque) All, Folks !!! Et dans la vraie vie ?

, Quelle question ! Vous lisez GLMF, vous êtes donc dans la vraie vie? En tout cas, c'est ce qu'aurait pu dire un certain Blaise P. s'il avait vécu à notre époque. Toutefois, j'ai volontairement omis une complication majeure liée à la programmation hybride avec OpenMP et Open MPI

. Au-lieu-de-mpi, La méthode statique MPI::Init_thread() -à l'instar de la méthode statique MPI::Init() -existe en deux versions, l'une qui prend en paramètres les arguments argc, argv de la fonction main (et ne s'en sert absolument pas) et une qui ne les prends pas. Cependant, contrairement à la méthode statique MPI::Init(), la méthode statique MPI::Init_thread() requiert un argument supplémentaire qui correspond au niveau de parallélisme léger supporté. Les quatre niveaux proposés sont représentés par quatre constantes : MPI_THREAD_SINGLE Un seul processus léger est exécuté, En effet, il n'y a pas de soucis tant que la parallélisation légère n'émet ni ne reçoit de messages MPI

, MPI_THREAD_FUNNELED Seul le processus léger qui a appelé la méthode MPI::Init_thread() communiquera dans l'univers MPI

, MPI_THREAD_SERIALIZED Lorsque plusieurs processus légers sont en cours d'éxécution, un seul parmi eux communiquera dans l'univers MPI

, MPI_THREAD_MULTIPLE Tous les processus légers peuvent communiquer parallèlement dans l'univers MPI

, Bien évidemment, plus le niveau autorise des opérations de communication complexes, plus cela impacte les performances

, Comme vous l'aurez compris, l'appel de MPI::Init(

, Là où les choses se compliquent encore, c'est que toutes les implémentations de MPI ne gèrent pas nécessairement le 4 e niveau (qui crée des complications qui ne sont pas nécessairement encore très bien gérées). Le cas échéant, l'initialisation se

, Pour savoir si votre implémentation d'Open MPI supporte le niveau MPI_THREAD_MULTIPLE, il suffit de le lui demander : $ ompi_info | grep -i thread Thread support: posix (MPI_THREAD_MULTIPLE: no, OPAL support: yes, OMPI progress: no, ORTE progress: yes

. $-comme-vous-pouvez-le-constater,

, Mais vous imaginez bien que le programme doit pouvoir détecter si le niveau demandé est supporté pour éventuellement afficher un message d'avertissement, dérouler une stratégie alternative, ou tout simplement quitter proprement. C'est pour cette raison que la méthode statique MPI::Init_thread(

, Je ne peux pas continuer à travailler dans de telles conditions, Ainsi, un code judicieux dans ce cas serait : if (MPI::Init_thread(MPI_THREAD_SERIALIZED) != MPI_THREAD_SERIALIZED) { cerr <<

, } Notez au passage que cet exemple m'a permis de subrepticement glisser la méthode Abort() du communicateur MPI::COMM_World dont l'intérêt réside dans l'arrêt de tous les processus

, Comme toujours, le choix du langage doit dépendre des objectifs et non de notre champ de compétence ou de notre affinité, Alternatives Bien évidemment, certains langages intègrent plus ou moins implicitement et naturellement les paradigmes de parallélisme, tels que NodeJS ou Go

. Ceci, on souhaite résoudre est simple et ne nécessite que peu de ressources matérielles, le choix reste assez libre. Dès lors que le volume de données à traiter devient colossal (aire haire hère ère du BigData) le besoin de performance devient primordial et le passage à des langages tels que le C++ voire le C (qui contrairement à ce que l'on peut lire parfois -y compris dans d'illustres revues comme GNU/Linux Mag, Linux Pratique HS, ? -est un langage de haut niveau) sont une nécessité et les implémentations des standards OpenMP et Open MPI sont clairement opportunes

«. Qu, est-ce qu'un algorithme ?, Philippe Flajolet et Étienne Parizot

. «-comme-d&apos;habitude, Chanson écrite par Gilles Thibaut et Claude François, musique de Jacques Revaux et Claude François, 1967.

«. Bibbidi-bobbidi-boo, Chanson écrite et composée par Mack David, Al Hoffman et Jerry Livingston1 pour le long-métrage Disney Cendrillon, 1950.