• Aucun résultat trouvé

mémoire disponible pour chaque coeur, et donc pour chaque tâche. De ce fait, il peut être inté- ressant de combiner programmation par passage de messages pour la gestion du parallélisme entre les noeuds, et programmation en mémoire partagée pour la gestion du parallélisme intra- noeud. C’est ce que l’on appelle la programmation hybride.

Bien que cette approche soit théoriquement la mieux adaptée pour l’exploitation optimale d’une grappe de calcul moderne, elle est encore peu mise en oeuvre à l’heure actuelle. En effet il n’existe ni interface, ni support exécutif standard prévu à cet effet. Il faut donc combiner des outils conçus pour chacun des deux paradigmes : typiquement une tâche MPI est déployée sur chaque noeud, chaque tâche MPI étant composée d’un ensemble de tâches en mémoire partagée générées par exemple avec OpenMP. Malheureusement, les interfaces des supports exécutifs actuels sont mal adaptées a cette utilisation, et ce pour différentes raisons.

Tout d’abord, les bibliothèques implémentant le standard MPI supportent très mal le mode MPI_THREAD_MULTIPLE qui permet aux primitives de communications MPI d’être appelées simultanément par plusieurs tâches en mémoire partagée. Les performances obtenues lorsque plusieurs tâches communiquent en parallèle sont ainsi très dégradées. En outre, ce mode de fonctionnement étant peu testé, les implémentations standard contiennent encore quelques bugs notamment lorsque des réseaux rapides sont mis en jeu.

En outre, l’ordonnancement des différentes tâches en mémoire partagée rentre en conflit avec la progression des communications MPI ainsi qu’avec les primitives de communication blo- quantes car elles sont implémentées par des bibliothèques différentes. Idéalement, la scruta- tion de la terminaison des communications doit être intégrée à l’ordonnanceur afin de pouvoir efficacement recouvrir les communications par du calcul en exécutant d’autres tâches.

Pour finir, le programmeur doit maîtriser deux interfaces de programmation hétérogènes, qui n’ont pas été pensées pour fonctionner ensemble.

L’approche hybride est donc complexe à mettre en oeuvre et demande un investissement im- portant en temps de développement. Cet investissement se révèle fréquemment peu rentable car, du fait des problèmes exposés ci-dessus, les performances obtenues sont souvent déce- vantes et même parfois inférieures à celles obtenues par l’approche mémoire distribuée pure. Néanmoins, cette situation est en train de changer du fait l’augmentation rapide du nombre de coeurs embarqués dans les machines et de nombreux travaux de recherche ont actuellement pour but de fournir des supports exécutifs performants pour la programmation hybride[22, 23, 24].

1.3 Des machines complexes à exploiter

Notre étude de l’architecture matérielle des grappes de calcul ainsi que des modèles de pro- grammation dédiés permet déjà de dégager une tendance générale : l’augmentation rapide de la puissance des machines dédiées au calcul haute performance s’accompagne de l’arrivée d’un grand nombre de contraintes. Dans cette section, nous nous penchons plus avant sur les difficultés rencontrées dans l’exploitation des grappes, et ce à différents niveaux. Nous pré- sentons d’abord les obstacles rencontrés par les développeurs qui doivent faire évoluer leurs applications en fonction des architectures matérielles des grappes. Nous passons ensuite aux nouvelles contraintes matérielles à prendre en compte par la pile logicielle de niveau système et terminons par les problèmes de déploiement d’application liés aux utilisations nouvelles des grappes.

1.3.1 Développement parallèle

Comme nous l’avons vu dans la section 1.2, les développeurs doivent paralléliser leurs applica- tions pour exploiter la puissance de calcul des grappes. Ce travail reste extrêmement difficile et les nombreux efforts investis dans la recherche de nouveaux modèles de programmation ainsi que dans le développement d’outils et de bibliothèques adaptés se révèlent encore insuffisants. Tout d’abord, indépendamment de toute contrainte technique, la nécessité de paralléliser des applications implique une remise en question d’un certain nombre d’acquis. Le meilleur algo- rithme parallèle n’est par exemple pas nécessairement issu d’une parallélisation du meilleur algorithme séquentiel et un travail de recherche conséquent est nécessaire pour obtenir des solutions efficaces.

