Interface de transmission de messages - Message Passing Interface

L'interface de transmission de messages ( MPI ) est une norme de transmission de messages standardisée et portable conçue pour fonctionner sur des architectures informatiques parallèles . La norme MPI définit la syntaxe et la sémantique des routines de bibliothèque qui sont utiles à un large éventail d'utilisateurs écrivant des programmes de transmission de messages portables en C , C++ et Fortran . Il existe plusieurs implémentations MPI open source , qui ont favorisé le développement d'une industrie du logiciel parallèle et encouragé le développement d'applications parallèles portables et évolutives à grande échelle.

Histoire

L'effort d'interface de transmission de messages a commencé à l'été 1991 lorsqu'un petit groupe de chercheurs a entamé des discussions dans une retraite de montagne en Autriche. De cette discussion est né un atelier sur les normes de transmission de messages dans un environnement de mémoire distribuée, qui s'est tenu les 29 et 30 avril 1992 à Williamsburg, en Virginie . Les participants à Williamsburg ont discuté des fonctionnalités de base essentielles à une interface de transmission de messages standard et ont établi un groupe de travail pour poursuivre le processus de normalisation. Jack Dongarra , Tony Hey et David W. Walker ont présenté un avant-projet de proposition, "MPI1", en novembre 1992. En novembre 1992, une réunion du groupe de travail MPI a eu lieu à Minneapolis et a décidé de placer le processus de normalisation sur un plan plus pied formel. Le groupe de travail MPI s'est réuni toutes les 6 semaines au cours des 9 premiers mois de 1993. Le projet de norme MPI a été présenté à la conférence Supercomputing '93 en novembre 1993. Après une période de commentaires publics, qui a entraîné quelques changements dans MPI, la version 1.0 de MPI est sorti en juin 1994. Ces réunions et la discussion par courrier électronique ont constitué le Forum MPI, dont l'adhésion a été ouverte à tous les membres de la communauté du calcul haute performance .

L'effort de MPI a impliqué environ 80 personnes de 40 organisations, principalement aux États-Unis et en Europe. La plupart des principaux fournisseurs d' ordinateurs concurrents ont été impliqués dans l'effort MPI, en collaboration avec des chercheurs d'universités, de laboratoires gouvernementaux et de l' industrie .

MPI fournit aux fournisseurs de matériel parallèle un ensemble de routines de base clairement défini qui peuvent être efficacement mis en œuvre. En conséquence, les fournisseurs de matériel peuvent s'appuyer sur cette collection de routines standard de bas niveau pour créer des routines de niveau supérieur pour l'environnement de communication à mémoire distribuée fourni avec leurs machines parallèles . MPI fournit une interface portable simple à utiliser pour l'utilisateur de base, mais suffisamment puissante pour permettre aux programmeurs d'utiliser les opérations de transmission de messages hautes performances disponibles sur les machines avancées.

Dans un effort pour créer une norme universelle pour la transmission de messages, les chercheurs ne l'ont pas basé sur un seul système, mais ont incorporé les fonctionnalités les plus utiles de plusieurs systèmes, y compris ceux conçus par IBM, Intel , nCUBE , PVM, Express, P4 et PARMACS. . Le paradigme de transmission de messages est attrayant en raison de sa grande portabilité et peut être utilisé dans la communication pour les multiprocesseurs à mémoire distribuée et à mémoire partagée, les réseaux de postes de travail et une combinaison de ces éléments. Le paradigme peut s'appliquer à plusieurs paramètres, indépendamment de la vitesse du réseau ou de l'architecture de la mémoire.

Le soutien aux réunions du MPI est venu en partie de la DARPA et de la National Science Foundation (NSF) des États-Unis dans le cadre de la subvention ASC-9310330, de l'accord de coopération NSF Science and Technology Center numéro CCR-8809615, et de la Commission européenne via le projet Esprit P6643. L' Université du Tennessee a également apporté des contributions financières au Forum MPI.

Aperçu

MPI est un protocole de communication pour la programmation d' ordinateurs parallèles . Les communications point à point et collectives sont prises en charge. MPI « est une interface de programmation d'applications de transmission de messages, ainsi que des spécifications de protocole et de sémantique sur la façon dont ses fonctionnalités doivent se comporter dans toute implémentation ». Les objectifs de MPI sont la haute performance, l'évolutivité et la portabilité. MPI reste le modèle dominant utilisé dans le calcul haute performance aujourd'hui.

