De quelles fonctionnalités les utilisateurs ont-ils besoin d'une interface MPI C ++?


28

La version 3.0 de la norme MPI a officiellement supprimé l'interface C ++ (elle était auparavant obsolète). Bien que les implémentations puissent toujours le prendre en charge, les fonctionnalités qui sont nouvelles dans MPI-3 n'ont pas d'interface C ++ définie dans la norme MPI. Voir http://blogs.cisco.com/performance/the-mpi-c-bindings-what-happened-and-why/ pour plus d'informations.

La motivation pour supprimer l'interface C ++ de MPI était qu'elle n'avait aucune valeur significative sur l'interface C. Il y avait très peu de différences autres que "s / _ / :: / g" et de nombreuses fonctionnalités auxquelles les utilisateurs C ++ sont habitués n'étaient pas utilisées (par exemple la détermination automatique de type via des modèles).

En tant que personne qui participe au Forum MPI et travaille avec un certain nombre de projets C ++ qui ont implémenté leur propre interface C ++ aux fonctions MPI C, je voudrais savoir quelles sont les caractéristiques souhaitables d'une interface C ++ à MPI. Bien que je ne m'engage à rien, je serais intéressé à voir la mise en œuvre d'une interface MPI C ++ autonome qui répond aux besoins de nombreux utilisateurs.

