Communiquer des données avec une valeur `count` proche de` INT_MAX`

Les API d’interface de passage de messages utilisent toujours int comme type pour les variables de count . Par exemple, le prototype de MPI_Send est:

 int MPI_Send(const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); 

Cela peut poser problème si le nombre d’éléments à envoyer ou à recevoir augmente, voire même au-delà de INT_MAX .

Bien sûr, le problème peut être résolu en diminuant la valeur du count :

  1. diviser un seul appel en plusieurs appels
  2. définir un agrégat (inutile) MPI_Datatype

Les deux approches sont de toute façon plus un hack qu’une vraie solution, surtout si elles sont mises en œuvre avec une simple heuristique. Ce que je voudrais demander, c’est donc:

Existe-t-il un meilleur langage pour traiter ce type de cas avec des appels MPI standard? Si non, quelqu’un connaît-il une bibliothèque d’encapsulation (solide) construite autour de MPI pour surmonter cette limitation?

Le forum MPI est extrêmement réticent à apporter des modifications majeures à l’API MPI afin d’introduire la prise en charge 64 bits. La raison en est à la fois de maintenir la compatibilité ascendante et de ne pas introduire de fonctionnalités rarement utilisées – cela semble être un processus presque aussi vigoureux que celui qui maintient Fortran 2xxx en général compatible avec les programmes FORTRAN IV préhistoriques.

Comme le montre clairement le ticket, la création d’un grand type de données pour contourner la limitation est en réalité considérée comme une solution peu astucieuse par beaucoup, même par William D. Gropp lui – même :

Tout d’abord, il est possible d’envoyer des données beaucoup plus volumineuses en créant simplement un type de données MPI approprié (cela pourrait être plus facile, mais c’est possible). Deuxièmement, l’envoi de données aussi volumineuses prendra quelques secondes (au moins!) Sur les plates-formes actuelles (8 Go seulement pour les entiers sur 4 octets et un compte de 2 Go). Cette opération ne devrait donc pas être une opération courante (et la surcharge liée à la création, la validation et la libération d’un fichier). type de données doit être négligeable).

Le fait que MPI-3.0 ait introduit le support officiel pour la construction de grands types de données (plus de 2 31 éléments) alors que la proposition de changer l’argument de comptage d’appels comme MPI_SEND en MPI_Count / INTEGER(KIND=MPI_COUNT_KIND) devait vous indiquer la voie à suivre. penser qui prévaut le MPI Forum. Même avant MPI-3.0, certaines implémentations utilisaient des tailles internes 64 bits (par exemple, Open MPI), tandis que d’autres avaient choisi de restr sur la bande passante 32 bits (par exemple, Intel MPI).

Je suis le principal développeur de BigMPI et j’ai co-écrit un article intitulé To INT_MAX … and beyond!: Explorant la prise en charge volumineuse dans MPI qui aborde ce sujet avec beaucoup plus de détails que l’espace ne le permet ici.

Si vous ne pouvez pas accéder librement à la liste de dissortingbution ACM, vous pouvez télécharger la pré – impression Argonne ou extraire le référentiel source papier .

Voici les points saillants de cet effort:

  • BigMPI est une interface de qualité relativement élevée avec MPI qui prend en charge les comptes d’entiers 64b (le type est techniquement MPI_Count mais MPI_Aint est utilisé en interne). Ironiquement, il n’utilise pas les fonctionnalités MPI-3 à grand nombre. En effet, BigMPI n’est pas complètement général, mais vise plutôt à prendre en charge les modèles d’utilisation les plus courants.

  • BigMPI a été conçu en partie pour être éducatif. Il utilise la licence ultra permissive de MIT pour permettre à quiconque de copier du code de celui-ci dans un autre projet, éventuellement avec des modifications pour répondre à un besoin imprévu.

  • Le dépassement de INT_MAX dans l’interface MPI-3 n’est pas un léger problème. C’est un code ISO C invalide. Le comportement de substitution des entiers signés est – contrairement aux entiers non signés – non défini. Le principal problème ne concerne donc pas MPI, mais le fait qu’un entier C ne puisse contenir de nombres supérieurs à INT_MAX. Le fait que l’argument count soit spécifié comme étant le type C int , par opposition à size_t , par exemple, est un sujet de débat. Avant de dire qu’il est évident que MPI aurait dû passer à size_t , vous devez comprendre l’historique de MPI et l’importance de la compatibilité ABI pour un sous-ensemble d’utilisateurs de MPI.

  • Même avec BigMPI ou des méthodes similaires basées sur un type de données, les implémentations peuvent comporter des bogues. Cela signifie que faire ce qui est conforme aux normes ne fonctionnera pas, car en interne, une implémentation MPI pourrait mal stocker quelque chose comme count*sizeof(type) dans une valeur 32b, ce qui peut déborder pour un compte valide tel qu’un milliard si sizeof(type) est huit, par exemple. Comme indiqué dans le document susmentionné, en plus de ces bogues – qui semblent être absents des versions récentes de MPICH et Open-MPI -, il existe des bogues dans les fonctions POSIX qui doivent être atténués.

  • La situation avec Fortran est plus compliquée. La taille d’entier par défaut de Fortran n’est pas spécifiée et les implémentations de MPI devraient, en théorie, respecter ce que le compilateur utilise. Cependant, ce n’est souvent pas le cas dans la pratique. Je crois que de nombreuses implémentations MPI sont cassées pour des comptes supérieurs à INT_MAX en raison de l’utilisation de C int interne. BigMPI n’a pas d’interface Fortran, bien que j’ai envie d’en écrire une un jour. Jusque-là, encouragez les développeurs MPI à faire ce qui est juste en transtypant Fortran INTEGER en C en interne.

