Sous-sections
Mots clés : algorithmique parallèle,
modèle de programmation, graphe de tâches, ordonnancement,
placement, répartition de charge, programme synthétique
.
Résumé :
La définition d'une interface de programmation pour
machine parallèle peut répondre à plusieurs
objectifs : la portabilité des codes existants, la
parallélisation automatique ou encore la répartition de
charge. Au niveau du langage de programmation, l'extraction
du parallélisme est un problème difficile, que nous
n'abordons pas dans ce projet. Notre effort porte sur la
problématique de la répartition de charge, l'utilisateur
exprimant le parallélisme de son algorithme de façon à
éviter toute analyse complexe du code.
La variété des architectures distribuées (de la machine
séquentielle super-scalaire à la grappe composée de noeuds
multi-processeurs symétriques) motive la définition de
modèles de programmation parallèle portables. Il s'agit bien
sûr d'offrir une sémantique indépendante de l'architecture
pour autoriser la réutilisabilité et faciliter le couplage de
codes (on parle parfois de langages de coordination, ou de
programmation par squelettes); mais il s'agit aussi de
permettre des exécutions performantes, en spécialisant
l'ordonnancement à l'architecture. Ceci est parfois réalisé
par annotation de code, comme c'est le cas pour HPF et
Open-MP.
Dans cet axe de recherche, nous étudions les modèles de
programmation parallèle et distribuée permettant d'offrir des
garanties de performances par contrôle de l'ordonnancement
tout en facilitant le développement et le couplage de
codes.
En dehors de la parallélisation automatique de code
séquentiel qui est un problème difficile, la plupart des
modèles sont généralement basés sur un parallélisme
explicite, dont l'extraction ne nécessite pas une analyse
complexe de code; c'est par exemple le cas pour Cilk
[6] ou Jade [11].
Historiquement employée pour les langages de programmation
logique, une technique d'interprétation abstraite est
utilisée pour contrôler l'exécution. Une difficulté est alors
de minimiser le coût de cette interprétation, notamment sur
des architectures distribuées.
Nous développons un modèle de
programmation dont la sémantique, basée sur une mémoire
partagée, fait totalement abstraction des caractéristiques de
l'architecture. Le parallélisme peut être analysé à un grain
arbitraire et les dépendances de données précalculées par
interprétation abstraite. Cette interpétation permet
l'analyse à la volée du flot de données et autorise donc le
calcul d'un ordonnancement fin, prenant en compte non
seulement l'activité des processeurs mais aussi la localité
des accès aux données. En outre, l'existence d'un
ordonnancement séquentiel implicite permet un repliage
efficace du programme sur un nombre limité de processeurs. De
plus, ce repliage séquentiel implicite conduit à une
sémantique naturelle, lexicographique. Ainsi, le modèle de
programmation permet d'exprimer le couplage de codes par
composition, sans perte de parallélisme et tout en respectant
les dépendances de données.
En liaison avec les études menées dans le
thème algorithmique et ordonnancement, l'exécution
d'un algorithme parallèle peut être représentée par un graphe
qui modélise les calculs et les dépendances de données entre
ces calculs. Les compilateurs-paralléliseurs s'attachent au
calcul de ce graphe à partir d'un programme séquentiel. Une
approche alternative est de définir un modèle de
programmation parallèle qui permet l'expression de la
décomposition d'un calcul en sous-calculs parallèles ainsi
que l'enchaînement de phases parallèles. Typiquement un
calcul est l'exécution d'un appel de procédure (on parle de
tâche).
La qualité d'une stratégie de
répartition de charge dépend de la connaissance de
l'application ( i.e. du graphe de tâches associé) et
de la machine d'exécution.
Le système est donc ouvert : à la stratégie de
répartition peut être substituée une autre stratégie qui
respecte une même spécification d'interface avec le module de
gestion du graphe de tâches d'une part et avec le module de
mise en oeuvre des tâches d'autre part. Le choix de la
stratégie de répartition peut se faire par annotation de
code.
Des stratégies de répartition justifiées sur le plan
théorique par la théorie de l'ordonnancement en ligne
existent. Ces stratégies cherchent à minimiser l'inactivité
des n
uds (algorithmes de liste,
work stealing). Certaines de ces
stratégies utilisent des informations annotées sur les tâches
(coût estimé, priorité ou localité). Testé sur des
applications en calcul scientifique, ces ordonnancements,
pourtant théoriquement justifiés, conduisentt à des
performances très faibles. La raison principale en est une
implantation trop générale du modèle de programmation qui
entraîne un surcoût important pour le contrôle de
l'ordonnancement (lié notamment à la création des tâches et
aux accès indirects aux données).
Pour limiter ce surcoût, nous nous intéressons à la
possibilité de prendre en compte finement, et ce dès la
compilation, le contexte d'exécution (application et
architecture cible) pour optimiser l'analyse du flot de
données.