Projets intermédiaires¶
Cinq projets à faire pendant les semestres 3 et 4, chacun recoupant une UE. Ils nécessitent, pour certains, un accès à plusieurs machines — voir Accès aux machines.
Charge totale : environ 140 heures. Ne les faites pas tous : voir Comment choisir.
P6 · Le solveur de Poisson distribué en MPI¶
⏱ 35 h · ★★★★ · Recoupe PRPA23
Pourquoi celui-là¶
C'est le projet MPI canonique, et c'est à peu de choses près ce que fait le benchmark HPCG — celui qui sert de second classement officiel aux supercalculateurs. Le construire soi-même donne une compréhension de HPCG que personne n'a en le lançant simplement.
Le sujet¶
Résoudre \(-\Delta u = f\) sur un carré avec conditions de Dirichlet, par la méthode du gradient conjugué, sur une grille distribuée en damier.
Les étapes techniques :
- Décomposition cartésienne avec
MPI_Cart_createetMPI_Cart_shift. - Échange des quatre bords par types dérivés — les bords verticaux ne sont pas
contigus, c'est exactement le cas d'usage de
MPI_Type_vector. - Le gradient conjugué, avec ses deux produits scalaires globaux par itération,
donc deux
MPI_Allreduce. - Version bloquante (
MPI_Sendrecv), puis non bloquante, puis avec recouvrement calcul-communication : lancer les échanges, calculer l'intérieur du domaine, attendre, calculer les bords.
Livrables¶
- Le code, dans un dépôt avec CMake et intégration continue.
- La validation numérique : convergence vers la solution analytique pour un \(f\) choisi, avec courbe d'erreur en fonction du raffinement, et vérification de l'ordre du schéma.
- Le passage à l'échelle forte (taille fixe) et faible (taille proportionnelle), jusqu'au maximum de nœuds accessibles. Deux courbes distinctes, avec la ligne idéale.
- Un modèle de coût analytique du temps par itération :
où \(T_{\text{calcul}}\) dépend du nombre de points locaux, \(T_{\text{échange}}\) du périmètre du sous-domaine, et \(T_{\text{allreduce}}\) de \(\log P\). Confronter ce modèle aux mesures : c'est la partie la plus instructive du projet, parce qu'elle vous permet de prédire où l'efficacité tombera. 5. Une trace Score-P ou Extrae à 16 rangs, avec le chemin critique identifié. 6. Un rapport de huit pages.
L'observation à faire¶
En strong scaling, l'efficacité chute à partir d'un certain nombre de rangs. La
cause est identifiable : le rapport surface/volume du sous-domaine se dégrade (le
calcul décroît en \(1/P\) mais les communications en \(1/\sqrt{P}\)), et le coût de
l'Allreduce en \(\log P\) devient dominant. Savoir montrer cela avec un modèle et
des mesures est le cœur du projet.
Extensions¶
- +15 h : ajouter un préconditionneur de Jacobi puis un Gauss-Seidel par blocs. Mesurer le compromis entre le nombre d'itérations (qui baisse) et le coût par itération (qui monte). C'est l'arbitrage fondamental des méthodes itératives.
- +10 h : ajouter la sortie en Parallel HDF5 et mesurer les quatre stratégies d'écriture. Cela recoupe SYFP24.
P7 · Le cluster maison, du métal au HPL¶
⏱ 35 h · ★★★★ · Recoupe LOCL24
Pourquoi celui-là¶
Parce que c'est littéralement l'épreuve d'une Student Cluster Competition, et parce que le contenu est impossible à acquérir en lisant.
Le matériel¶
Par ordre de préférence :
- Du vrai matériel : quelques machines de récupération, ou des cartes de type Raspberry Pi. Le plus formateur, parce qu'on rencontre les vrais problèmes (PXE, IPMI, câblage, chaleur).
- Des instances cloud à la demande, détruites après usage. Coût modéré si l'on est discipliné.
- Des machines virtuelles sur un seul hôte. Suffisant pour tout sauf les mesures de performance réseau.
Le sujet, en sept étapes¶
- Conception : un document d'architecture de trois pages. Nombre de nœuds, rôles, réseau, stockage, authentification, budget électrique estimé. Chaque choix justifié.
- Déploiement automatisé : PXE et Kickstart sur du métal, ou images et Ansible sinon. Contrainte : la reconstruction complète doit être scriptée et prendre moins d'une heure.
- Services : NTP, résolution de noms, utilisateurs synchronisés, NFS, Slurm avec comptabilité.
- Pile logicielle : compilateur, MPI, BLAS, avec
lmodou Spack. - Surveillance : Prometheus et Grafana, avec au moins une alerte.
- Validation par benchmarks : OSU Micro-Benchmarks pour le réseau, STREAM pour
la mémoire, HPL pour le calcul. Régler HPL (paramètres
N,NB,P,Q) et comparer au pic théorique. - Documentation d'exploitation : un guide utilisateur d'une page, un guide administrateur de trois pages, une procédure de reconstruction après panne.
Critère de réussite¶
Détruire complètement le cluster, le reconstruire depuis vos scripts, et retrouver le même chiffre HPL à 5 % près. C'est le test qui valide tout le projet.
Le chiffre à obtenir¶
Un HPL à 60-70 % du pic théorique sur un cluster mal réglé, 85-90 % sur un cluster
bien réglé. L'écart vient du réglage : taille de bloc NB, grille P × Q,
placement des rangs, choix de la bibliothèque BLAS, réseau correctement utilisé.
Liens : LOCL24, Build et environnement, Anatomie d'une compétition.
P8 · L'expertise de performance d'un code réel¶
⏱ 30 h · ★★★★ · Recoupe PRSA24
Pourquoi celui-là¶
Parce que c'est le métier. Un ingénieur HPC en centre de calcul passe une partie de son temps à diagnostiquer les codes d'utilisateurs qui se plaignent que « la machine est lente ».
Le choix du code¶
Prenez un code que vous n'avez pas écrit, libre, réel et non trivial.
| Code | Domaine | Langage | Intérêt |
|---|---|---|---|
| WRF | Météorologie | Fortran | Annoncé pour la SCC de SC26 |
| MFC | Écoulements multiphasiques | Fortran | Annoncé pour la SCC de SC26 |
| GROMACS | Dynamique moléculaire | C++, CUDA | Très optimisé : le défi est de comprendre pourquoi il est rapide |
| LAMMPS | Dynamique moléculaire | C++ | Modulaire, facile à instrumenter |
| OpenFOAM | Mécanique des fluides | C++ | Mauvais en E-S : beaucoup à gagner |
| Code_Saturne | Mécanique des fluides | C, Fortran | Français, EDF, bien documenté |
| HPCG | Benchmark | C++ | Petit, lisible, représentatif |
Les deux premières lignes méritent attention : travailler sur WRF ou MFC en projet d'UE, c'est préparer la compétition en étant noté pour cela.
Les huit parties du rapport¶
- Description du code, des équations, et du cas test représentatif.
- Construction reproductible : la recette exacte, en Spack ou en conteneur, avec toutes les versions consignées.
- Mesure de référence : temps total, répartition calcul / communication / E-S, trois répétitions avec variance.
- Modèle de performance : intensité arithmétique, roofline, borne théorique. Avant de profiler. C'est la prédiction.
- Profil :
perfou VTune pour les points chauds, mpiP ou Score-P pour MPI, Darshan pour les E-S. Confronter au modèle. - Passage à l'échelle : strong et weak, avec identification du point où l'efficacité tombe sous 70 % et explication de la cause.
- Améliorations : au moins trois, chacune avec hypothèse chiffrée, implémentation, mesure, et écart entre prédiction et résultat. Les améliorations qui échouent sont aussi intéressantes, à condition d'expliquer pourquoi.
- Visualisation des résultats scientifiques, pour vérifier que les améliorations n'ont rien cassé physiquement.
Critère de réussite¶
Le rapport doit être utilisable par quelqu'un qui veut faire tourner ce code sur une machine similaire : il doit contenir des recommandations opérationnelles, et pas seulement des mesures.
Le bonus¶
Si le code est libre et que votre amélioration est propre, proposez-la en amont. Un correctif accepté dans un code de production est la meilleure ligne possible dans un CV de jeune ingénieur HPC.
P9 · Le portage sur GPU d'un noyau, cinq manières¶
⏱ 25 h · ★★★★ · Recoupe PGPU35
Pourquoi celui-là¶
Parce que le portage sur accélérateur est l'activité la plus demandée du domaine, et parce que personne ne documente honnêtement le compromis performance/effort entre les différentes approches de portabilité.
Le sujet¶
Prendre un noyau non trivial et l'implémenter cinq fois :
- CUDA natif ;
- HIP (obtenu par
hipifypuis ajusté) ; - SYCL ou oneAPI DPC++ ;
- Kokkos ;
- OpenMP target.
Choix du noyau : un stencil 3D à 7 points, un SpMV en CSR, ou le noyau dominant d'une mini-application du projet Exascale (LULESH, miniFE, XSBench, BabelStream).
Livrables¶
- Les cinq implémentations, avec une validation numérique commune.
- Un tableau performance/effort : GFLOPS ou bande passante atteinte, nombre de lignes de code, temps de développement réellement chronométré, et une note subjective de lisibilité.
- Le même tableau sur une seconde architecture si vous y avez accès (AMD, Intel, ou CPU multicœur) : c'est là que la portabilité se juge.
- Un profil Nsight Compute de la version la plus rapide et de la plus lente, avec l'explication de l'écart.
- Une recommandation argumentée : pour un code neuf, pour un gros code existant en C++, pour un gros code existant en Fortran.
Pourquoi c'est rare et précieux¶
La littérature sur la portabilité de performance est abondante en promesses et pauvre en mesures comparatives honnêtes qui incluent l'effort de développement. Un travail sérieux là-dessus intéresse réellement du monde, et c'est un excellent sujet de RDEV36.
Liens : GPU et hétérogène, le cours GPU de cette bibliothèque.
P10 · La bibliothèque de threads utilisateur¶
⏱ 15 h · ★★★★ · Recoupe PRCV24, module MPPT24
Pourquoi celui-là¶
Parce que c'est le mini-projet annoncé de MPPT24, le module « conception de bibliothèques de threads utilisateur » de PRCV24, et parce qu'écrire un ordonnanceur de threads change définitivement la manière dont on comprend le parallélisme.
Le sujet¶
Implémenter des threads coopératifs en espace utilisateur.
Les étapes :
- Création : allouer une pile séparée par thread (
mmap), et initialiser un contexte d'exécution. - Changement de contexte : d'abord avec
makecontext/swapcontextde la libc, qui fait le travail. Puis, si vous voulez aller au bout, en assembleur x86-64 : sauvegarder les registres à préserver selon la convention d'appel, échanger le pointeur de pile, restaurer. C'est une quarantaine d'instructions, et c'est très instructif. - Un ordonnanceur round-robin, puis une variante avec priorités.
- Les primitives :
yield,join, un mutex, une variable de condition. - La mesure : le coût d'un changement de contexte, à comparer à
pthread_create, à un changement de contexte noyau, et à une itération de boucle vide.
Le résultat à obtenir¶
Un changement de contexte utilisateur de l'ordre de quelques dizaines à quelques centaines de nanosecondes, contre plusieurs microsecondes pour la création d'un thread noyau. Ce facteur de cinquante à mille explique à lui seul l'existence de tout l'écosystème des runtimes de tâches (OpenMP tasks, StarPU, Cilk, TBB, Argobots).
Extension · +10 h¶
Ajouter le vol de travail : chaque ordonnanceur a sa file locale de tâches prêtes, et vole dans les files des autres quand il est inactif. Mesurer le déséquilibre de charge résiduel sur un ensemble de tâches de durées très variables, et comparer à un ordonnancement statique.
Liens : ICPA24, OpenMP et threads, ARSE23.
Le bilan des intermédiaires¶
Après ces projets, vous savez
- écrire un code MPI distribué avec recouvrement, et modéliser son passage à l'échelle ;
- construire et exploiter un cluster de zéro, et le reconstruire par script ;
- diagnostiquer un code que vous n'avez pas écrit et l'améliorer avec méthode ;
- porter un noyau sur accélérateur et juger le compromis entre performance et portabilité ;
- ce qu'il y a à l'intérieur d'une bibliothèque de threads.
À ce stade, vous avez le profil d'un candidat sérieux pour une équipe de compétition et pour un stage en centre de calcul.
Chapitre suivant : Projets avancés.