MPI n'est sanctionné par aucun organisme de normalisation majeur ; néanmoins, il est devenu une norme de facto pour la communication entre les processus qui modélisent un programme parallèle s'exécutant sur un système de mémoire distribuée . Les superordinateurs à mémoire distribuée réels, tels que les grappes d'ordinateurs, exécutent souvent de tels programmes.

Le modèle principal MPI-1 n'a pas de concept de mémoire partagée , et MPI-2 n'a qu'un concept limité de mémoire partagée distribuée . Néanmoins, les programmes MPI sont régulièrement exécutés sur des ordinateurs à mémoire partagée, et MPICH et Open MPI peuvent utiliser la mémoire partagée pour le transfert de messages si elle est disponible. Concevoir des programmes autour du modèle MPI (contrairement aux modèles explicites de mémoire partagée ) présente des avantages par rapport aux architectures NUMA puisque MPI encourage la localisation de la mémoire . La programmation explicite de la mémoire partagée a été introduite dans MPI-3.

Bien que MPI appartienne aux couches 5 et supérieures du modèle de référence OSI , les implémentations peuvent couvrir la plupart des couches, avec des sockets et le protocole TCP ( Transmission Control Protocol ) utilisés dans la couche de transport.

La plupart des implémentations MPI consistent en un ensemble spécifique de routines directement appelables depuis C , C++ , Fortran (c'est-à-dire une API) et tout langage capable de s'interfacer avec de telles bibliothèques, y compris C# , Java ou Python . Les avantages de MPI par rapport aux anciennes bibliothèques de transmission de messages sont la portabilité (car MPI a été implémenté pour presque toutes les architectures de mémoire distribuée) et la vitesse (car chaque implémentation est en principe optimisée pour le matériel sur lequel elle s'exécute).

MPI utilise des spécifications indépendantes de la langue (LIS) pour les appels et les liaisons de langue. La première norme MPI spécifiait les liaisons ANSI C et Fortran-77 avec le LIS. Le projet a été présenté à Supercomputing 1994 (novembre 1994) et finalisé peu de temps après. Environ 128 fonctions constituent la norme MPI-1.3 qui a été publiée comme la fin finale de la série MPI-1 en 2008.

À l'heure actuelle, la norme a plusieurs versions : la version 1.3 (généralement abrégée MPI-1 ), qui met l'accent sur le passage de messages et dispose d'un environnement d'exécution statique, MPI-2.2 (MPI-2), qui inclut de nouvelles fonctionnalités telles que les E/S parallèles, gestion dynamique des processus et opérations de mémoire à distance, et MPI-3.1 (MPI-3), qui comprend des extensions aux opérations collectives avec des versions non bloquantes et des extensions aux opérations unilatérales. Le LIS de MPI-2 spécifie plus de 500 fonctions et fournit des liaisons de langage pour ISO C , ISO C++ et Fortran 90 . L'interopérabilité des objets a également été ajoutée pour permettre une programmation de passage de messages en plusieurs langues plus facile. Un effet secondaire de la standardisation du MPI-2, achevée en 1996, a été de clarifier le standard MPI-1, créant le MPI-1.2.

MPI-2 est principalement un sur-ensemble de MPI-1, bien que certaines fonctions aient été dépréciées. Les programmes MPI-1.3 fonctionnent toujours sous des implémentations MPI conformes à la norme MPI-2.

MPI-3 inclut de nouvelles liaisons Fortran 2008, tout en supprimant les liaisons C++ obsolètes ainsi que de nombreuses routines et objets MPI obsolètes.

MPI est souvent comparé à la machine virtuelle parallèle (PVM), qui est un environnement distribué populaire et un système de transmission de messages développé en 1989, et qui a été l'un des systèmes qui ont motivé le besoin de transmission de messages parallèle standard. Les modèles de programmation de mémoire partagée filetée (tels que Pthreads et OpenMP ) et la programmation de passage de messages (MPI/PVM) peuvent être considérés comme complémentaires et ont été utilisés ensemble à l'occasion dans, par exemple, des serveurs avec plusieurs grands nœuds de mémoire partagée.

Fonctionnalité

L'interface MPI est destinée à fournir des fonctionnalités essentielles de topologie virtuelle, de synchronisation et de communication entre un ensemble de processus (qui ont été mappés sur des nœuds/serveurs/instances informatiques) d'une manière indépendante du langage, avec une syntaxe spécifique au langage (liaisons), ainsi que quelques fonctionnalités spécifiques à la langue. Les programmes MPI fonctionnent toujours avec des processus, mais les programmeurs appellent généralement les processus des processeurs. En règle générale, pour des performances maximales, chaque processeur (ou cœur d'une machine multicœur) se verra attribuer un seul processus. Cette affectation se produit au moment de l'exécution via l'agent qui démarre le programme MPI, normalement appelé mpirun ou mpiexec.

Les fonctions de la bibliothèque MPI incluent, sans s'y limiter, les opérations d'envoi/réception de type rendez-vous point à point, le choix entre une topologie de processus logique cartésienne ou graphique , l'échange de données entre des paires de processus (opérations d'envoi/réception), la combinaison de les résultats des calculs (opérations de collecte et de réduction), la synchronisation des nœuds (opération de barrière) ainsi que l'obtention d'informations liées au réseau telles que le nombre de processus dans la session de calcul, l'identité actuelle du processeur auquel un processus est mappé, les processus voisins accessibles dans un topologie logique, etc. Les opérations point à point se présentent sous des formes synchrones , asynchrones , tamponnées et prêtes , pour permettre une sémantique à la fois relativement plus forte et plus faible pour les aspects de synchronisation d'un envoi de rendez-vous. De nombreuses opérations en suspens sont possibles en mode asynchrone, dans la plupart des implémentations.

MPI-1 et MPI-2 permettent tous deux des implémentations qui chevauchent la communication et le calcul, mais la pratique et la théorie diffèrent. MPI spécifie également des interfaces thread-safe , qui ont des stratégies de cohésion et de couplage qui aident à éviter l'état caché au sein de l'interface. Il est relativement facile d'écrire du code MPI point à point multithread, et certaines implémentations prennent en charge un tel code. La communication collective multithread est mieux réalisée avec plusieurs copies de Communicators, comme décrit ci-dessous.

notions

MPI propose plusieurs fonctionnalités. Les concepts suivants fournissent un contexte pour toutes ces capacités et aident le programmeur à décider quelle fonctionnalité utiliser dans ses programmes d'application. Quatre des huit concepts de base de MPI sont propres à MPI-2.

Communicateur

Les objets Communicator connectent des groupes de processus dans la session MPI. Chaque communicateur attribue à chaque processus contenu un identifiant indépendant et organise ses processus contenus dans une topologie ordonnée . MPI a également des groupes explicites, mais ceux-ci sont principalement utiles pour organiser et réorganiser des groupes de processus avant qu'un autre communicateur ne soit créé. MPI comprend les opérations intracommunicatrices d'un seul groupe et la communication intercommunicatrice bilatérale. Dans MPI-1, les opérations de groupe unique sont les plus répandues. Les opérations bilatérales apparaissent principalement dans MPI-2 où elles incluent la communication collective et la gestion dynamique en cours de processus.

Les communicateurs peuvent être partitionnés à l'aide de plusieurs commandes MPI. Ces commandes incluent MPI_COMM_SPLIT, où chaque processus rejoint l'un des plusieurs sous-communicateurs colorés en se déclarant avoir cette couleur.

Bases point à point

Un certain nombre de fonctions MPI importantes impliquent une communication entre deux processus spécifiques. Un exemple populaire est MPI_Send, qui permet à un processus spécifié d'envoyer un message à un deuxième processus spécifié. Les opérations point à point, comme on les appelle, sont particulièrement utiles dans les communications structurées ou irrégulières, par exemple, une architecture parallèle de données dans laquelle chaque processeur échange régulièrement des régions de données avec d'autres processeurs spécifiques entre les étapes de calcul, ou un maître- architecture esclave dans laquelle le maître envoie de nouvelles données de tâche à un esclave chaque fois que la tâche précédente est terminée.

MPI-1 spécifie des mécanismes pour les mécanismes de communication point à point bloquants et non bloquants, ainsi que le mécanisme dit « prêt à envoyer » par lequel une demande d'envoi ne peut être faite que lorsque la demande de réception correspondante a déjà été faite .

Fondamentaux collectifs

Les fonctions collectives impliquent la communication entre tous les processus d'un groupe de processus (ce qui peut signifier l'ensemble du pool de processus ou un sous-ensemble défini par le programme). Une fonction typique est l' MPI_Bcastappel (abréviation de « diffusion »). Cette fonction prend les données d'un nœud et les envoie à tous les processus du groupe de processus. Une opération inverse est l' MPI_Reduceappel, qui prend les données de tous les processus d'un groupe, effectue une opération (telle que la sommation) et stocke les résultats sur un nœud. MPI_Reduceest souvent utile au début ou à la fin d'un grand calcul distribué, où chaque processeur opère sur une partie des données puis les combine en un résultat.