En outre, l’écriture d’un programme parallèle reste conditionnée à la prise en compte de nom- breuses contraintes liées au matériel que les modèles de programmation présentés précédem- ment ne permettent pas de masquer. Les efforts déployés pour paralléliser efficacement une application sur une machine donnée peuvent ainsi être réduits à néant lors du passage à une génération suivante de machine. C’est un problème majeur car le matériel tend a évoluer bien plus rapidement que le logiciel : le cycle de vie des machines parallèles est de quelques années seulement, alors que celui de certaines applications critiques se compte en dizaines d’années. Le portage de codes écrit pour des supercalculateurs vectoriels vers les machines parallèles distribuées d’aujourd’hui a par exemple été très coûteux en temps de développement. Aujour- d’hui encore, on ne parvient pas à pleinement exploiter les grappes de machines multicoeur mais celles-ci pourraient déjà être remplacées dans un futur proche par des grappes hétéro- gènes dont la majorité de la puissance de calcul est fournie par des GPUs

Par ailleurs l’ensemble des outils composant l’environnement de développement standard d’un programmeur ne se sont pas encore adaptés à la révolution parallèle. L’un des exemples les plus frappant est celui des outils standard de débuggage qui ne permettent pas d’analy- ser efficacement des exécutions parallèles à grande échelle. Il en va de même pour les outils de trace qui sont pourtant indispensables pour comprendre les bogues difficiles à reproduire auxquels les développeurs d’applications parallèles sont fréquemment confrontés.

Pour finir, l’utilisation simultanée d’un grand nombre de noeuds de calcul par une applica- tion rend probable que l’un des composants matériel mis en jeu tombe en panne au cours de son exécution. Une application dédiée au calcul parallèle à grande échelle doit donc implé- menter des mécanismes de tolérance aux pannes pour ne pas gaspiller le temps de calcul déjà consommé en cas de défaillance d’un composant matériel. Ainsi, dans le cas de la technique de protection/reprise, qui est la plus utilisée, l’application doit être capable de sauvegarder sur disque son état complet afin de pouvoir le restaurer par la suite en cas de panne.

Tout cela constitue donc une véritable barrière à l’utilisation massive des grappes de calcul, surtout si l’on considère que leurs utilisateurs potentiels sont souvent des scientifiques de dif- férents domaines, non spécialistes en informatique, qui ont besoin de puissance de calcul mais n’ont pas le temps ou les compétences pour paralléliser efficacement leurs programmes en pre- nant en compte toutes ces contraintes.

1.3.2 Gestion des contraintes matérielles

En sus du travail supplémentaire induit par la nécessité de paralléliser les applications, l’aug- mentation de la puissance de calcul des grappes par l’ajout de parallélisme supplémentaire est source de contraintes matérielles nouvelles qui complexifient la gestion des calculateurs. Nous

1.3. Des machines complexes à exploiter 25 donnons ci-après quelques exemples de ces problèmes qui nécessitent des solutions novatrices à différent niveaux de la pile logicielle en charge de la gestion de la grappe.

Systèmes d’exploitation

Avec l’augmentation du nombre de coeurs mobilisés pour effectuer des calculs parallèles, il devient impératif de prendre en compte le bruit système qui peut, dans certaines conditions, avoir une influence très importante sur les performances obtenues [25]. On appelle bruit sys- tème l’ensemble des traitements relatifs au système d’exploitation que les processeurs d’une machine ont à effectuer, tels que le traitement des interruptions ou l’exécution de différents dé- mons système. Ces traitements asynchrones sont répartis sur les différents coeurs de la machine et « volent » un peu de temps de calcul aux programmes utilisateur qui s’exécutent simultané- ment. Cependant, comme ils sont généralement très légers, leur impact sur l’exécution d’un programme séquentiel est négligeable. La situation est toute autre dans le cas de programmes parallèles fortement couplés s’exécutant sur des milliers de coeurs. En effet, chaque pertur- bation d’un coeur par un traitement asynchrone peut potentiellement ralentir l’ensemble des processeurs si ceux-ci ont besoin d’un résultat calculé globalement pour continuer. Ce bruit système ne survenant pas au même moment sur les différents coeurs, son impact sur le temps d’exécution croît avec l’augmentation du nombre de coeurs.

Plus généralement, l’utilisation de systèmes d’exploitation généralistes tels que Linux pose des problèmes croissants. Que ce soit au niveau des politiques d’allocation mémoire, d’ordonnan- cement ou encore de gestion des entrées/sorties, les algorithmes mis en jeu relèvent de compro- mis qui ne sont pas toujours optimaux dans le cadre des machines parallèles à grande échelle. Pour tirer les meilleures performances des grappes il est donc fréquemment nécessaire de mo- difier ces systèmes d’exploitation par l’utilisation de « patchs » voir d’utiliser des systèmes d’exploitation dédiés. Il existe par exemple des systèmes d’exploitation légers qui permettent de minimiser le bruit système et qui laissent plus de contrôle aux applications sur certaines opérations bas-niveau comme les allocations mémoire[26].

