Projet :
EP-ATR

Précédent : Transformations affines d'horloges
Remonter : Résultats nouveaux Suivant :
Synthèse de
circuits et conception
Sous-sections
Mises en oeuvre distribuées
Participants : Albert Benveniste, Loïc Besnard, Patricia
Bournai, Thierry Gautier, Paul Le Guernic, Sylvain Machard, Éric
Rutten.
Mots clés : Signal, DC+, programmation
synchrone, génération de code enfoui, code distribué,
architecture hétérogène, compilation séparée, causalité,
communication synchrone/asynchrone .
Résumé :
La génération de code distribué pour les programmes
synchrones pose deux grands types de difficultés. 1/ La
compilation directe de code C (ou, plus généralement, de code
séquentiel) n'est pas compatible avec une recomposition
ultérieure avec d'autres modules. En d'autres termes, on ne
peut pas compiler séparément (du moins de façon brutale) des
programmes synchrones. 2/ Une architecture distribuée ne
s'accomode pas, en général, de l'hypothèse de synchronisme
parfait qui correspond au modèle de la programmation synchrone.
Pour le premier problème, nous avons proposé une notion de
«tâche atomique» qui constitue le grain maximal
autorisant une compilation séparée avec réutilisation possible
dans tout contexte. Pour le second problème, nous avons proposé
la propriété d'endochronie pour un programme
synchrone, qui garantit que ce composant peut être distribué en
s'appuyant uniquement sur les services d'une communication de
type ``send/receive'' fiable.
Sur ces bases, une méthodologie a été développée pour la
génération de code distribué, qui implique : 1/ la
spécification par l'utilisateur, au niveau du programme source,
de la répartition du programme, 2/ l'application de
transformations automatisées du code intermédiaire, qui
contrôle la correction du partitionnement, 3/ la génération du
code distribué correspondant aux différents processus et à
leurs communications.
La particularité du modèle synchrone (qui fait aussi sa
souplesse) est la possibilité pour le contrôle, lors d'une
réaction, de prendre des décisions sur la base de l'absence de
tel ou tel événement. Ceci est évidemment impossible en univers
distribué de nature asynchrone, où la notion de réaction n'existe
pas (à moins de distribuer une horloge globale). Nous avons mis
en évidence une classe de programmes, dits endochrones,
dont aucune décision de contrôle ne nécessite de tester l'absence
de signaux dans l'environnement. Ces programmes peuvent être
aisément utilisés en tant que modules dans une exécution
répartie. Lorsqu'un module n'est pas endochrone, on sait le
rendre endochrone en lui rajoutant un petit moniteur, spécifié en
Signal. Ceci revient à attacher au module le protocole dont il a
besoin, préalablement à toute répartition. Dans les cas
standards, ceci est pris en charge par le compilateur Signal.
Cette année, en collaboration avec B. Caillaud, du projet
Pampa, nous avons également dégagé la notion
d'isochronie pour une paire de programmes
synchrones : deux programmes forment une paire isochrone si
le remplacement du protocole de communication synchrone par une
communication asynchrone par file non bornée ne change pas les
comportements de chaque composant (bien-sûr, le timing global du
système résultant n'est pas préservé). Répartir une paire
isochrone sur une architecture asynchrone est immédiat. Rendre
une paire isochrone se fait, là encore, par ajout de protocoles
synthétisés.
Les programmes qui sont mono-horloge et dont toutes les sorties
dépendent de toutes les entrées s'exécutent naturellement selon
le schéma 1/ lire les entrées, 2/ calculer la réaction, 3/
produire les sorties. Et il n'y a pas d'autre schéma
envisageable. Ces programmes peuvent être compilés
séparément : une fois les entrées lues, on est armé pour
calculer la réaction, on peut le faire en toute tranquilité et
dans n'importe quel ordre. On peut donc compiler de tels modules
en code séquentiel et les conserver tels quels. Cette remarque se
généralise au cas multi-horloge, et aboutit à la notion de
tâche atomique. Ainsi, on augmente en général
considérablement le grain des actions qu'un scheduler
doit gérer à l'éxécution, contribuant à la simplification du
scheduler.
Ce modèle abstrait se présente donc sous la forme d'un ensemble
de tâches atomiques, ordonnancées par un scheduler. Les tâches
atomiques sont endochrones par construction, il reste à s'assurer
que le scheduler l'est aussi, ainsi que les modules résultant de
son partitionnement. On suppose, pour simplifier, que les tâches
atomiques ne sont pas partitionnées. Dans le cas contraire, on
synthétise les petits moniteurs additionnels. On dispose ainsi
d'un modèle abstrait de programme réparti, équivalent au source,
et dont les communications sont conformes au modèle asynchrone de
communication send/receive. Dans ce modèle abstrait, on notera
que, grâce aux propriétés de la composition synchrone de
programmes, on peut répliquer certains calculs sur des
processeurs différents, afin de minimiser les communications ou
de faciliter l'obtention de l'endochronie.
Il reste alors à :
- implémenter effectivement les communications abstraites à
l'aide des primitives de communication de l'architecture
support -- il faut donc modéliser ces communications à l'aide
de Signal;
- engendrer le code pour chaque module.
Cette approche est développée au sein des projets Esprit
Sacres et Syrf, et est présentée dans [[20],[23],[24],[31]].
Cette année, dans le cadre de la dernière phase de Sacres,
nous avons achevé de mettre au point l'ensemble des modules
nécessaires à la mise en oeuvre de cette méthodologie. Ces
modules prennent du format DC+ ou du format
interne Signal, et opèrent par transformation de programme. On
dispose ainsi d'un atelier où ces modules peuvent être enchaînés
de manière flexible. Le travail de développement de cette année
est donc une brique essentielle à l'évolution du compilateur
Signal vers un compilateur reciblable, paramétré par
l'architecture cible.
Cette méthodologie de répartition de programmes (Signal ou
DC+) est ainsi mise en oeuvre sous l'environnement
graphique de Signal. Elle se décompose alors en plusieurs
étapes :
- définition par l'utilisateur du graphe logiciel (représenté
par des «boîtes interconnectées»). Ce programme peut être
compilé tel quel puis simulé afin de vérifier qu'il est correct
et qu'il correspond bien aux spécifications d'origine.
- définition par l'utilisateur de son architecture
matérielle, les boîtes correspondant alors à des
processeurs.
- mapping du graphe logiciel sur le graphe matériel,
avec réplication de code autorisée (une boîte représentant du
logiciel peut être dupliquée dans plusieurs boîtes représentant
des processeurs).
- compilation séparée de chacun des processeurs.
- remplacement automatique (au niveau graphique) des
processeurs par le résultat de leur compilation. Le résultat de
la compilation est un programme Signal dont l'interface est
modifiée.
- ajout des processus de communication avec leurs
connexions.
- compilation globale, les processeurs sont alors vus comme
des programmes externes afin de ne pas les recompiler.
- génération de code distribué, suivant le type de génération
souhaité (code embarqué, simulation...).

Précédent : Transformations affines d'horloges
Remonter : Résultats nouveaux Suivant :
Synthèse de
circuits et conception