D'autres opérations effectuent des tâches plus sophistiquées, telles que la MPI_Alltoallréorganisation de n éléments de données de telle sorte que le n ème nœud obtienne le n ème élément de données de chacun.

Types de données dérivés

De nombreuses fonctions MPI nécessitent que vous spécifiiez le type de données qui sont envoyées entre les processus. En effet, MPI vise à prendre en charge des environnements hétérogènes où les types peuvent être représentés différemment sur les différents nœuds (par exemple, ils peuvent exécuter différentes architectures de processeurs ayant un endianness différent ), auquel cas les implémentations MPI peuvent effectuer une conversion de données . Comme le langage C ne permet pas de passer un type lui-même en paramètre, MPI prédéfinit les constantes MPI_INT, MPI_CHAR, MPI_DOUBLEpour correspondre à int, char, double, etc.

Voici un exemple en C qui passe des tableaux de ints de tous les processus à un seul. Le seul processus de réception est appelé le processus "racine", et il peut s'agir de n'importe quel processus désigné mais normalement ce sera le processus 0. Tous les processus demandent d'envoyer leurs tableaux à la racine avec MPI_Gather, ce qui équivaut à avoir chaque processus (y compris le root lui-même) appel MPI_Sendet la racine effectue le nombre correspondant d' MPI_Recvappels ordonnés pour assembler tous ces tableaux en un plus grand :