Ordonnanceur de travaux

Nous avons vu que les noeuds des grappes ont une architecture hiérarchique. Cela est aussi vrai pour la topologie des réseaux puisque ceux-ci sont souvent organisés selon une cascade de commutateurs réseau formant un fat tree. La latence des communications point-à-point entre deux noeuds varie donc suivant le nombre de commutateurs traversés. En outre, pour les grappes de grande taille il devient trop coûteux d’équiper les derniers niveaux de l’arbre de suffisamment de liens pour obtenir une bande passante maximale entre deux moitiés du ré- seau. On se dirige donc vers des architectures de type « grappe de grappe », contenant un ensemble d’îlots au sein desquels les noeuds peuvent communiquer de manière optimale. Ces îlots sont eux-même interconnectés par un réseau performant mais insuffisant pour permettre à deux îlots complets de communiquer entre eux à pleine vitesse. Il est donc de plus en plus important pour les performances de minimiser la distance sur le réseau des noeuds qui sont utilisés pour l’exécution d’une application parallèle.

De même l’utilisation de noeuds multicoeur et multiprocesseur pose problème. D’un coté, cer- taines applications très fortement couplées, ou utilisant un modèle de programmation par mé- moire partagée, ont besoin de voir leur tâches regroupées sur une même machine. D’un autre coté, d’autres applications gourmandes en mémoire (en quantité ou en bande passante) pour- ront s’exécuter plus efficacement si leurs tâches sont réparties sur des noeuds différents. Pour

finir, les noeuds de calculs intégrant toujours plus de coeurs, il devient intéressant de regrouper plusieurs applications faiblement parallèles sur un même noeud, afin de minimiser le nombre de noeuds de calcul utilisés et réduire ainsi la consommation électrique.

Toutes ces contraintes sont difficiles à prendre en compte pour les ordonnanceurs de travaux qui ont la charge d’allouer les ressources des grappes pour les applications. Les algorithmes à mettre en place relèvent de compromis entre temps d’exécution, temps d’attente, fragmentation des ressources et nécessitent que l’utilisateur ait une bonne connaissance des caractéristiques de son application pour guider les décisions d’ordonnancement.

1.3.3 Adéquation de l’environnement logiciel

L’augmentation de la taille des grappes rend de plus en plus important de les mutualiser entre un grand nombre d’utilisateurs afin de les rentabiliser, que ce soit au niveau du prix d’achat ou de la consommation électrique. Nous pouvons notamment citer les nombreux projets de grilles qui visent à mettre en commun plusieurs grappes et groupes d’utilisateurs distribués géographiquement sur différents sites. Plus récemment l’engouement pour le cloud computing pousse de nombreuses entreprises à développer des offres commerciales permettant de louer de la puissance de calcul à la demande. Ces entreprises disposent en effet de gros centres de calcul très efficaces d’un point de vue énergétique et peuvent donc fournir de la puissance de calcul à faible coût. Pour de nombreux laboratoires, une telle solution peut se révéler plus rentable que l’achat d’une grappe de calcul dédiée.

Cette tendance pose le problème du déploiement rapide d’applications sur des grappes di- verses disposant d’environnement logiciels hétérogènes. En effet, même une application écrite de manière portable a souvent des dépendances logicielles, typiquement des bibliothèques, qui ne sont pas simples à satisfaire pour un utilisateur lambda de la grappe. Quant aux admi- nistrateurs, ils n’ont pas nécessairement les ressources pour installer et maintenir à jour tous les logiciels requis par les utilisateurs. Ce problème est exacerbé par les incompatibilités qui existent entre les versions de certaines bibliothèques ou compilateurs. Une mise à jour de la pile logicielle installée sur la grappe peut donc empêcher le fonctionnement ultérieur de cer- taines applications installées par les utilisateurs.

Nous avons par ailleurs vu que des patchs pour le système d’exploitation, voire des systèmes conçus spécialement pour les grappes sont parfois nécessaires pour obtenir les meilleures per- formances possibles. Ces patchs sont toutefois difficiles à appliquer en pratique car il faut les faire évoluer avec les mises à jour du système et s’assurer qu’ils ne posent pas de problème de sécurité. Quant aux systèmes d’exploitation dédiés, s’ils conviennent à certains utilisateurs pointus désirant les meilleures performances en calcul intensif, d’autres ne peuvent se passer des fonctionnalités standard fournies par les systèmes généralistes.