Et oui, je connais Boost :: MPI ( http://www.boost.org/doc/libs/1_54_0/doc/html/mpi.html ) mais il ne prend en charge que les fonctionnalités MPI-1 et le modèle de sérialisation serait extrêmement difficile à supporter pour RMA.

Une interface C ++ vers MPI que j'aime est celle d'Elemental ( https://github.com/poulson/Elemental/blob/master/src/core/imports/mpi.cpp ) donc peut-être que les gens peuvent fournir des avantages et des inconvénients qui approche. En particulier, je pense que MpiMap résout un problème essentiel.


Je ne pense pas que ce soit l'endroit approprié pour une telle question.
Jack Poulson

Pouvez-vous donner quelques raisons à cela? Beaucoup de questions MPI sur ce site me suggèrent que les gens ici sont prêts à répondre à cette question. De plus, 0,2 vote par minute suggère que d'autres personnes ne sont pas d'accord avec votre évaluation. Dans tous les cas, il serait plus utile de suggérer un autre endroit pour publier ceci si vous n'aimez pas le lieu actuel.
Jeff

La question est précieuse, et je pense qu'elle pourrait obtenir des réponses précieuses sur des listes de diffusion plus vastes en science informatique, si elle est là. (Peut-être NA-digest, SIAM-CSE, ou même un message public sur G +?) Cette question peut ne pas convenir à un site Stack Exchange car elle est subjective (voir scicomp.stackexchange.com/help/dont-ask ) . Tant que les réponses sont concrètes et se concentrent sur des cas d'utilisation spécifiques (sans répétitions ni chevauchements importants), je pense que cela vaut la peine de rester ouvert.
Geoff Oxberry

@Jeff: La question me semble un peu comme un sondage. Je ne conteste pas sa valeur, mais je ne vois pas qu'il y ait une seule réponse acceptée. Une telle question serait-elle hors du commun pour le forum MPI?
Jack Poulson

@JackPoulson Je ne veux pas savoir ce que les implémentateurs pensent être la bonne réponse; Je veux savoir ce dont les scientifiques en informatique ont besoin. À cet égard, la question a des réponses objectives. Il n'y a pas de bonne réponse, mais cela ne signifie pas qu'il s'agit d'une situation subjective.
Jeff

Réponses:


17

Permettez-moi d'abord de répondre à la raison pour laquelle je pense que les interfaces C ++ vers MPI n'ont généralement pas été un succès excessif, après avoir réfléchi au problème pendant longtemps en essayant de décider si nous devons simplement utiliser les liaisons C standard de MPI ou construire sur quelque chose à un niveau supérieur. :

Lorsque vous regardez les codes MPI du monde réel (par exemple, PETSc, ou dans mon cas deal.II), on constate que peut-être de manière surprenante, le nombre d'appels MPI n'est pas vraiment très important. Par exemple, dans les 500 000 lignes de deal.II, il n'y a que ~ 100 appels MPI. Une conséquence de cela est que la douleur liée à l'utilisation d'interfaces de niveau inférieur telles que les liaisons MPI C, n'est pas trop grande. Inversement, on ne gagnerait pas beaucoup en utilisant des interfaces de niveau supérieur.

Ma deuxième observation est que de nombreux systèmes ont plusieurs bibliothèques MPI installées (différentes implémentations MPI ou différentes versions). Cela pose une difficulté importante si vous voulez utiliser, par exemple, boost :: mpi qui ne se compose pas uniquement de fichiers d'en-tête: soit il doit y avoir plusieurs installations de ce paquet également, soit il faut le construire dans le cadre de la projet qui utilise boost :: mpi (mais c'est encore un problème en soi, étant donné que boost utilise son propre système de construction, qui ne ressemble à rien d'autre).

Je pense donc que tout cela a comploté contre la récolte actuelle d'interfaces C ++ vers MPI: les anciennes liaisons MPI C ++ n'offraient aucun avantage, et les packages externes avaient des difficultés avec le monde réel.

Cela dit, voici ce que je pense être les fonctionnalités de tueur que j'aimerais avoir d'une interface de niveau supérieur:

  • Il doit être générique. Décider de spécifier le type de données d'une variable n'est décidément pas du genre C ++. Bien sûr, cela conduit également à des erreurs. La classe MpiMap d'Elemental serait déjà une bonne première étape (bien que je ne puisse pas comprendre pourquoi la MpiMap::typevariable n'est pas une constante statique, afin qu'elle soit accessible sans créer d'objet).

  • Il devrait avoir des installations pour diffuser des types de données arbitraires.

  • Les opérations qui nécessitent un MPI_Opargument (par exemple, des réductions) devraient bien s'intégrer à l' std::functioninterface de C ++ , de sorte qu'il est facile de simplement passer un pointeur de fonction (ou un lambda!) Plutôt que d'avoir à enregistrer maladroitement quelque chose.

boost :: mpi satisfait en fait tout cela. Je pense que s'il s'agissait d'une bibliothèque uniquement en-tête, elle serait beaucoup plus populaire dans la pratique. Il serait également utile de prendre en charge les fonctions post-MPI 1.0, mais soyons honnêtes: cela couvre la plupart de ce dont nous avons besoin la plupart du temps.


L'un des problèmes avec la sérialisation dans Boost :: MPI est qu'elle ne fonctionne pas avec un côté (alias RMA). Pensez-vous qu'il sera possible de créer des types de données MPI pour les objets C ++ qui intéressent les utilisateurs? Bien sûr, en théorie, tout devrait être soutenu, mais je préfère commencer par un objectif plus pragmatique.
Jeff

Je pense que c'est une erreur de penser que le type de données sérialisé peut jamais fonctionner avec des communications unilatérales. Cela suppose que la sérialisation implique uniquement le regroupement des données dans une chaîne et, de l'autre côté, le décompactage à nouveau. Mais les fonctions de sérialisation peuvent faire beaucoup plus (par exemple, suivre les pointeurs vers d'autres objets, compter les octets qui ont été sérialisés, etc.) que ce à quoi on peut s'attendre si vous ne pouvez rien exécuter sur l'hôte de destination. Mon point de vue est que la sérialisation de style C ++ et la communication unilatérale ne sont tout simplement pas un démarreur. Je pense que personne ne devrait s'attendre à ce que cela fonctionne, donc il ne manquerait pas grand chose.
Wolfgang Bangerth

Salut Wolfgang, vous avez raison de dire que MpiMap serait plus élégant s'il utilisait une variable de membre const statique. J'ai réorganisé l'implémentation: github.com/poulson/Elemental/commit/…
Jack Poulson

Oui, beaucoup mieux :-)
Wolfgang Bangerth

+1 sur pas beaucoup d'appels mpi @WolfgangBangerth. Fondamentalement, mpi est censé accélérer les calculs, vous voulez minimiser les appels mpi car ils vous coûtent!
Charles

6

Pour lancer le bal, voici deux de mes besoins:

  • L'interface doit être en mesure d'éliminer les arguments redondants ou inutiles, par exemple MPI_IN_PLACE.
  • L'interface doit détecter automatiquement les types de données intégrés comme MpiMap d'Elemental.
  • Si / chaque fois que cela est possible, des types de données définis par l'utilisateur doivent être construits pour les classes.

5

Ma liste sans ordre de préférence particulier. L'interface doit:

  • être en-tête uniquement, sans aucune dépendance mais <mpi.h> , et la bibliothèque standard,
  • être générique et extensible,
  • être non bloquant uniquement (si vous voulez bloquer, puis bloquer explicitement, pas par défaut),
  • permettre le chaînage basé sur la continuation des opérations non bloquantes,
  • prendre en charge la sérialisation extensible et efficace (Boost.Fusion comme, de sorte qu'il fonctionne avec RMA),
  • avoir une pénalité d'abstraction nulle (c'est-à-dire être au moins aussi rapide que l'interface C),
  • être en sécurité (le destructeur d'un avenir non prêt est appelé? -> std :: terminate!),
  • avoir un fort DEBUG mode avec des tonnes d'assertions,
  • extrêmement sûr pour le type (plus d'ints / void * pour tout, diable je veux que les tags soient des types!),
  • cela devrait fonctionner avec les lambdas (par exemple tous réduire + lambda),
  • utiliser les exceptions de manière cohérente comme mécanisme de rapport et de traitement des erreurs (plus de codes d'erreur! plus d'arguments de sortie de fonction!),
  • MPI-IO devrait offrir une interface d'E / S non bloquante dans le style de Boost.AFIO,
  • et il suffit de suivre les bonnes pratiques modernes de conception d'interface C ++ (définir des types réguliers, des fonctions non-amis non-amis, bien jouer avec la sémantique de déplacement, prendre en charge les opérations de plage, ...)

Extras:

  • permettez-moi de choisir l'exécuteur de l'environnement MPI, c'est-à-dire le pool de threads qu'il utilise. À l'heure actuelle, vous pouvez avoir des applications avec un mélange d'OpenMP, MPI, CUDA et TBB ... le tout en même temps, où chaque exécution pense qu'il est propriétaire de l'environnement et demande donc au système d'exploitation des threads chaque fois qu'il le souhaite il. Sérieusement?

  • utilisez la convention de dénomination STL (et Boost). Pourquoi? Chaque programmeur C ++ le sait.

Je veux écrire du code comme ceci:

auto buffer = some_t{no_ranks};
auto future = gather(comm, root(comm), my_offsets, buffer)
              .then([&](){
                /* when the gather is finished, this lambda will 
                   execute at the root node, and perform an expensive operation
                   there asynchronously (compute data required for load 
                   redistribution) whose result is broadcasted to the rest 
                   of the communicator */
                return broadcast(comm, root(comm), buffer);
              }).then([&]() {
                /* when broadcast is finished, this lambda executes 
                   on all processes in the communicator, performing an expensive
                   operation asynchronously (redistribute the load, 
                   maybe using non-blocking point-to-point communication) */
                 return do_something_with(buffer);
              }).then([&](auto result) {
                 /* finally perform a reduction on the result to check
                    everything went fine */
                 return all_reduce(comm, root(comm), result, 
                                  [](auto acc, auto v) { return acc && v; }); 
              }).then([&](auto result) {
                  /* check the result at every process */
                  if (result) { return; /* we are done */ }
                  else {
                    root_only([](){ write_some_error_log(); });
                    throw some_exception;
                  }
              });

/* Here nothing has happened yet! */

/* ... lots and lots of unrelated code that can execute concurrently 
   and overlaps with communication ... */

/* When we now call future.get() we will block 
   on the whole chain (which might have finished by then!).
*/

future.get();

Imaginez comment on pourrait enchaîner toutes ces opérations en utilisant les MPI_C request. Vous devrez tester à plusieurs (ou à chaque étape) intermédiaire à travers un tas de code non lié pour voir si vous pouvez faire avancer votre chaîne sans bloquer .


Il s'agit d'une liste intense d'exigences. Certains d'entre eux sont impossibles à toutes fins pratiques (par exemple, soutenir les lambdas dans les réductions). Cependant, dans l'ensemble, je pense que c'est le genre de chose que la communauté MPI devrait aspirer à soutenir.
Jeff

En ce qui concerne les threads et l'environnement d'exécution, MPI n'utilise ni thread ni thread OS (POSIX, Windows ou Solaris, selon l'OS) en interne. Je ne suis pas sûr de bien comprendre l'exigence ici.
Jeff

Le problème est que MPI peut demander des threads arbitraires au système d'exploitation. Mon application dispose d'un pool de threads et j'aimerais que MPI demande ces threads à partir de mon pool de threads. Ce n'est actuellement pas possible (et généralement pas un problème), sauf si vous avez une application utilisant OpenMP, TBB et MPI, chacune avec ses propres pools de threads, chacun avec 4x nombre de cœurs.
gnzlbg

1
MPI peut mais n'utilise généralement pas les threads du système d'exploitation en interne. Dans tous les cas que je connais (MPICH (2), MVAPICH2, OpenMPI, CrayMPI), seule une option d'exécution fournie par l'utilisateur provoque cela, c'est-à-dire que la valeur par défaut est qu'elle ne le fait pas. Blue Gene / Q MPI est une exception mais sous une forme telle qu'elle n'est pas pertinente pour cette discussion.
Jeff

Merci @Jeff! Pourriez-vous expliquer comment MPI gère plusieurs appels non bloquants tout en utilisant un seul thread? Utilise-t-il des coroutines / fils verts / fibres?
gnzlbg

2

Personnellement, cela ne me dérange pas vraiment d'appeler de longues fonctions de style C pour la raison exacte mentionnée par Wolfgang; il y a vraiment peu d'endroits où vous devez les appeler et même alors, ils sont presque toujours enveloppés par un code de niveau supérieur.

Les seules choses qui me dérangent vraiment avec les MPI de style C sont les types de données personnalisés et, dans une moindre mesure, les opérations personnalisées (car je les utilise moins souvent). En ce qui concerne les types de données personnalisés, je dirais qu'une bonne interface C ++ devrait être capable de prendre en charge un moyen générique et efficace de gérer cela, très probablement par le biais de la sérialisation. C’est bien sûr l’itinéraire qui boost.mpia été emprunté, qui si vous faites attention , beaucoup de temps.

En ce qui concerne boost.mpiles dépendances supplémentaires (en particulier boost.serializationqui n'est pas uniquement en-tête), j'ai récemment rencontré une bibliothèque de sérialisation C ++ uniquement en-tête appelée cereal qui semble prometteuse; étant donné qu'il nécessite un compilateur compatible C ++ 11. Il pourrait être utile de l'examiner et de l'utiliser comme base pour quelque chose de similaire à boost.mpi.


Notez que je ne cherchais pas nécessairement quelque chose à mettre dans la norme MPI. Je suis tout à fait d'accord pour dire que MPI devrait presque toujours "être enveloppé par un code de niveau supérieur", alors ce que je me demande, à quoi ressemble ce code de niveau supérieur? Elemental a une belle approche, mais est-ce le meilleur pour tous les cas? Si l'on voulait avoir une interface C ++ vers MPI qui essayait de faire plaisir à un très grand nombre de personnes, à quoi cela ressemblerait-il?
Jeff

@Jeff. Pour moi: 1. J'aime pouvoir envoyer facilement des types de données personnalisés. 2. J'aime pouvoir effectuer des réductions avec des opérations personnalisées en toute simplicité. Je pense aussi que 1 je me sens plus important / utile que 2
GradGuy

Je ne vois pas comment C ++ fait quelque chose de magique par rapport à (2). Qu'imaginez-vous ici?
Jeff

@Jeff Je pensais à quelque chose dans le sens de la thrustréduction: docs.thrust.googlecode.com/hg/group__reductions.html
GradGuy

-1

Le projet github easyLambda fournit une interface de haut niveau à MPI avec C ++ 14.

Je pense que le projet a des objectifs similaires et il donnera une idée des choses qui peuvent être et sont faites dans ce domaine en utilisant le C ++ moderne. Guider d'autres efforts ainsi que easyLambda lui-même.

Les repères initiaux sur les performances et les lignes de code ont montré des résultats prometteurs.

entrez la description de l'image ici

Voici une brève description des fonctionnalités et de l'interface qu'il fournit.

L'interface est basée sur la programmation de flux de données et les opérations de listes fonctionnelles qui fournissent un parallélisme inhérent. Le parallélisme s'exprime comme la propriété d'une tâche. L'allocation de processus et la distribution de données pour la tâche peuvent être demandées avec une propriété .prll (). Il y a un bon nombre d'exemples dans la page Web et le code-référentiel qui incluent LAMMPS dynamique moléculaire traitement post, solution explicite de différence finie à l' équation de la chaleur, la régression logistique , etc. Par exemple , le problème de la diffusion de la chaleur discuté dans l'article HPC est en train de mourir ... peut être exprimé en ~ 20 lignes de code.

J'espère qu'il est bon de donner des liens plutôt que d'ajouter plus de détails et d'exemples de codes ici.

Disclamer: Je suis l'auteur de la bibliothèque. Je crois que je ne fais aucun mal en espérant obtenir une rétroaction constructive sur l'interface actuelle d'easyLambda qui pourrait être avantageuse pour easyLambda et tout autre projet poursuivant des objectifs similaires.


La question dit " Nous recherchons des réponses longues qui fournissent des explications et du contexte. Ne donnez pas seulement une réponse en une seule ligne; expliquez pourquoi votre réponse est correcte, idéalement avec des citations. Les réponses qui ne comprennent pas d'explications peuvent être supprimées . ". Pourquoi pensez-vous que votre réponse est suffisamment complète pour correspondre à cette description?
nicoguaro

Je pointe vers un projet qui fournit une interface similaire à ce que demande l'OP. Je peux donner des détails sur la motivation et les caractéristiques du projet dans la réponse elle-même et laisser le PO et les autres lire et suggérer ce qu'ils en pensent. Cependant, j'ai choisi de ne donner que des liens. Je comprends ton point de vue. Permettez-moi d'ajouter du texte avec des références à la réponse.
Utkarsh Bhardwaj

@UtkarshBhardwaj: Quelques commentaires: (1) Merci d'avoir écrit une bibliothèque qui interface C ++ avec MPI. C'est une entreprise importante et il semble que vous y ayez consacré beaucoup de travail. (2) En parcourant rapidement les documents (encore une fois, beau travail), ce qui ressort, c'est les longues chaînes de commandes de méthodes utilisées, qui semblent stylistiquement ... pénibles à déboguer, même si vous les avez bien formatées. (3) Les abstractions supposent un paradigme fonctionnel, qui semble utile pour les tâches de type réduction de carte, mais en tant que personne qui programme en MPI, je ne veux pas retravailler mes algorithmes et m'éloigner trop des interfaces que je connais.
Geoff Oxberry

(4) Je ne vois aucun communicateur dans l'exemple, ce qui m'amène à soupçonner que vous utilisez MPI_COMM_WORLD pour tout, et limite le potentiel de votre bibliothèque. (5) Les abstractions semblent s'appuyer sur les abstractions MPI et pourraient avoir un backend différent. (6) Sur la base de (3) - (5), je ne pense pas que cette bibliothèque soit une interface MPI, et je pense que ce commentaire est hors sujet en conséquence.
Geoff Oxberry

@Geoff merci pour les précieux commentaires, merci beaucoup. Réponse à des points spécifiques: 2) Le chaînage est parfois appelé ExpressionBuilder . C'est une façon courante d'exprimer la composition dans un style fonctionnel. Il n'est pas nécessaire d'écrire dans ce style en ezl. Il est possible d'écrire d'abord des unités individuelles puis de les composer, vérifiez [l'exemple] ( goo.gl/YzaL0k ). 3) Je sais qu'il est difficile de passer du contrôle-flux & impératif au flux de données & fonctionnel. Chacun a ses avantages et ses inconvénients. Cependant, je crois que ce dernier doit être exploré davantage pour connaître sa véritable efficacité.
Utkarsh Bhardwaj
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.