int send_array[100];
int root = 0; /* or whatever */
int num_procs, *recv_array;
MPI_Comm_size(comm, &num_procs);
recv_array = malloc(num_procs * sizeof(send_array));
MPI_Gather(send_array, sizeof(send_array) / sizeof(*send_array), MPI_INT,
           recv_array, sizeof(send_array) / sizeof(*send_array), MPI_INT,
           root, comm);

Cependant, vous pouvez à la place envoyer les données sous forme de bloc au lieu de 100 ints. Pour ce faire, définissez un type de données dérivé « bloc contigu » :

MPI_Datatype newtype;
MPI_Type_contiguous(100, MPI_INT, &newtype);
MPI_Type_commit(&newtype);
MPI_Gather(array, 1, newtype, receive_array, 1, newtype, root, comm);

Pour transmettre une classe ou une structure de données, MPI_Type_create_structcrée un type de MPI_predefineddonnées dérivé MPI à partir des types de données, comme suit :

int MPI_Type_create_struct(int count,
                           int *blocklen,
                           MPI_Aint *disp,
                           MPI_Datatype *type,
                           MPI_Datatype *newtype)

où:

  • countest un nombre de blocs et spécifie la longueur (en éléments) des tableaux blocklen, disp, et type.
  • blocklen contient des nombres d'éléments dans chaque bloc,
  • disp contient les déplacements d'octets de chaque bloc,
  • type contient des types d'éléments dans chaque bloc.
  • newtype (une sortie) contient le nouveau type dérivé créé par cette fonction

Le disptableau (déplacements) est nécessaire pour l'alignement de la structure de données , car le compilateur peut remplir les variables dans une classe ou une structure de données. Le moyen le plus sûr de trouver la distance entre les différents champs est d'obtenir leurs adresses en mémoire. Ceci est fait avec MPI_Get_address, qui est normalement le même que l' &opérateur de C, mais cela peut ne pas être vrai lorsqu'il s'agit de segmentation de mémoire .

La transmission d'une structure de données sous forme d'un bloc est nettement plus rapide que la transmission d'un élément à la fois, en particulier si l'opération doit être répétée. En effet, les blocs de taille fixe ne nécessitent pas de sérialisation pendant le transfert.

Étant donné les structures de données suivantes :

struct A {
    int f;
    short p;
};

struct B {
    struct A a;
    int pp, vp;
};

