Prise en charge de l'accélération multiprocessus et multithread
Cette page décrit dans quelle mesure qiskit-addon-sqd prend en charge l'accélération multithread et multiprocessus, ainsi que les hypothèses sur lesquelles un développeur en calcul haute performance (HPC) peut s'appuyer lors de l'intégration de ce package dans une charge de travail accélérée.
L'hypothèse du traitement monothread
Sauf indication contraire, les API contenues dans ce package sont destinées à être appelées à partir d'un seul thread. La réentrance des API de haut niveau fournies par ce paquet n'est pas garantie; les utilisateurs finaux ne doivent donc pas les appeler à partir d'un thread autre que le thread principal.
Exécution collective de plusieurs processus
Ce package prend en charge l’accélération collective multiprocessus selon le modèle « single-program, multiple-data » (SPMD), dans lequel l’ensemble du programme est lancé sous la forme de plusieurs processus isolés qui s’exécutent avec une synchronisation globale explicite et une communication entre eux (par exemple, mpirun -n 128 python my_program.py). Comme le modèle SPMD s'intègre parfaitement aux planificateurs de tâches et autres logiciels parallèles et s'adapte à un grand nombre de processus, il constitue le modèle recommandé pour les charges de travail à haute performance et à grande échelle, et fait l'objet de cette page.
Bien que ce package soit conçu pour prendre en charge différents backends d'exécution collective, son implémentation actuelle est destinée à MPI, l'API standard de passage de messages pour les systèmes HPC. Quelle que soit la mise en œuvre, ce package part du principe qu'un seul thread contrôle chaque processus. Dans le cas du MPI, cela correspond à MPI_THREAD_FUNNELED ou moins.
Si une fonction prend en charge l'exécution collective, sa documentation doit le préciser. Si la documentation ne fait pas mention d'une exécution collective, la fonction ne présente pas de sémantique collective et doit être appelée uniquement depuis le processus de contrôle.
La valeur de retour spécifique et la sémantique de synchronisation d'une fonction collective sont documentées avec la fonction elle-même. De manière générale, cette documentation devrait préciser clairement :
- Que la fonction soit destinée à être appelée de manière indépendante par chaque processus sur ses propres données locales, ou collectivement par l'ensemble des processus.
- Comment ses arguments doivent être cohérents d'un processus à l'autre.
- La manière dont sa valeur de retour est transmise : si le résultat n’existe que dans le processus de contrôle, si tous les processus reçoivent la même valeur, ou si chaque processus reçoit un descripteur pointant vers une partie locale d’une structure de données distribuée.
Une seule fonction permet actuellement d'être appelée simultanément par tous les processus : diagonalize_fermionic_hamiltonian(). Lorsqu'elle est appelée de manière collective, l'étape de résolution des valeurs propres est celle à laquelle tous les processus participent et apportent leur contribution; une implémentation de ce résolveur peut donc utiliser l'ensemble des processus. Les autres éléments de la boucle de configuration-récupération ne font pas l'objet d'une implémentation distribuée et s'exécutent uniquement au niveau du processus de contrôle (rang 0).
Certaines implémentations existantes de solveurs de valeurs propres exigent en revanche que le programme appelant s'exécute en dehors d'un environnement MPI/SPMD, car elles lancent et gèrent en interne leurs propres processus parallèles, par exemple en appelant mpirun au nom de l'utilisateur. Ce mode est pratique pour le travail interactif et sur bloc-notes, et il continue d'être pris en charge; ses exigences vis-à-vis du programme appelant sont décrites dans la documentation de l'API de la fonction diagonalize_fermionic_hamiltonian() .
Gestion des erreurs dans un contexte multiprocessus
Une fonction appelée simultanément par tous les processus ne doit pas déclencher d'exception ni interrompre un seul processus, car cela laisserait les processus restants dans une situation de blocage ou dans un état incohérent. Au contraire, la gestion des erreurs suit une sémantique de type « fail-stop » pour le contexte d'exécution dans son ensemble : en cas d'erreur, l'implémentation doit être prête à interrompre l'ensemble du contexte d'exécution de manière globale (par exemple, en utilisant MPI_Abort).
L'API ne peut garantir ni la notification coordonnée des erreurs ni la transmission collective des exceptions entre les processus, car les implémentations MPI n'offrent pas de telles garanties. Une implémentation pourrait en outre tenter de rendre une erreur visible à tous les processus participants — par exemple, en faisant en sorte que chaque processus lève une exception —, mais cela ne peut être assuré qu’au mieux et ne doit pas être considéré comme une garantie de correctitude ou de récupération.
Il s'agit là de propriétés qu'une implémentation collective est autorisée à présenter, et non de garanties concernant une implémentation particulière. Dans ce package, la seule étape collective est le calcul des valeurs propres (voir la section précédente); son implémentation par défaut n'étant pas distribuée, ces considérations s'appliquent à un calculateur de valeurs propres collectif personnalisé fourni par l'utilisateur.