Déblocage d'une communication point à point standard dans un programme MPI

L'exécution d'un programme faisant appel à la fonction MPI_Send suivie de MPI_Recv peut rester bloquée sur MPI_Send quant au moins deux processus s'échangent des messages de tailles importantes (variable selon le nombre de processus sur Ada, >2048 octets sur Turing).

Ce problème est dû à l'utilisation du mode d'envoi MPI dit standard (MPI_Send). Ce mode autorise l'implémentation MPI à choisir la façon d'envoyer les messages. En général (et sur toutes les machines de l'IDRIS), les petits messages sont recopiés dans un espace mémoire temporaire avant d'être expédiés. Tandis que les gros messages sont envoyés en mode synchrone. Ce mode synchrone implique que pour que le message parte (càd pour que l'appel MPI_Send puisse se terminer), il faut que la réception de ce message ait été postée (càd que l'appel à MPI_Recv ait été effectué).

Des situations de blocage peuvent alors apparaître. Cela peut arriver, par exemple, pour le schéma de communication suivant :

       processus    0                               1
                    send(vers 1)                    send(vers 0)
                    recv(  de 1)                    recv(  de 0)

Ce schéma de communication n'est pas du tout conseillé et est d'ailleurs considéré comme erroné par la norme MPI. Heureusement, les solutions ne manquent pas mais elles nécessitent toutes une légère modification de votre source :

  • Remplacer MPI_SEND/MPI_RECV par MPI_SENDRECV :
             processus    0                               1
                          sendrecv(vers 1, de 1)          sendrecv(vers 0, de 0)
  • Remplacer MPI_SEND par MPI_BSEND (attention : il faut allouer un buffer spécifique) :
             processus    0                               1
                          bsend(vers 1)                   bsend(vers 0)
                          recv(   de 1)                   recv(   de 0)
  • Pour un des processus, inverser MPI_SEND et MPI_RECV :
             processus    0                               1
                          send(vers 1)                    recv(  de 0)
                          recv(  de 1)                    send(vers 0)
  • Utiliser les fonctions non-bloquantes MPI_ISEND et MPI_IRECV suivies d'un appel à MPI_WAITALL :
             processus    0                               1
                          isend(vers 1)                   isend(vers 0)
                          irecv(  de 1)                   irecv(  de 0)
                          waitall()                       waitall()

Selon la machine, il est possible de modifier la valeur à partir de laquelle les messages sont envoyés en mode synchrone :

  • sur Turing : la variable d'environnement PAMID_EAGER permet de fixer la taille de message à en octets partir de laquelle les envois seront synchrones (2049 par défaut),
  • sur Ada : la variable d'environnement MP_EAGER_LIMIT permet de fixer la taille de message à partir de laquelle les envois seront synchrones.

Si vous voulez vous assurer que votre application ne risque pas de souffrir de ce problème, il est conseillé de la tester en mettant ces variables d'environnement à 0 afin de forcer le mode synchrone pour tous les envois standards. Si tout se passe bien (pas de blocage), votre application ne devrait pas avoir ce soucis (sauf si vous variez vos schémas de communication).