Voici le code C pour créer un type de données dérivé de MPI :

static const int blocklen[] = {1, 1, 1, 1};
static const MPI_Aint disp[] = {
    offsetof(struct B, a) + offsetof(struct A, f),
    offsetof(struct B, a) + offsetof(struct A, p),
    offsetof(struct B, pp),
    offsetof(struct B, vp)
};
static MPI_Datatype type[] = {MPI_INT, MPI_SHORT, MPI_INT, MPI_INT};
MPI_Datatype newtype;
MPI_Type_create_struct(sizeof(type) / sizeof(*type), blocklen, disp, type, &newtype);
MPI_Type_commit(&newtype);

Concepts MPI-2

Communication unilatérale

MPI-2 définit trois opérations de communication unilatérales, MPI_Put, MPI_Get, et MPI_Accumulate, étant une écriture dans la mémoire distante, une lecture à partir de la mémoire distante et une opération de réduction sur la même mémoire sur un certain nombre de tâches, respectivement. Trois méthodes différentes sont également définies pour synchroniser cette communication (verrouillages globaux, par paires et distants) car la spécification ne garantit pas que ces opérations ont eu lieu jusqu'à un point de synchronisation.

Ces types d'appels peuvent souvent être utiles pour des algorithmes dans lesquels la synchronisation serait gênante (par exemple , multiplication matricielle distribuée ), ou lorsqu'il est souhaitable que les tâches puissent équilibrer leur charge pendant que d'autres processeurs fonctionnent sur des données.

Gestion dynamique des processus

L'aspect clé est "la capacité d'un processus MPI à participer à la création de nouveaux processus MPI ou à établir une communication avec des processus MPI qui ont été démarrés séparément". La spécification MPI-2 décrit trois interfaces principales par lesquelles les processus MPI peuvent établir dynamiquement des communications, MPI_Comm_spawn, MPI_Comm_accept/ MPI_Comm_connectet MPI_Comm_join. L' MPI_Comm_spawninterface permet à un processus MPI de générer un certain nombre d'instances du processus MPI nommé. L'ensemble de processus MPI nouvellement généré forme un nouvel MPI_COMM_WORLDintracommunicateur mais peut communiquer avec le parent et l'intercommunicateur que la fonction renvoie. MPI_Comm_spawn_multipleest une interface alternative qui permet aux différentes instances générées d'être des binaires différents avec des arguments différents.

E/S

La fonction d'E/S parallèle est parfois appelée MPI-IO et fait référence à un ensemble de fonctions conçues pour faire abstraction de la gestion des E/S sur les systèmes distribués en MPI et permettre d'accéder facilement aux fichiers de manière structurée à l'aide de la fonctionnalité de type de données dérivée existante. .

Le peu de recherche qui a été effectuée sur cette fonctionnalité indique qu'il n'est peut-être pas anodin d'obtenir des gains de performances élevés en utilisant MPI-IO. Par exemple, une implémentation de multiplications matrice-vecteur éparses utilisant la bibliothèque d'E/S MPI montre un comportement général de gain de performances mineur, mais ces résultats ne sont pas concluants. Ce n'est qu'avec l'idée d'E/S collectives implémentée dans MPI-IO que MPI-IO a commencé à être largement adopté. Les E/S collectives augmentent considérablement la bande passante des E/S des applications en faisant en sorte que les processus transforment collectivement les opérations d'E/S petites et non contiguës en opérations volumineuses et contiguës, réduisant ainsi le temps système de verrouillage et de recherche de disque. En raison de ses vastes avantages en termes de performances, MPI-IO est également devenu la couche d'E/S sous-jacente pour de nombreuses bibliothèques d'E/S de pointe, telles que HDF5 et Parallel NetCDF . Sa popularité a également déclenché des recherches sur les optimisations d'E/S collectives, telles que les E/S sensibles à la disposition et l'agrégation entre fichiers.

Implémentations officielles

De nombreux autres efforts sont des dérivés de MPICH, LAM et d'autres travaux, y compris, mais sans s'y limiter, des implémentations commerciales de HP , Intel , Microsoft et NEC .

Bien que les spécifications imposent une interface C et Fortran, le langage utilisé pour implémenter MPI n'est pas contraint de correspondre au ou aux langages qu'il cherche à prendre en charge lors de l'exécution. La plupart des implémentations combinent C, C++ et assembleur, et ciblent les programmeurs C, C++ et Fortran. Les liaisons sont disponibles pour de nombreux autres langages, notamment Perl, Python, R, Ruby, Java et CL (voir #Language bindings ).