Quoi qu’il en soit, je ne souhaite pas transcrire l’intégralité du contenu de notre document dans cet article, d’autant plus qu’il est disponible gratuitement, de même que le code source. Si vous pensez que cet article est inadéquat, veuillez commenter et j’essaierai d’en append d’autres plus tard.

Enfin, BigMPI est un code de recherche et je ne dirais pas qu’il est terminé (cependant, vous ne devez pas toucher le code inachevé). Les utilisateurs sont vivement encouragés à effectuer leurs propres tests d’exactitude de BigMPI et de la mise en œuvre de MPI avant leur utilisation en production.

Je ne suis au courant d’aucun emballage existant qui gère cela, mais vous pouvez écrire le vôtre. La plupart des implémentations MPI ont une couche supplémentaire destinée au profilage (PMPI). Vous pouvez utiliser cette couche à d’autres fins, dans ce cas, le fractionnement d’un message. Le fonctionnement de cette couche consiste à appeler la fonction MPI souhaitée et à appeler immédiatement la version PMPI de cette fonction. Vous pouvez écrire un wrapper de la version MPI qui divisera le message et appellera la version PMPI pour chacun. Voici un exemple extrêmement simple que j’ai écrit il y a longtemps pour scinder MPI_Bcast:

 #include  int MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm ) { /* This function is a simple attempt at automatically splitting MPI messages, in this case MPI_Bcast. By utilizing the profiling interface of MPI, this function is able to intercept a call to MPI_Bcast. Then, instead of the typical profiling, the message size is checked. If the message is larger than the maximum allowable size, it will be split into multiple messages, each of which will be sent individually. This function isnot intended for high performance, it is intended to add capability without requiring access to the source code of either the MPI implementation or the program using MPI. The intent is to comstack this as a shared library and preload this library to catch MPI calls. */ int result; int typesize; long totalsize; long maxsize=1; // Set the maximum size of a single message maxsize=(maxsize<<31)-1; // Get the size of the message to be sent MPI_Type_size(datatype, &typesize); totalsize=static_cast(typesize)*static_cast(count); // Check the size if (totalsize > maxsize) { // The message is too large, split it /* Ideally, this should be tailored to the system, possibly split into a minimum of equally sized messages that will fit into the maximum message size. However, this is a very simple implementation, and is focusing on proof of concept, not efficiency. */ int elementsPerChunk=maxsize/typesize; // Number of elements per chunk int remCount=count; // Remaining number of elements char *address=static_cast(buffer); // Starting address // Cast to char to perform arithmetic int nChunks=count/elementsPerChunk; // How many chunks to send if (count%elementsPerChunk!=0) nChunks++; // One more for any remaining elements int chunkCount; // Number of elements in current chunk // Send one chunk at a time for (int i=0;ielementsPerChunk) { chunkCount=elementsPerChunk; } else { chunkCount=remCount; } // Decrement the remaining elements remCount-=chunkCount; // Send the message chunk /* There is room for improvement here as well. One key concern is the return value. Normally, there would be a single return value for the entire operation. However, as the operation is split into multiple operations, each with its own return value, a decision must be made as to what to return. I have chosen to simply use the return value from the last call. This skips over some error checking but is not critical at present. */ result=PMPI_Bcast(static_cast(address),chunkCount,datatype,root,comm); // Update the address for the next chunk address+=chunkCount*typesize; } } else { // The message is small enough, just send as it is result=PMPI_Bcast(buffer,count,datatype,root,comm); } // Pass the return value back to the caller return result; } 

Vous pouvez écrire quelque chose de similaire pour MPI_Send (et MPI_Recv) et obtenir les fonctionnalités souhaitées. Mais s’il ne s’agit que d’un programme, vous feriez peut-être mieux de le modifier pour envoyer des morceaux.

Je ne l’ai pas utilisé moi-même, mais il existe une enveloppe appelée BigMPI pour vous aider. Vous devrez jeter un coup d’œil au fichier README de Github pour en savoir plus sur son utilisation, mais je pense qu’il résout le problème.