L' ABI des implémentations MPI est à peu près répartie entre les dérivés MPICH et OpenMP, de sorte qu'une bibliothèque d'une famille fonctionne comme un remplacement direct d'une bibliothèque de la même famille, mais le remplacement direct entre les familles est impossible. Le CEA français maintient une interface wrapper pour faciliter de tels basculements.

Matériel

La recherche sur le matériel MPI se concentre sur la mise en œuvre de MPI directement dans le matériel, par exemple via un processeur en mémoire , en intégrant des opérations MPI dans les microcircuits des puces RAM de chaque nœud. Par implication, cette approche est indépendante de la langue, du système d'exploitation et du processeur, mais ne peut pas être facilement mise à jour ou supprimée.

Une autre approche a consisté à ajouter une accélération matérielle à une ou plusieurs parties de l'opération, y compris le traitement matériel des files d'attente MPI et l'utilisation de RDMA pour transférer directement les données entre la mémoire et l' interface réseau sans intervention du processeur ou du noyau du système d'exploitation.

Emballages de compilateur

mpic (et de la même manière mpic++ , mpif90 , etc.) est un programme qui encapsule un compilateur existant pour définir les indicateurs de ligne de commande nécessaires lors de la compilation de code qui utilise MPI. En règle générale, il ajoute quelques indicateurs qui permettent au code d'être compilé et lié à la bibliothèque MPI.

Liaisons de langue

Les liaisons sont des bibliothèques qui étendent la prise en charge de MPI à d'autres langages en enveloppant une implémentation MPI existante telle que MPICH ou Open MPI.

Infrastructure linguistique commune

Les deux implémentations gérées de Common Language Infrastructure .NET sont Pure Mpi.NET et MPI.NET, un effort de recherche de l'Université d'Indiana sous licence de type BSD . Il est compatible avec Mono et peut tirer pleinement parti des structures de réseau MPI sous-jacentes à faible latence.

Java

Bien que Java n'ait pas de liaison MPI officielle, plusieurs groupes tentent de combler les deux, avec différents degrés de réussite et de compatibilité. L'une des premières tentatives a été le mpiJava de Bryan Carpenter, essentiellement un ensemble de wrappers Java Native Interface (JNI) vers une bibliothèque C MPI locale, résultant en une implémentation hybride avec une portabilité limitée, qui doit également être compilée avec la bibliothèque MPI spécifique utilisée .

Cependant, ce projet original a également défini l'API mpiJava (une API MPI de facto pour Java qui suivait de près les liaisons C++ équivalentes) que d'autres projets Java MPI ultérieurs ont adoptés. Une API moins utilisée est l'API MPJ, qui a été conçue pour être plus orientée objet et plus proche des conventions de codage de Sun Microsystems . Au-delà de l'API, les bibliothèques MPI Java peuvent soit dépendre d'une bibliothèque MPI locale, soit implémenter les fonctions de transmission de messages en Java, tandis que certaines, comme P2P-MPI, fournissent également des fonctionnalités d' égal à égal et permettent un fonctionnement sur plusieurs plates-formes.

Certaines des parties les plus difficiles de Java/MPI découlent des caractéristiques de Java telles que le manque de pointeurs explicites et l' espace d'adressage de mémoire linéaire pour ses objets, ce qui rend le transfert de tableaux multidimensionnels et d'objets complexes inefficace. Les solutions de contournement impliquent généralement le transfert d'une ligne à la fois et/ou l'exécution d'une dé- sérialisation et d'un transtypage explicites à la fois aux extrémités d'envoi et de réception, en simulant des tableaux de type C ou Fortran à l'aide d'un tableau à une dimension et des pointeurs vers des types primitifs en l'utilisation de tableaux à un seul élément, aboutissant ainsi à des styles de programmation assez éloignés des conventions Java.

Un autre système de transmission de messages Java est MPJ Express. Les versions récentes peuvent être exécutées dans des configurations cluster et multicœur. Dans la configuration en cluster, il peut exécuter des applications Java parallèles sur des clusters et des clouds. Ici, les sockets Java ou les interconnexions d'E/S spécialisées comme Myrinet peuvent prendre en charge la messagerie entre les processus MPJ Express. Il peut également utiliser l'implémentation C native de MPI à l'aide de son périphérique natif. Dans la configuration multicœur, une application Java parallèle est exécutée sur des processeurs multicœurs. Dans ce mode, les processus MPJ Express sont représentés par des threads Java.

Julia

Le wrapper de langage Julia pour MPI a été utilisé et s'est avéré plus rapide que pour C ou Fortran.

MATLAB

Il existe quelques implémentations académiques de MPI utilisant MATLAB . MATLAB possède sa propre bibliothèque d'extensions parallèles implémentée à l'aide de MPI et PVM .

OCaml

Le module OCamlMPI implémente un grand sous-ensemble de fonctions MPI et est activement utilisé dans le calcul scientifique. Un programme OCaml de 11 000 lignes a été « MPI-ifié » à l'aide du module, avec 500 lignes de code supplémentaires et une légère restructuration et s'est exécuté avec d'excellents résultats sur jusqu'à 170 nœuds dans un superordinateur.

Python

Les implémentations MPI dans Python incluent : pyMPI , mpi4py, pypar, MYMPI et le sous-module MPI dans ScientificPython . pyMPI est remarquable car il s'agit d'une variante de l'interpréteur python, tandis que pypar, MYMPI et le module de ScientificPython sont des modules d'importation. Ils font le travail du codeur pour décider où MPI_Initappartient l'appel .

Récemment, les bibliothèques Boost C++ ont acquis Boost:MPI qui comprenait les liaisons Python MPI. Ceci est particulièrement utile pour mélanger C++ et Python. En octobre 2016, les liaisons Python de Boost:MPI ont toujours des bogues d'emballage non corrigés dans CentOS .

R

Les liaisons R de MPI incluent Rmpi et pbdMPI , où Rmpi ​​se concentre sur le parallélisme gestionnaire-travailleurs tandis que pbdMPI se concentre sur le parallélisme SPMD . Les deux implémentations prennent entièrement en charge Open MPI ou MPICH2 .

Exemple de programme

Voici un "Hello, World!" programme en MPI écrit en C. Dans cet exemple, nous envoyons un message "bonjour" à chaque processeur, le manipulons de manière triviale, renvoyons les résultats au processus principal et imprimons les messages.

/*
  "Hello World" MPI Test Program
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <mpi.h>

int main(int argc, char **argv)
{
    char buf[256];
    int my_rank, num_procs;

    /* Initialize the infrastructure necessary for communication */
    MPI_Init(&argc, &argv);

    /* Identify this process */
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    /* Find out how many total processes are active */
    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

    /* Until this point, all programs have been doing exactly the same.
       Here, we check the rank to distinguish the roles of the programs */
    if (my_rank == 0) {
        int other_rank;
        printf("We have %i processes.\n", num_procs);

        /* Send messages to all other processes */
        for (other_rank = 1; other_rank < num_procs; other_rank++)
        {
            sprintf(buf, "Hello %i!", other_rank);
            MPI_Send(buf, sizeof(buf), MPI_CHAR, other_rank,
                     0, MPI_COMM_WORLD);
        }

        /* Receive messages from all other process */
        for (other_rank = 1; other_rank < num_procs; other_rank++)
        {
            MPI_Recv(buf, sizeof(buf), MPI_CHAR, other_rank,
                     0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            printf("%s\n", buf);
        }

    } else {

        /* Receive message from process #0 */
        MPI_Recv(buf, sizeof(buf), MPI_CHAR, 0,
                 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        assert(memcmp(buf, "Hello ", 6) == 0);

        /* Send message to process #0 */
        sprintf(buf, "Process %i reporting for duty.", my_rank);
        MPI_Send(buf, sizeof(buf), MPI_CHAR, 0,
                 0, MPI_COMM_WORLD);

    }

    /* Tear down the communication infrastructure */
    MPI_Finalize();
    return 0;
}

Lorsqu'il est exécuté avec 4 processus, il doit produire la sortie suivante :

$ mpicc example.c && mpiexec -n 4 ./a.out
We have 4 processes.
Process 1 reporting for duty.
Process 2 reporting for duty.
Process 3 reporting for duty.

Voici mpiexecune commande utilisée pour exécuter l'exemple de programme avec 4 processus , dont chacun est une instance indépendante du programme au moment de l'exécution et les rangs attribués (c'est-à-dire les ID numériques) 0, 1, 2 et 3. Le nom mpiexecest recommandé par la norme MPI, bien que certaines implémentations fournissent une commande similaire sous le nom mpirun. Le MPI_COMM_WORLDest le communicateur qui se compose de tous les processus.

Un modèle de programmation à programme unique et données multiples ( SPMD ) est ainsi facilité, mais pas obligatoire; de nombreuses implémentations MPI permettent de démarrer plusieurs exécutables différents dans le même travail MPI. Chaque processus a son propre rang, le nombre total de processus dans le monde, et la capacité de communiquer entre eux soit par communication point à point (envoi/réception), soit par communication collective au sein du groupe. Il suffit que MPI fournisse un programme de style SPMD avec MPI_COMM_WORLD, son propre rang et la taille du monde pour permettre aux algorithmes de décider quoi faire. Dans des situations plus réalistes, les E/S sont gérées avec plus de soin que dans cet exemple. MPI ne précise pas comment les E/S standard (stdin, stdout, stderr) doivent fonctionner sur un système donné. Il fonctionne généralement comme prévu sur le processus de rang 0, et certaines implémentations capturent et canalisent également la sortie d'autres processus.

MPI utilise la notion de processus plutôt que de processeur. Les copies de programme sont mappées aux processeurs par le runtime MPI . En ce sens, la machine parallèle peut être mappée à un processeur physique ou à N processeurs, où N est le nombre de processeurs disponibles, ou même quelque chose entre les deux. Pour une accélération parallèle maximale, davantage de processeurs physiques sont utilisés. Cet exemple ajuste son comportement à la taille du monde N , il cherche donc également à s'adapter à la configuration d'exécution sans compilation pour chaque variation de taille, bien que les décisions d'exécution puissent varier en fonction de cette quantité absolue de simultanéité disponible.

Adoption MPI-2

L'adoption de MPI-1.2 a été universelle, en particulier dans l'informatique en grappe, mais l'acceptation de MPI-2.1 a été plus limitée. Les problèmes incluent :

  1. Les implémentations de MPI-2 incluent la gestion des E/S et des processus dynamiques, et la taille du middleware est considérablement plus importante. La plupart des sites qui utilisent des systèmes de planification par lots ne peuvent pas prendre en charge la gestion dynamique des processus. Les E/S parallèles du MPI-2 sont bien acceptées.
  2. De nombreux programmes MPI-1.2 ont été développés avant MPI-2. Les problèmes de portabilité ont initialement ralenti l'adoption, bien qu'un soutien plus large l'ait atténué.
  3. De nombreuses applications MPI-1.2 n'utilisent qu'un sous-ensemble de cette norme (16-25 fonctions) sans réel besoin de fonctionnalité MPI-2.

Futur

Certains aspects de l'avenir du MPI semblent solides ; d'autres moins. Le Forum MPI s'est réuni à nouveau en 2007 pour clarifier certains problèmes de MPI-2 et explorer les développements pour un éventuel MPI-3, ce qui a abouti aux versions MPI-3.0 (septembre 2012) et MPI-3.1 (juin 2015).

Les architectures évoluent, avec une plus grande concurrence interne ( multicœur ), un meilleur contrôle de la concurrence à granularité fine (threading, affinité) et davantage de niveaux de hiérarchie mémoire . Les programmes multithreads peuvent tirer parti de ces développements plus facilement que les applications monothread. Cela a déjà donné lieu à des normes distinctes et complémentaires pour le multitraitement symétrique , à savoir OpenMP . MPI-2 définit comment les implémentations conformes aux normes doivent traiter les problèmes multithread, mais n'exige pas que les implémentations soient multithread, ou même thread-safe. MPI-3 ajoute la possibilité d'utiliser le parallélisme à mémoire partagée au sein d'un nœud. Les implémentations de MPI telles que Adaptive MPI, Hybrid MPI, Fine-Grained MPI, MPC et autres offrent des extensions à la norme MPI qui répondent à différents défis dans MPI.

L'astrophysicien Jonathan Dursi a écrit un article d'opinion qualifiant le MPI d'obsolescent, soulignant les nouvelles technologies comme le langage Chapel , Unified Parallel C , Hadoop , Spark et Flink .

Voir également

Les références

Lectures complémentaires

Liens externes