TH`ESE Architecture logicielle et outils pour syst`emes d`exploitation

publicité
INSTITUT NATIONAL POLYTECHNIQUE DE GRENOBLE
N◦ attribué par la bibliothèque
THÈSE
pour obtenir le grade de
DOCTEUR DE l’INPG
Spécialité : « Informatique : Systèmes et Logiciels »
préparée au laboratoire LSR-IMAG, projet SARDES,
dans le cadre de l’Ecole Doctorale
« Mathématiques Sciences et Technologies de l’Information »
présentée et soutenue publiquement par
Juraj P OLAKOVIC
le 25 Juin 2008
Architecture logicielle et outils pour systèmes d’exploitation
reconfigurables
Directeur de thèse :
Jean-Bernard S TEFANI
JURY
M.
Mme
M.
M.
M.
M.
M.
Gilles
Valérie
Gilles
Jacques
Jean-Philippe
Jacques
Jean-Bernard
M ULLER
I SSARNY
G RIMAUD
M OSSI ÈRE
FASSINO
P ULOU
S TEFANI
Président
Rapporteur
Rapporteur
Examinateur
Examinateur
Examinateur
Directeur de thèse
ii
Abstract
Dynamic reconfiguration allows modifying a system during its execution, and can be used to apply
patches and updates, to implement adaptive systems, dynamic instrumentation, or to support third-party
modules. Dynamic reconfiguration is important in embedded systems, where one does not necessarily
have the luxury to stop a running system.
While some operating systems do offer mechanisms for dynamic reconfiguration, the proposed mechanisms are essentially hardwired in the system. This results in a fixed trade-off between flexibility
of reconfigurations and the system’s efficiency which may be far from optimal in certain operational
contexts, thus limiting the system reuse.
We present an architecture-based programming model allowing both construction of customized reconfigurable system kernels and programming of their reconfigurations. This model is based on the
F RACTAL component model and its C implementation for constructing component-based operating systems, called T HINK. The framework supporting our approach encompasses an architecture compiler for
building customized system kernels and a reconfiguration compiler. We developed several prototypes of
reconfigurable systems that show the flexibility of our approach and the impact of different implementations of reconfiguration mechanisms on the system’s performance.
Résumé
La reconfiguration dynamique est la capacité d’un système logiciel à permettre sa modification pendant son exécution et peut être utilisée pour mettre-à-jour une partie fautive du système, introduire des
algorithmes spécialisés, autoriser des extensions faites par des tiers, adapter le système à un nouvel environment et ajouter des sondes de monitoring ou debugging, etc.
Les systèmes d’exploitation existants offrent des mécanismes de reconfiguration dynamique, néanmoins ceux-ci sont figés par l’implémentation du système. Par conséquent le compromis entre la flexibilité et l’efficacité du système reconfigurable est fixe et il n’est pas possible de réutiliser le système dans
d’autres contextes opérationnels (avec des mécanismes de reconfiguration différents).
Nous présentons une approche architecturale pour la construction de systèmes reconfigurables à
la carte et la programmation de leurs reconfigurations. Notre modèle de programmation est basé sur
le modèle à composants F RACTAL et son implémentation en C, appelée T HINK. Le canevas associé au
modèle comprend un compilateur d’architecture qui permet de construire des systèmes reconfigurables et
un compilateur de reconfigurations. Pour illustrer notre approche, nous avons réalisé plusieurs prototypes
de systèmes reconfigurables qui ont permis de montrer la flexibilité de notre approche ainsi qu’une
évaluation quantitative et l’impact des différentes implémentations de reconfiguration dynamique sur
l’efficacité d’un système concret.
iii
iv
Table des matières
1
Introduction
1.1 Une définition . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Intérêts de la reconfiguration dynamique . . . . . . . . . . .
1.3 Systèmes reconfigurables . . . . . . . . . . . . . . . . . . .
1.4 Objectifs de la thèse . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Mécanismes de reconfiguration dynamique . . . . .
1.4.2 Construction des systèmes reconfigurables à la carte
1.4.3 Programmation des reconfigurations . . . . . . . . .
1.5 Organisation du document . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
I
Problématique et Etat de l’art
2
Etat de l’art
2.1 Systèmes reconfigurables . . . . . . . . . . . . . . . . . . . . . .
2.2 Systèmes d’exploitation reconfigurables . . . . . . . . . . . . . .
2.2.1 Classification des systèmes d’exploitation reconfigurables
2.2.2 Modèles d’architecture . . . . . . . . . . . . . . . . . . .
2.3 Synthèse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1 Flexibilité . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2 Efficacité . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.3 Garanties . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.4 Outils . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
II
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
3
4
5
5
5
6
7
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Contributions
9
9
10
10
13
15
15
17
17
18
20
21
Vers un modèle de construction de systèmes reconfigurables
3.1 Concepts fondamentaux de la reconfiguration dynamique .
3.1.1 Architecture et la reconfiguration dynamique . . .
3.1.2 Etat et la reconfiguration dynamique . . . . . . . .
3.2 Aperçu de la contribution . . . . . . . . . . . . . . . . . .
3.2.1 Limitations . . . . . . . . . . . . . . . . . . . . .
3.2.2 Mise-en-oeuvre . . . . . . . . . . . . . . . . . . .
3.2.3 Organisation de la contribution . . . . . . . . . . .
3.3 Fondations de l’approche . . . . . . . . . . . . . . . . . .
3.3.1 Le modèle à composant Fractal . . . . . . . . . .
v
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
24
24
25
26
28
29
29
29
30
TABLE DES MATIÈRES
3.3.2
4
5
6
III
7
TABLE DES MATIÈRES
THINK : une implémentation de Fractal en C . . . . . . . . . . . . . . . . . . .
31
Interface de programmation pour la reconfiguration dynamique
4.1 Interface de programmation des reconfigurations . . . . . . .
4.1.1 Motivation des choix de conception . . . . . . . . . .
4.1.2 Identification et introspection . . . . . . . . . . . . .
4.1.3 Contrôle d’état . . . . . . . . . . . . . . . . . . . . .
4.1.4 Modifications de l’architecture . . . . . . . . . . . . .
4.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 Exemple d’un programme de reconfiguration . . . . . . . . .
4.4 Exemples d’implémentation . . . . . . . . . . . . . . . . . .
4.4.1 Comptage de références . . . . . . . . . . . . . . . .
4.4.2 Intercepteurs dynamiques . . . . . . . . . . . . . . .
4.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
37
37
37
38
40
42
42
44
46
46
51
55
Compilation des systèmes reconfigurables
5.1 Le principe de la compilation des systèmes reconfigurables
5.2 Le compilateur Think ADL . . . . . . . . . . . . . . . . .
5.3 Mise-en-oeuvre avec Think ADL . . . . . . . . . . . . . .
5.3.1 Spécification des composants reconfigurables . . .
5.3.2 Transformations architecturales . . . . . . . . . .
5.3.3 Intercepteurs et usines d’intercepteurs . . . . . . .
5.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
57
57
58
60
61
63
64
66
Reconfiguration des architectures Think avec FScript
6.1 Le langage FScript . . . . . . . . . . . . . . . . .
6.1.1 Eléments du langage . . . . . . . . . . . .
6.1.2 Bibiolothèque d’actions et de fonctions . .
6.1.3 Exemples . . . . . . . . . . . . . . . . . .
6.2 Supports d’exécution pour FScript . . . . . . . . .
6.2.1 Répartition du support FScript . . . . . . .
6.3 Un compilateur FScript . . . . . . . . . . . . . . .
6.3.1 Défis de l’implémentation . . . . . . . . .
6.3.2 Caractéristiques du prototype . . . . . . .
6.3.3 Mise-en-oeuvre avec Think ADL . . . . .
6.3.4 Le composant de reconfiguration généré . .
6.3.5 Support du système à l’exécution . . . . .
6.4 Conclusion . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
67
67
68
69
69
70
71
73
74
74
75
76
78
78
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Evaluation
Evaluations
7.1 Méthode d’évaluation . . . . . .
7.1.1 Sujet d’évaluation . . .
7.1.2 Critères d’évaluation . .
7.1.3 Prototypes d’évaluation
7.2 Evaluation qualitative . . . . . .
7.2.1 Description du système .
79
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
vi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
81
81
81
82
83
83
83
TABLE DES MATIÈRES
7.3
7.4
7.5
TABLE DES MATIÈRES
7.2.2 Compilation du système . . . . . . . . . . . . . . .
7.2.3 Programmation et compilation d’une reconfiguration
Micro-benchmarks . . . . . . . . . . . . . . . . . . . . . .
7.3.1 Intercepteurs dans un modèle à threads . . . . . . .
7.3.2 Un modèle d’exécution événementielle . . . . . . .
Evaluation de performances de systèmes reconfigurables . .
7.4.1 Décodeur vidéo H.264 reconfigurable . . . . . . . .
7.4.2 Reconfiguration dynamique des noeuds de capteurs .
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.1 Evaluation qualitative . . . . . . . . . . . . . . . . .
7.5.2 Evaluation quantitative . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Conclusion
8
86
87
88
88
90
92
92
96
98
98
99
101
Conclusion et perspectives
101
8.1 Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
8.2 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
8.3 Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Annexes
107
A Caractéristiques variées des systèmes embarqués
107
B Modèles d’exécution
111
B.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
B.2 Modèle d’exécution événementiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
C Historique du compilateur Think ADL
113
D Optimisations architecturales sélectives
D.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
D.1.1 Historique . . . . . . . . . . . . . . . . . . . . . . . .
D.1.2 Objectif . . . . . . . . . . . . . . . . . . . . . . . . .
D.2 Les problèmes . . . . . . . . . . . . . . . . . . . . . . . . . .
D.2.1 Problèmes identifiés de l’implémentation actuelle . . .
D.2.2 Problèmes liés à l’implémentation des optimisations .
D.3 Vers une implémentation . . . . . . . . . . . . . . . . . . . .
D.3.1 Un nouveau langage d’implémentation de composants
D.3.2 Spécification des optimisations . . . . . . . . . . . . .
D.3.3 Support de compilation . . . . . . . . . . . . . . . . .
D.4 Optimisations architecturales et reconfiguration dynamique . .
D.5 En conclusion . . . . . . . . . . . . . . . . . . . . . . . . . .
115
115
115
116
117
117
118
118
118
119
119
119
119
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Réferences
121
References
121
vii
TABLE DES MATIÈRES
TABLE DES MATIÈRES
viii
Chapitre 1
Introduction
Avec la chute des prix des circuits intégrés et les avancées technologiques permettant entre autre leurs
miniaturisation, les systèmes embarqués prolifèrent dans notre entourage. Ces systèmes varient du simple
capteur ou divers objets communiquants jusqu’aux systèmes embarqués dans les voitures, avions ou dans
l’électronique grand public, en passant par des systèmes de télécommunication. Souvent, ces systèmes
sont inaccessibles physiquement ou sont sous le contrôle d’un utilisateur final (ou dans sa possession,
comme par exemple un téléphone portable).
Avec cet avénement de l’informatique ubiquitaire (Weiser, 1991), émerge le problème de la mise-àjour, voire de modification complète, du logiciel qui est embarqué sur ces systèmes. La manière simple
consiste à écrire une nouvelle image du système et à le redémarrer. Cependant, ces systèmes fournissent
souvent un service qui ne peut pas être interrompu pour mettre à jour le logiciel du système. De plus,
un tel arrêt et redémarrage du système implique la perte de l’état du système. Par conséquent il faut se
tourner vers des solutions qui permettent une mise-à-jour du système, sans interruption de service et sans
perte d’état.
Par exemple, le système d’exploitation d’un téléphone portable peut à un moment nécessiter une
mise-à-jour de sécurité. Dans ce cas, l’approche de la modification du système avec un redémarrage
occasionne une gène à l’utilisateur – le redémarrage lui est visible avec toutes les conséquences (surtout
commerciales, dûes à l’inconfort d’utilisation) que cela implique1 .
1.1
Une définition
Nous definissons la reconfiguraiton comme :
La reconfiguration dynamique est la capacité d’un système logiciel à permettre la modification d’une sous-partie du système pendant son exécution, sans interruption de service.
En d’autres termes, une reconfiguration dynamique est une modification de la configuration architecturale (ou structurelle) d’un système pendant son exécution. La configuration i du système évolue vers
la configuration i+1 (Kramer & Magee, 1990), par exemple par l’ajout, la suppression ou le remplacement d’une partie de l’architecture. Contrairement à la reconfiguration statique – qui consiste à arrêter
le système pour effectuer les modifications et le redémarrer – la reconfiguration dynamique n’interrompt
pas l’exécution du système et de ce fait est trasparente à l’utilisateur.
1
”Do you want to restart your computer now ?”
1
1.2. Intérêts de la reconfiguration dynamique
Chapitre 1. Introduction
Dans la littérature, d’autres définitions sont proches de la définition de reconfiguration dynamique,
notamment l’adaptabilité et l’extensibilité. Une adaptation est une modification d’un système en réponse
à un changement du contexte dans lequel il se trouve, créant des conditions particulières ou nouvelles
(David, 2005). La notion d’adaptation considère non seulement le système, mais aussi son contexte
environnant et des critères permettant d’évaluer la qualité d’une adaptation. Une adaptation peut donner
lieu à une modification du système, i.e. reconfiguration dynamique, que nous considérons alors comme
un mécanisme de bas niveau à l’adaptation. Quant à l’extensibilité, elle réfère à des mécanismes d’un
système d’exploitation permettant l’ajout de nouvelles fonctionalités (ou d’interface plus appropriées)
et non à la mise-à-jour des parties existantes. Notre définition de la reconfiguration dynamique englobe
l’extensibilité du système.
La problématique de la reconfiguration dynamique est souvent considérée comme un cas particulier
d’une problématique plus vaste qu’est la configuration d’un système. Dans ce cas la reconfiguration
est la capacité de configuration à l’exécution (Denys et al., 2002). La reconfiguration dynamique est
aussi appelée online reconfiguration (dans K42 (Soules et al., 2003), mutation (dans MMLite (Helander
& Forin, 1998) ou dynamic software update (DSU, dans les travaux de Hicks (Hicks, 2001; Hicks &
Nettles, 2005)).
1.2
Intérêts de la reconfiguration dynamique dans les systèmes embarqués
Nous référons au système embarqué comme à un sous-système éléctroniquement programmable faisant partie d’un système hétérogène plus large (définition empruntée du projet européen Artist, (Artist2,
n.d.)). Cette large définition englobe toute une gamme de systèmes plus ou moins complexes avec des
caractéristiques différentes, en particulier, cette définition comprend aussi bien la partie matérielle que
la partie logicielle d’un tel système. Le logiciel comprend éventuellement un système d’exploitation et
la partie applicative. Dans ce travail nous nous intéréssons plus spécifiquement à la partie logicielle des
systèmes embarqués.
Nous divisons les systèmes embarqués, en deux catégories – i) les systèmes pour lesquels un arrêt
de fonctionnement et réinitialisation pour la mise-à-jour du logiciel est acceptable, voire prévue, et ii)
les systèmes où un tel arrêt est inacceptable (par exemple pour des raisons économiques). Dans la suite,
nous nous intéressons uniquement à la deuxième catégorie.
Les capacités de reconfiguration dynamique ouvrent de nouvelles possibilités à la conception de
systèmes embarqués. Pour faire une modification du système déployé, il n’est plus nécéssaire de reconstruire, regénerer et redéployer le système, avec les conséquences comme le redémarrage (donc un temps
sans service), perte de l’état actuel du système etc. Par conséquent, nous pouvons exploiter ces capacités
pour mettre-à-jour une partie fautive du logiciel, introduire des algorithmes spécialisés, autoriser des
extensions faites par des tiers ou adapter le système à un nouvel environment.
Mises-à-jour La mise-à-jour d’une partie du système est la première application de la reconfiguration
dynamique. Cette mise-à-jour peut être requise soit i) pour corriger un module défaillant dans le logiciel,
soit ii) pour adapter le système à un nouvel environment.
– Correction de fautes logicielles Selon le système embarqué considéré, la conception du logiciel
système passe par une phase de validation importante qui élimine quasiment toute source d’erreur.
Cependant, il existe toute une classe de systèmes dont la conception est dictée par le délai de
mise sur le marché et où le système commercialisé comporte encore des erreurs à corriger, voire
des erreurs de conception. La capacité de reconfiguration dynamique permet alors de corriger ces
défauts et la finalisation peut avoir du produit peut avoir lieu même après son déploiement2 .
2
Ceci est le cas des routeurs domotiques tels la LiveBox ou la FreeBox ou des routeurs télécoms.
2
Chapitre 1. Introduction
1.3. Systèmes reconfigurables
– Nouvelles versions, nouvelles spécifications Les besoins sur un système peuvent évoluer au cours
du temps, donnant lieu à une nouvelle spécification. Dans ce cas, une fois la nouvelle version disponible, la reconfiguration dynamique permet de mettre à jour le système déployé avec cette nouvelle
version. Par exemple une mise-à-jour du routeur domotique peut être nécéssaire pour déployer un
nouveau service de l’opérateur de (ex. de la passerelle domotique LiveBox de l’opérateur Orange
et des service MaLigneTV ou unik).
Spécialisations, Algorithmes adaptatifs Les perfomances d’un algorithme implémenté dans le système d’exploitation peuvent varier d’un système embarqué à l’autre. La reconfiguration dynamique
permet de remplacer l’algorithme (sous-système) avec une version spécialisée, pendant l’exécution du
système. Le concepteur du système développe plusieurs version d’un algorithme qui peuvent être interchangées à l’aide de la reconfiguration dynamique ((Soules et al., 2003) discute l’exemple d’un file cache
manager adaptable).
Monitoring, debugging Dans l’exemple précédent, la décision de reconfiguration pour spécialiser un
module se base sur des données récoltées pendant l’exécution du système, notamment les informations
concernant les performances du système. Ces informations peuvent être obtenues en introduisant des
sondes de surveillance entre les différents modules du système moyennant la reconfiguration dynamique.
Le monitoring des interactions entre les différents modules du système peut s’avérer utile pendant la mise
au point d’un système - par exemple comprendre l’origine d’un inter-bloquage (deadlock).
Extensions Une autre application de la reconfiguration dynamique se trouve dans l’extension d’un
système d’exploitation. Il peut s’agir des extensions effectuées par des tiers, en particulier par des applications (on parle alors de application specific services). Une application n’est plus obligée de se baser
sur un ensemble d’interface imposé par le système, mais peut implémenter et utiliser ses propres interfaces systèmes, réalisées sous forme d’extensions. Il en résulte une meilleure efficacité de l’application.
Bershad dans SPIN (Bershad et al., 1994) détaille plusieurs scénarios d’extensions système utiles à une
application (extension de traitement d’un protocol (IPC, TCP/IP), ordonnancement applicatif, système
de fichier applicatif ...).
Un système qui autorise des extensions faites par des tiers (via la reconfiguration dynamique) est
un système ouvert, et cette capacité entraı̂ne des conséquences en matière de sécurité et de sûreté d’un
système ouvert, car il faut pouvoir garantir la fiabilité des extensions ou du moins les isoler en cas de
dys-fonctionnement (Denys et al., 2002), (Seltzer et al., Oct. 1996), (Bershad et al., 1994).
Support pour l’adaptabilité De manière générale, la reconfiguration dynamique constitue la base
pour la conception de système adaptables (self-diagnosing et self-healing) – des systèmes qui évoluent en
fonction des conditions de leur environment, de leur contexte (Appavoo et al., 2003). Ainsi, la conception
du système évolue vers un élément de la boucle autonomique (autonomic computing) (Horn, 2001),
(Horn, 2001).
1.3
Systèmes reconfigurables
Un système est reconfigurable lorsqu’il permet de reconfigurer dynamiquement une de ses parties. Un
système reconfigurable définit le qui, le quoi, le quand et le comment de la reconfiguration dynamique.
La reconfiguration dynamique est à comprendre dans son environment qui comprend à la fois :
– des mécanismes (ou algorithmes) de reconfiguration dynamiques,
– des moyens (procédés, outils, ...) qui permettent de construire un système reconfigurable, et
3
Chapitre 1. Introduction
spécification
système
reconfigurable
exécution
système
reconfigurable
?
spécification
reconfiguration
plate-forme d'exécution
1.4. Objectifs de la thèse
reconfiguration
F IG . 1.1 – Les éléments d’un modèle de programmation de systèmes reconfigurables et leur relation.
– des moyens qui permettent de programmer des reconfigurations.
La relation entre ces trois éléments est schématisée sur la figure 1.1. Dans ce travail, nous appelons
l’ensemble de ces trois élements et leur relation un modèle de programmation de systèmes reconfigurables3 .
L’élément central de ce modèle de programmation sont les mécanismes de reconfiguration dynamique. Ces mécanismes permettent de modifier le logiciel en cours d’exécution, par exemple en ajoutant
de nouvelles parties, ou en modifiant le code ou les données des parties existantes.
Pour construire un système reconfigurable, le concepteur détermine quelles sont les parties reconfigurables du système (par exemple application sous-partie du système, composant, une liaison entre composants etc.), avec quels mécanismes et comment ces mécanismes sont accédés depuis les programmes
de reconfiguration.
La problématique de la reconfiguration dynamique ne s’arrête pas à la définition des mécanismes
de reconfiguration et à la construction d’un système reconfigurable, mais définit également comment
programmer les reconfigurations une fois que le système est déployé. Le programme de reconfiguration
va effectuer les modifications souhaitées en utilisant les mécanismes fournis par le système.
1.4
Objectifs de la thèse
Cette thèse est à placer dans le contexte des systèmes embarqués à composants, construits à la carte.
Les composants permettent de structurer un système et le concevoir explicitement suivant une architecture logicielle. De plus, les composants sont une unité de réutilisation et permettent ainsi la construction
de systèmes à la carte. Nous investiguons ces deux aspects au chapitre suivant.
Dans ce contexte, l’objectif de cette thèse est de fournir une approche homogène, permettant à la fois
de construire (à la carte) des systèmes embarqués à composants reconfigurables et de programmer les
reconfigurations de ces systèmes.
Concrétement, nous proposons :
– une approche générique pour autoriser l’utilisation de différentes implémentations des différents
mécanismes de reconfiguration dynamique dans un système à composants,
– une approche et des outils pour la contruction de systèmes reconfigurables à la carte, et
– une approche et des outils pour programmer les reconfigurations des systèmes reconfigurables
déployés.
L’association de ces trois éléments et la définition de la relation entre-eux, définit ce que nous appelons un Modèle de construction de systèmes reconfigurables à la carte.
3
Le modèle de programmation est une vue conceptuelle abstraite de la structure et de l’opération d’un système
4
Chapitre 1. Introduction
1.4. Objectifs de la thèse
La suite de cette section décrit plus en détail les objectifs des différents éléments constituant le
modèle.
1.4.1
Mécanismes de reconfiguration dynamique
Une interface de programmation générique Comme nous allons le voir dans les chapitres suivants,
la reconfiguration dynamique repose sur plusieurs mécanismes de base qui peuvent avoir différentes
implémentations suivant le système à construire. L’objectif premier étant alors de proposer une abstraction – une interface de programmation – pour ces différents mécanismes de base. Cette interface expose
au programmeur des reconfigurations l’implémentation des mécanismes de reconfiguration, pour une
partie donnée du système (i.e. chaque partie d’un système peut implémenter sa propre interface de reconfiguration). Une telle interface, permet la séparation des préoccupations entre l’implémentation des
mécanismes de reconfiguration et la programmation des reconfigurations se basant exclusivement sur le
contrat offert par l’interface proposée.
Mécanismes et interface de reconfiguration indépendants de l’implémentation fonctionnelle Nous
voulons que l’interface ainsi définie et son implémentation soient indépendantes de l’implémentation de
la partie fonctionnelle d’un système (séparation des préoccupations entre l’implémentation des mécanismes de reconfiguration et la partie fonctionnelle du système).
De cet objectif découle un certain nombre de propriétés :
– L’implémentation d’une telle interface de reconfiguration pour une partie donnée d’un système
peut être optionnelle – le système peut omettre l’implémentation des mécanismes de reconfiguration pour une partie du système non-reconfigurable.
– Plusieurs implémentations de cette même interface peuvent exister et peuvent être utilisées dans
un système, de façon transparente au programmeur de reconfigurations.
– Par conséquent, cette indépendance offre une flexibilité pour la construction des systèmes reconfigurables personnalisés (ou à la carte).
Implémentation des mécanismes respectant les contraintes de performances Nous voulons que
l’implémentation de cette interface de reconfiguration, par conséquent des mécanismes de reconfiguration, puisse respecter les différentes contraintes de performances de la plate-forme cible (par exemple
l’occupation mémoire ou le surcoût du temps à l’exécution).
1.4.2
Construction des systèmes reconfigurables à la carte
Il existe un certain nombre de canevas à composants permettant de construire des systèmes à la
carte. L’objectif est alors de proposer une extension d’un canevas pour pouvoir construire des systèmes
reconfigurable à la carte, i.e. avec une interface de reconfiguration.
Outils de construction Nous proposons de développer des outils (compilateur) supportant le processus
de construction des systèmes reconfigurables. Nous voulons également pouvoir combiner à la reconfiguration dynamique d’autres aspects non-fonctionnels (tel la sécurité).
1.4.3
Programmation des reconfigurations
Nous avons pour objectif de proposer un paradigme et des outils adaptés pour programmer les reconfigurations d’un système construit à la carte, homogènes avec le paradigme de construction de systèmes
reconfigurables.
5
1.5. Organisation du document
1.5
Chapitre 1. Introduction
Organisation du document
Le présent document est organisé en trois parties.
Etat de l’art et problématique
Le chapitre 2 – Etat de l’art – analyse les systèmes reconfigurables existants par rapport à nos objectifs.
Description de la contribution
Cette partie décrit notre proposition du modèle de programmation de systèmes reconfigurables et les
trois éléments qui le composent.
Le chapitre 3 – Vers un modèle de programmation de systèmes reconfigurables – présente un aperçu
global de notre proposition avec les fondations de notre approche à composants – le modèle Fractal et
son implémentation Think.
Le chapitre 4 – Interface de programmation pour la reconfiguration dynamique – décrit le premier
élément de notre proposition, à savoir comment nous proposons d’implémenter les différents mécanismes
de reconfiguration dans un systèmes à composants.
Le chapitre 5 – Compilation des systèmes reconfigurables – décrit notre approche pour la construction
des systèmes reconfigurables, à l’aide du compilateur Think ADL.
Le chapitre 6 – Reconfiguration des architectures Think avec FScript – développe notre proposition
pour programmer les reconfigurations d’un système à l’aide d’un langage dédié à la reconfiguration des
architectures Fractal.
Finalement, l’annexe D – Optimisations architecturales séléctives – décrit un travail en cours sur les
optimisations architecturales et leurs combinaison avec l’implémentation des mécanismes de reconfiguration dynamique. Partant du constat que la notion de composant comme entité visible à l’exécution
n’est pas toujours nécéssaire, nous avons développé un compilateur capable de générer des structures à
composants optimisées où le coût relatif à l’utilisation d’un composant est quasi nul.
Evaluation de la proposition
Le chapitre 7 – Evaluations – est dédié à l’évaluation qualitative et quantitative de notre proposition.
Concrétement nous avons réalisé trois prototypes de systèmes reconfigurables, à travers lesquels nous
montrons les différents aspects de l’évaluation du modèle proposé.
Nous concluons ce travail au chapitre 8 avec les différentes perspectives qui s’ouvrent par la suite.
6
Première partie
Problématique et Etat de l’art
7
Chapitre 2
Etat de l’art
Il existe une variété de systèmes d’exploitation, ainsi qu’il existe une multitude d’implémentations
de mécanismes de reconfiguration dynamique. L’objectif de ce chapitre est de synthétiser un état de l’art
de la reconfiguration dynamique dans les systèmes embarqués.Nous limitons notre analyse aux systèmes
disposant d’une architecture.
2.1
Systèmes reconfigurables
Le spectre de systèmes1 reconfigurables est large, avec autant de mécanismes pour la reconfiguration
dynamique. La figure 2.1 montre la répartition de ce spectre de systèmes en plusieurs catégories suivant
l’échelle de la reconfiguration, allant des systèmes d’exploitation reconfigurables, jusqu’aux systèmes
répartis. A chaque niveau correspond une problématique propre de reconfiguration dynamique. Ainsi par
exemple un mécanisme de reconfiguration pour les systèmes distribués n’aura pas les mêmes contraintes
d’efficacité qu’un mécanisme pour les systèmes d’exploitation mono-processeur, voire sur un noeud de
capteur fortement contraint en ressources matérielles. Orthogonallement à cette répartition, on trouve
des approches se basant sur des techniques particulières liées à une implémentation d’un langage de
programmation.
programming
language
(implementation)
application
application
application
middleware
operating
system
operating
system
operating
system
hardware
platform
hardware
platform
hardware
platform
OS level
middleware level
distributed operating
system
hardware
platform
...
application level
hardware
platform
...
DistOS level
language level
F IG . 2.1 – Le spectre de la reconfiguration dynamique dans les systèmes.
1
Système au sens large – système informatique plus ou moins complexe, comportant une ou plusieurs plate-formes
matérielles, système(s) d’exploitation, des applications etc.
9
2.2. Systèmes d’exploitation reconfigurables
Chapitre 2. Etat de l’art
Mécanismes de reconfiguration d’applications et approches langages Les approches langages pour
la reconfiguration dynamique consistent à s’appuyer sur un langage (souvent avec une sémantique particulière permettant la vérification à l’exécution) et son environnement d’exécution (au minimum un
éditeur de liens, sinon un compilateur) qui permet de remplacer des parties de codes ou de données à
l’exécution, comme c’est la cas de Dynamic Software Update de Hicks qui utilise Popcorn, une extension
au langage C (Hicks, 2001; Hicks & Nettles, 2005; Neamtiu et al., 2006), Dynamic C++ (Hjálmtýsson
& Gray, 1998) ou Erlang (Armstrong et al., 1996). Généralement ces approches sont adaptées à la reconfiguration des applications et non des systèmes d’exploitation – dépendence à un langage particulier,
nécéssité d’un environment d’exécution. Néanmoins, Dymos (Lee, 1983), un des premiers système d’exploitation reconfigurable, utilise cette technique pour la reconfiguration dynamique (basé sur le langage
Modula – *Mod (Cook, 1980)).
D’autres mécanismes de reconfiguration d’applications existent, comme PODUS (Segal & Frieder,
1993) ou On-Line Software Version Change (Gupta & Jalote, 1993), le dernier utilise une fonction de
transfert d’état entre deux instances du même programme (la notion d’état dans ce cas conret comprend
l’état d’exécution d’un programme – pile, tas et variables globales).
Systèmes distribués et middleware reconfigurables Il existe un grand nombre de systèmes répartis
reconfigurables, dont Argus (Bloom & Day, 1993; Bloom, 1983), PolyLith (Hofmeister, 1994), 2k (Kon
et al., 1998), Djinn (Mitchell et al., 1998) ou OpenCOM (Clarke et al., 2001; Coulson et al., 2002). Le
défi des mécanismes de reconfiguration dans les systèmes (d’exploitation) distribués ou les intergiciels
est de proposer des mécanismes de reconfiguration répartis, qui permettent d’une part de changer la
configuration distribuée du système, et d’autre part de synchroniser les modifications entre plusieurs
noeuds du système de manière efficace (Ajmani, 2004).
Systèmes d’exploitation reconfigurables La conception de mécanismes de reconfiguration pour les
systèmes d’exploitation présente des contraintes et défis que nous détaillons par la suite.
2.2
Systèmes d’exploitation reconfigurables
Le but de cette section est de présenter brièvement les différentes catégories de systèmes d’exploitation reconfigurables que nous analysons par rapport à nos objectifs dans la section suivante. Nous
discutons également les aspects architecture et modèle d’exécution dans ces systèmes.
Les systèmes que nous considérons tout au long de ce chapitre sont les suivants :
– systèmes à usage général
– K42, Synthetix
– micro-noyaux et exo-noyaux
– L4, Kea, Exokernel
– systèmes extensibles
– DYMOS, SPIN, VINO, Deimos
– systèmes reflexifs
– Apertos, Muse, MetaOS
– systèmes pour réseaux de capteurs, et – FlexCup, Maté, Contiki, SOS
– canevas de construction de systèmes
– MMLite, Think
2.2.1
Classification des systèmes d’exploitation reconfigurables
Le problème de la reconfiguration dynamique dans les systèmes d’exploitation est ancien. DYMOS
(Lee, 1983), un des premiers systèmes reconfigurables, a été proposé il y a plus de 25 ans. Depuis, une
quantité de systèmes reconfigurables ou solutions pour la reconfiguration dynamique ont vu le jour. Dans
ce spectre, nous avons identifié et classifié un certain nombre de systèmes représentatifs du domaine qui
répondent à des besoins différents.
10
Chapitre 2. Etat de l’art
2.2. Systèmes d’exploitation reconfigurables
Systèmes à usage général La reconfiguration dynamique dans les systèmes à usage général n’a que
peu d’intérêt et se limite à satisfaire le confort d’un utilisateur. Les systèmes, tels que Linux ou Windows
(qui sont des systèmes modulaires), fournissant qu’un support limité pour la reconfiguration dynamique,
typiquement limité à certaines fonctionnalités comme les pilotes de périphériques – il est possible de
charger ou décharger un module noyau. Cependant ces mécanismes sont ad-hoc et n’offrent pas un support complet pour la reconfiguration dynamique. Dans Linux par exemple, les modules peuvent dépendre
d’autres modules et pour remplacer (ou reconfigurer) un module sous-jacent, il faut décharger tous les
modules qui en dépendent.
Par contre, l’emploie des systèmes d’exploitation à usage général dans les serveurs ayant des requis
de haute disponibilité motive l’implémentation des mécanismes de reconfiguration dynamique dans ces
systèmes. Plusieurs approches existent, comme K42 (Soules et al., 2003; Baumann et al., 2005; Appavoo
et al., 2002), Slic (Ghormley et al., 1998) ou Synthetix (Pu et al., 1995b; Pu et al., 1995a).
K42 est un système à composants récent qui implémente l’ABI2 Linux. K42 défini un modèle d’exécution particulier, qui permet de détecter un état stable de composant en employant des intercepteurs
dynamiques. L’emploie des intercepteurs dynamiques permet de limiter dans le temps l’impact des intercepteurs, introduits uniquement pendant la reconfiguration. Dans nos travaux nous avons implémenté
ces mécanismes et nous les discuterons plus en détail dans les chapitres 4 et 7.
Synthetix consitue une approche intéréssante en proposant des mécanismes de spécialisation (i.e. reconfiguration) par évaluation partielle d’un système à l’exécution.
Micro-noyaux et exo-noyaux Historiquement, par rapport aux systèmes monolithiques, les micronoyaux, comme L4 (Liedtke, 1995), Chorus (Rozier et al., 1988), µ-Choices (Campbell & Tan, 1995;
Campbell & Islam, 1993), QNX (Hildebrand, 1992), Kea (Veitch & Hutchinson, 1998) ou Pebble (Gabber et al., 1999), répondent à un besoin de modularité, flexibilité et sécurité des systèmes (Liedtke, 1996).
La performance des mécanismes de communication entre les serveurs est au coeur de la conception de
tous les micro-noyaux.
Un micro-noyau n’est lui-même pas reconfigurable, mais le couplage faible entre les différents serveurs, implémenté par des IPC constitue un mécanisme de base pour la reconfiguration dynamique – à
base de redirection de la liaison entre deux serveurs – exploité dans Kea ou Pebble. De plus Kea affine les
mécanismes de communication et permet de migrer les serveurs utilisateurs vers le noyau et vice-versa.
µChoices permet l’extension d’un noyau en chargeant des agents.
Les exo-noyaux – Exokernel (Engler et al., 1995) – poursuivent la philosophie du minimalisme des
services systèmes des micro-noyaux, néanmoins tout mécanisme de reconfiguration dynamique est à
bâtir par le concepteur d’un système concret, au-dessus de ces services. Les exo-noyaux permettent de
construire de systèmes d’exploitation adaptés fonctionnellement à des applications.
Systèmes extensibles L’objectif des systèmes extensibles est d’autoriser les applications à personnaliser le système d’exploitation en y chargeant leur propre code permettant d’améliorer les performances et
les foncationnalités du système entier (système d’exploitation et application) (Cheung & Loong, 1995).
Par rapport à un système reconfigurable, un système extensible permet un ajout de fonctionalités de façon
prédéfinie et non la modification du système existant. Notre approche à la reconfiguration dynamique englobe l’extensibilité du système. Les extensions dans les systèmes extensibles ont un accès privilégié au
noyau, par conséquent la plupart des systèmes extensibles se focalise sur les mécanismes garantissant la
sécurité et la sûreté du système. Les techniques utilisées varient suivant les systèmes et inclus l’utilisation
de langages sûrs ou interprétés, l’isolation logicielle de fautes (software fault isolation ou sandboxing)
(Wahbe et al., 1993; Rippert & Stefani, 2002) ou un code vérifiable (proof-carrying code) (Necula, 1997;
2
Application Binary Interface - spécification d’un niveau de compatibilité entre le systèmes d’exploitation et les applications.
11
2.2. Systèmes d’exploitation reconfigurables
Chapitre 2. Etat de l’art
Necula & Lee, 1996) (qui consiste à accompagner un code avec une preuve formelle de validité qui peut
être vérifiée par le système au chargement).
SPIN (Bershad et al., 1995; Bershad et al., 1994) utilise un langage fortement typé – Modula-3,
associé à un compilateur à l’exécution qui par construction vérifie la validité des extensions, ou spindles.
Les extensions sont des gestionnaires d’événements qui sont connectés au bus d’événements du système
et peuvent ainsi réagir aux événements (appels de méthodes).
Dans VINO (Small & Seltzer, 1995; Seltzer et al., Oct. 1996) les extensions sont appelées grafts.
Dans VINO la sécurité est atteinte en combinant l’isolation logicielle de fautes (Small, 1997) et en
réalisant les reconfigurations du systèmes comme des transactions, permettant de maı̂triser l’utilisation
des ressources et valider les extensions. En cas de défaillance, un rollback permet de revenir à l’état avant
la reconfiguration.
DEIMOS (pour Dynamically Extensible Incrementally Modularised Operating System) (Clarke &
Coulson, 1998) est un système extensible qui permet à chaque application de construire son propre environment d’exécution, i.e. système d’exploitation. DEIMOS ne prédéfinit pas d’entité noyau, au lieu de
cela, les services systèmes sont implémentés comme modules gérés par un gestionnaire de configuration
(configuration manager) – chargement ou déchargement. Les modules DEIMOS implémentent le modèle
RM-ODP (Blair & Stefani, 1998) et sont conformes à notre définition de composants, à l’exception du
fait que le modèle ODP est un modèle plat.
De part sa technique d’implémentation, nous classons également DYMOS (pour Dynamic Modification System) (Lee, 1983) dans cette catégorie. Dymos est un des premiers systèmes reconfigurable
(il y a plus de vingt ans !), basé sur une variante de Modula. A l’exécution DYMOS inclus un compilateur et un environment d’exécution (comprenant par exemple un interpréteur de commandes pour la
reconfiguration).
Systèmes réflexifs Les systèmes réfléxifs, tels que Apertos (Yokote, 1992; Itoh et al., 1995), Muse
(Yokote et al., 1991) ou MetaOS (Horie et al., 1998), organisent le système en objets associées à des
méta-objets, via un MOP – meta-object protocol. Un premier méta-méta niveau alloue les ressources au
système – qui constitue les objets du méta-niveau. Les applications sont les objets du niveau de base
qui sont associés à un méta-niveau. Les objets implémentent des interfaces bien définies (Kiczales et al.,
1997; Maeda et al., 1997) qui permettent la reconfiguration du système en remplaçant des objets au
niveau méta, donc au niveau du système. Par conséquent chaque application (objets au niveau de base)
peut personnaliser le système sous-jacent (méta-niveau).
Systèmes pour réseaux de capteurs Apparus récémment (Hill et al., 2000), les noeuds de réseaux de
capteurs ont la particularité d’être des systèmes très contraints en ressources, nécéssitant des systèmes
d’exploitation légér et efficaces. De par la nature de leur déploiement, souvent difficilement accessible physiquement, la reconfiguration dynamique des systèmes pour réseaux de capteurs est essentielle,
néanmoins peu d’entre eux le sont. Pour la plupart, ces systèmes remontent des événements de capteurs
de manière périodique, étant en veille la plupart du temps. Par conséquent les mécanismes de mise-à-jour
se limitent souvent à une réécriture de l’image du système et redémarrage fiables du système (perdant
éventuellement un état), comme Mantis (Bhatti et al., 2005).
TinyOS (Hill et al., 2000) est l’un des premiers systèmes pour réseaux de capteurs. Les systèmes à
composants TinyOS sont construits à la carte, à l’aide du langage nesC (Gay et al., 2003). TinyOS est
un système événementiel. TinyOS n’est pas reconfigurable, néanmoins plusieurs approches existent pour
permettre la reconfiguration des applications d’un système TinyOS. XNP (Jeong et al., 2003) permet de
télécharger et réinstaller une nouvelle image système en effectuant un redémarrage. FlexCup (Marrón
et al., 2006) permet la reconfiguration dynamique au grain des applications. Le mécanisme de FlexCip
est basé sur des méta-données générées pendant la compilation du système qui permet à un éditeur de
12
Chapitre 2. Etat de l’art
2.2. Systèmes d’exploitation reconfigurables
liens embarqué de modifier le système pendant l’exécution. Cette approche nécéssite le partitionnement
d’une application en plusieurs composants chacun dans un segment mémoire séparé.
Contiki (Dunkels et al., 2004; Dunkels et al., 2006) est un système reconfigurable modulaire pour
réseaux de capteurs. Contiki est organisé en modules, une architecture plate. Un coeur non-reconfigurable
permet de (télé-)charger les modules (applications ou sous-systèmes), qui constituent alors l’unité de
reconfiguration dans Contiki. Un modèle d’exécution événementiel permet une implémentation efficace
d’un état stable pour les modules. L’approche SOS (Han et al., 2005) est similaire à Contiki.
Finallement Maté (Levis & Culler, 2002) est une machine virtuelle construite avec TinyOS. Les applications Maté sont construites avec un ensemble restreint d’instructions de la machine virtuelle, arrivant
à des applications très compactes. Le système permet uniquement une mise-à-jour d’applications de la
machine virtuelle. De cette façon, l’approche Maté optimise l’utilisation de la ressource la plus critique
– la consommation d’énergie de l’interface radio. Par contre, dû à l’approche de machine virtuelle, Maté
présente un impact sur les performances d’un système. Egalement, cette approche ne permet pas une reconfiguration à grain fin, notamment des couches de service, et ne sauvegarde pas l’état d’une application
à la reconfiguration.
Canevas de construction de systèmes à la carte Les canevas (framework) de construction de systèmes
permettent de construire des système à la carte. Pour la plupart il s’agit de systèmes à composants –
composants uniquement comme une notion à la conception par conséquent non-reconfigurables, comme
OSKit (Ford et al., 1997; Reid et al., 2000) ou eCos (eCos, n.d.), ou également composants à l’exécution
qui permettent une reconfiguration du système – MMLite (Helander & Forin, 1998; Forin et al., 2001)
ou Think (Sénart, 2003; Charra, 2004; Senart et al., 2002).
MMLite est système à composants, implémentant le modèle COM. Dans MMLite un composant
implémente une interface et ses dépendences sont bien identifiés ce qui permet de bâtir des algorithmes de
détection d’un état quiescent (MMLite est un système multi-threadé) à l’aide de comptage de références
(read-write locks).
Les travaux récents par A. Sénart et O. Charra revisitent le canevas à composants Think original
pour se baser sur le modèle à composants Fractal. Ainsi, Think à travers les interface de contrôle Fractal
défini une interface de programmation de reconfigurations. Cependant, ces travaux ne considèrent pas
l’implémentation d’un état stable, ni la programmation pratique des reconfigurations tel que présentés
dans ce travail.
2.2.2
Modèles d’architecture
La notion d’architecture est relative à un état de l’art, une pratique, de construction de logiciels
(ou systèmes) et dépend du niveau d’abstraction choisi. Par exemple, peut-on considérer la structure
offerte par le langage C comme une architecture ? Oui à la conception, mais cette structure disparaı̂t à
l’exécution. De la même manière, un micro-noyau défini également une architecture du système.
Parmi l’ensemble des définitions de l’architecture logicielle, nous empruntons celle donnée par Bass
et al. (Bass et al., 1998) : ”The software architecture of a program or computing system is the structure
or structures of the system, which comprise software elements, the externally visible properties of those
elements, and the relationships among them.” Cette définition met en évidence une structure du logiciel
et la relation explicite établie entre ses éléments.
La notion d’architecture permet de définir les mécanismes de la reconfiguration pour identifier une
partie de l’architecture et pour la modifier.
Dans les systèmes embarqués nous pouvons considérer l’architecture à plusieurs niveaux. Au premier
niveau, l’architecture du système ou son organisation interne à gros grain. Au second plan, architecture
13
2.2. Systèmes d’exploitation reconfigurables
Chapitre 2. Etat de l’art
logicielle ou style d’architecture, notion dévelopée par Garlan et Shaw (Garlan & Shaw, 1994; Shaw &
Garlan, 1996).
2.2.2.1
Architecture système
L’architecture du système défini son organisation, en particulier la relation entre le système (d’exploitation) et les applications. Il existe plusieurs architectures de systèmes :
– systèmes à protection unique – le système et l’application partagent le même domaine de protection
(par exemple DOS ou PalmOS (aujourd’hui Garnet OS) (PalmOS, n.d.)),
– noyaux monolithiques – le système est constitué d’un seul bloc sans architecture apparente (les
premières versions de Unix, Linux ou Windows),
– micro-noyaux – un système minimal fourni une abstraction minimale de la machine sous-jacente et
un mécanisme de communication – Inter Process Communication (IPC) (Liedtke, 1996; Liedtke,
1995), le reste du système étant implémenté comme un ensemble de serveurs dans des espaces
d’adressage et de protection différents, communicant via des IPCs. Les applications utilisateurs
sont implémentées de la même manière et demandent service aux processus serveurs par des IPCs
(par exemple L4, QNX, Chorus, µChoices et beaucoup d’autres, les hyperviseurs comme Xen
(Barham et al., 2003) sont des cas particuliers de cette architecture),
– exonoyaux – un exokernel élimine toutes les abstractions du noyau et se limite au multiplexage
et à la protection des resources, tout les services systèmes sont implémentés sous forme de bibliothèques.
2.2.2.2
Architecture logicielle
Parmi les différents styles d’architecture logicielle, tels que définies par Garlan et Shaw (Garlan &
Shaw, 1994; Shaw & Garlan, 1996) nous comptons par exemple :
– structuration en couches – système historique THE (Dijkstra, 1968),
– structuration orientée objet – le système Choices ou µChoices, ou K42,
– structuration orientée composant (ou module) – pratiquement tous les systèmes modernes tombent
dans cette catégorie – SPIN, VINO ou encore MMLite. Le µ-noyau Pebble est un système à
composant, tout comme les systèmes construits avec le canevas à composants Think.
– structure orientée événément,
– structure orientée flot de donnée – les systèmes x-Kernel (Hutchinson & Peterson, 1991) ou Click
(Morris et al., 1999).
2.2.2.3
Architecture à composants
Le contexte de cette thèse sont les systèmes embarqué à composants.
Un composant est défini comme suit (Szyperski, 2002) : ”Un composant logiciel est une unité de
composition avec des interfaces spécifiées contractuellement et des dépendances de contexte explicites.
Un composant peut être déployé indépendamment et être composé par des tiers pour former des applications ou des composants composites.3 ”. Par rapport aux modules, un composant peut être instancié et
les composants peuvent être assemblés de manière hiérarchique et dynamique. Par rapport aux objets, un
composant définit explicitement ses dépendences, permettant de répondre aux besoins de configuration
logicielle et de déploiement.
Ainsi, un système à composants défini les entités architecturales (composants) et les relations entre
ces entités (dépendans et liaisons).
3
A component is a unit of composition with contractually specified interfaces and fully context dependencies that can be
deployed independently and is subject to third-party composition
14
Chapitre 2. Etat de l’art
2.2.2.4
2.3. Synthèse
Description architecturale des systèmes
L’architecture d’un système peut être décrite à l’aide de langages spécifiques comme des ADL (Architecture Description Language) – (Medvidovic et al., 2007) (xADL (Dashofy et al., 2001), AADL
(SEA-AADL, n.d.), ACME (Garlan et al., 2000), Rapide (Luckham et al., 1995), Wright (Douence et al.,
1997), ...) – ou d’autres abstractions comme UML (OMG, 2004; Bell, 2003), DCUP (Plásil et al., 1998).
Cette description d’architecture peut avoir des fins variées – une documentation du système, ou son design indépendant de l’implémentation (le cas historique d’UML modélisant une architecture à objets),
ou servir au déploiement du système (Darwin (Magee et al., 1995), Olan (Balter et al., 1998)), ou dans
d’autre cas servir à construire, ou assembler, le système (le cas des canevas de construction de systèmes
comme eCos avec CDL (eCos, n.d.) ou OSKit avec Knit (Ford et al., 1997; Reid et al., 2000)).
2.3
Synthèse
La notion de configuration désigne la capacité de personaliser un système lgociel. Cette notion englobe à la fois une capacité de personalisation pendant la conception, aussi bien qu’à l’exécution –
reconfiguration dynamique. Il existe plusieurs études de systèmes configurables, notamment Stankovic
et al. (Friedrich et al., 2001) ou Denys (Denys et al., 2002), le dernier classifiant les systèmes selon deux
dimensions, suivant le moment de l’adaptation et suivant l’initiateur de celle-ci. Quant à Sénart (Sénart,
2003) ou Ketfi et al. (Ketfi et al., 2002), ils proposent une classification des mécanismes de la reconfiguration dynamique suivant les capacités offertes (l’objet de la reconfiguration, le moment, l’initiateur, le
type etc.).
Classer les systèmes embarqués uniquement suivant les dimensions de la reconfiguration dynamique
est reducteur, car souvent la conception des mécanismes de reconfiguration dynamique impacte profondément la conception du système en général. Pour analyser les systèmes reconfigurables par rapport
à nos objectifs décrit au chapitre 1-1.4, nous nous sommes inspirés des critères établis d’une part par
Hicks (Hicks, 2001; Hicks & Nettles, 2005) et d’autre part par Tournier (Tournier, 2005b), à savoir :
– flexibilité des mécanismes de reconfiguration – granularité, les différents types de reconfiguration
possibles (composants, liaisons etc.), indépendance et optionalité des mécanismes,
– impact sur les performances du système, ou l’efficacité du système reconfigurable,
– garanties offertes par le système reconfigurable quant à la reconfiguration dynamique (fiabilité,
sûreté, sécurité, robustese etc.),
– simplicité d’utilisation (subjectif) ou concrétement le degré et la compléxité de l’outillage permettant de maı̂triser la complexité de conception de systèmes reconfigurables et des reconfigurations.
Les résultats de cette analyse sont reportés sur le tableau 2.3.4.
2.3.1
Flexibilité
– Objet de reconfiguration ou Qu’est-ce qui peut être reconfiguré dans un système reconfigurable ?
– Une partie du système à un grain élevé (comme par exemple un driver complet) ou plus finement
des sous-parties plus ou moins complexes, voire des types de données C et leurs instances ? Est-ce
que le système entier peut être reconfiguré ou uniquement une partie du système peut être modifiée
– cas des systèmes ayant une couche minimale non-reconfigurable.
Ici nous identifions deux sous-critères : le grain d’objets reconfigurables et si le système entier
peut être l’objet d’une reconfiguration.
– Quelles sont les différentes évolutions possibles d’une architecture ? Une reconfiguration n’est
pas forcément un remplacement 1-à-1 d’une partie de l’architecture. Par exemple, dans le cas d’une
architecture à composants, une reconfiguration peut remplacer un composant par un composant
15
2.3. Synthèse
Chapitre 2. Etat de l’art
ayant une dépendances supplémentaire. Pour satisfaire la dépendence, la reconfiguration peut alors
ajouter un nouveau composant à l’architecture.
– Indépendance des mécanismes de la conception du système Il n’existe pas un mécanismes universel répondant à toutes les exigeances d’efficacité, flexibilité etc. Par conséquent un système
reconfigurable pourrait offrir plusieurs mécanismes, adaptés aux besoins du système (pouvant
évoluer au cours du temps).
– Optionalité L’implémentation des mécanismes de reconfiguration, en particulier l’implémentation
de la détection d’un état stable ou quiescent, ont un impact considérable sur les performances d’un
système. Un système pourrait inclure les mécanismes de reconfiguration (par exemple des intercepteurs) uniquement là où c’est réellement nécéssaire ou spécifié par l’utilisateur – les mécanismes
de reconfiguration seraient alors optionnels.
Objet de reconfiguration Le grain de reconfiguration qu’un système autorise dépend fortement de son
architecture :
– les systèmes dont les mécanismes sont conçus au niveau langage d’implémentation (i.e. fonctions,
types de données etc.) offrent le grain de reconfiguration le plus fin – SPIN, VINO et DYMOS,
– les systèmes qui ont une architecture à grain fin, comme les systèmes à composants ou des objets,
– finalement les systèmes modulaires qui permettent une reconfiguration à gros grain - modules,
applications (pour Maté ou systèmes pour réseaux de capteurs) ou serveurs systèmes pour les
micro-noyaux.
Pour la plupart, les systèmes analysés ne sont pas entièrement reconfigurable :
– En principe, avec les mécanismes appropriés, les systèmes construits avec Deimos, MMLite et
Think ne présentent pas de couche minimale non-reconfigurable et donc toute partie d’un système
construit à l’aide de ces canevas peut être objet d’une reconfiguration.
– Les autres systèmes sont consistitués d’une couche minimale non-reconfigurable à laquelle les
mécanismes de reconfiguration ne sont pas applicables.
Evolutions d’architecture Nous distinguons plusieurs catégories de systèmes qui autorisent l’évolution
de leur architecture logicielle. Cette capacité est fortement lié à la définition de l’architecture dans chaque
système considéré :
– Les systèmes à objets ou composants – Think, MMLite, K42, Deimos, Apertors – peuvent faire
évoluer leur architecture interne en autorisant la modification des liaisons entre objets (ou composants) et en autorisant l’évolution des définition d’interface des objets (ou composants).
– Dans les systèmes à architecture figée à gros grain – micro-noyaux, FlexCup, Contiki, SOS – les
modules implémentent des interfaces systèmes représentant des services bien définis, des contrats.
L’évolution de cette architecture ne représente pas l’objecitf de ces systèmes.
– Dans Maté, les reconfigurations consistent à remplacer une application complète (donc son architecture complète), par conséquent les mécanismes offerts par Maté offrent moins de flexibilité par
rapport à d’autres systèmes reconfigurables.
– Les systèmes extensibles, tels que SPIN ou VINO, autorisent un ajout de code dans le système.
VINO et SPIN autorisent le changement d’une partie de l’architecture grâce aux extensions, l’architecture du coeur du système restant inchangée. Dans DYMOS l’architecture du système sont
les éléments du langage Modula et ne peuvent être changés. DYMOS autorise la modification des
fonctions existantes, mais non l’évolution de l’architecture. Cependant, les mécanismes de reconfiguration basés sur l’utilisation d’un langage, comme proposé par Hicks (Hicks & Nettles, 2005),
peuvent éventuellement offrir des fonctionnalités de réécriture et restructuration du code où il n’y
a aucune restriction quant à l’évolution d’une architecture.
16
Chapitre 2. Etat de l’art
2.3. Synthèse
Indépendance des mécanismes de la conception du système Dans la plupart des systèmes les mécanismes pour la reconfiguration dynamique sont fortement dépendant de la conception du système et
le système propose uniquement un seul ensemble de mécanismes (par example un mécanisme pour la
détection d’un état stable/quiescent) :
– MMLite implémente plusieurs mécanismes gérant l’état d’un composant pendant sa reconfiguration. Entre autres MMLite implémente le mécanisme de comptage de référence.
– La conception des interfaces de contrôle du modèle Fractal appliqué au canevas Think laisse supposer l’indépendance des différentes implémentations. Nous confirmons cette hypothèse dans le
chapitre 4.
Optionalité des mécanismes Les mécanismes de reconfiguration ont un impact sur les performances
du système. Par conséquent un système où les mécanismes sont implémentés sélectivement (là où besoin)
permet de réduire cet impact sur les performances :
– Pour détecter un état quiescent, K42 implémente des intercepteurs dynamiques, introduits uniquement pendant la reconfiguration. Ces intercepteurs sont génériques, par conséquent en dehors de la
reconfiguration, un composant ne paie aucune surcoût lié à la capacité de reconfiguration et cette
implémentation peut être considérée comme facultative.
– Les mécanismes sont optionnels dans MMLite.
– Pour les autre systèmes, les mécanismes sont figés et inclus à la conception du système, voire obligatoire pour les systèmes refléxifs, car la reconfiguration est le concept de base de ces systèmes.
2.3.2
Efficacité
Les mécanismes de reconfiguration ont un impact sur les performances du système reconfigurable –
sur les performances nominales, sans reconfiguration, et sur les performances pendant la reconfiguration.
Chaque système prend en compte de façon diverse les critères de performance – temps d’exécution (ou
le temps de calcul), l’occupation de l’espace mémoire, l’utilisation de l’énergie (en rapport avec le temps
de calcul), les temps de réponses, l’utilisation de la bande passante etc.
L’efficacité est un bon critère de comparaison, cependant les systèmes étudiés divergent dans leur
conception (et leur but) et il est nécéssaire d’analyser chaque système en profondeur pour en tirer des
éléments de comparaison. De plus, ces systèmes implémentent différents mécanismes de reconfiguration
ce qui accroı̂t la dispersion.
Par conséquent nous résumons uniquement quelques remarques :
– DYMOS implémentent un système complexe de verrouillage à l’entrée et sortie de chaque méthode
qui est une source de dégradation de performances. Les reconfigurations dans DYMOS sont compilées à l’exécution par le système lui-même.
– VINO implémente modifie les grafts avec l’outil MiSFIT pour inclure des vérifications à l’exécution.
– Dans SPIN, les spindles sont compilés à l’exécution par un compilateur inclus dans le système.
– Maté est une machine virtuelle, donc par sa conception comprend un surcoût lié à l’exécution du
byte-code.
– La discussion sur l’impact d’IPCs sur les performances des micro-noyaux est ancienne (Liedtke,
1993; Haertig et al., 1997).
2.3.3
Garanties
La reconfiguration dynamique affecte le code et les données d’un système d’exploitation. Une reconfiguration peut être source d’erreurs et ammener le système à défaillir :
17
2.3. Synthèse
Chapitre 2. Etat de l’art
– le nouveau code instantié par la reconfiguration peut être défaillant, causant des erreurs,
– le nouveau code peut intéragir avec le reste du système ne respectant pas les spécifications,
– un transfert d’état incomplet peut corrompre l’état du système, par exemple les nouvelles données
instantiées par la reconfiguration peuvent être mal initialisées,
– les mécanismes de reconfiguration peuvent être exploités par des tiers, pour faire défaillir le
système (en ajoutant un code défectueux ou en corrompant les données),
– le programme de reconfiguration lui-même peut être défaillant et peut abandonner le système dans
un état non-cohérent, par exemple où la reconfiguration ne satisfait pas toutes les dépendances
d’une partie du système, ou un nouveau module est incomptabile avec le reste du système,
– ...
Par conséquent, il est nécéssaire qu’un système reconfigurable garantisse un certain nombre de propriétés par rapport à la conception des mécanismes de reconfiguration et la programmation des reconfigurations, de façon à fiabiliser le système et le processus de reconfiguration.
Alors que la liste exacte des garanties dépend du système, de son architecture et des capacités de
reconfiguration qu’il offre, on peut dégager trois garanties majeures :
– cohérence de l’architecture – l’architecture du système après reconfiguration soit cohérente par
rapport à sa spécification,
– le nouveau module est valide suivant une liste de critères établis par le système, en particulier le
système garantit que son fonctionnement est correct (fiabilité),
– les mécanismes de reconfiguration ne peuvent pas être détournés pour faire défaillir le système
(sécurité).
Cohérence architecturale
– Les systèmes qui n’autorisent aucune évolution de l’architecture n’ont pas la nécéssité d’offrir
cette garantie.
– Les systèmes qui autorisent une évolution de l’architecture au cours d’une reconfiguration garantissent au moins la cohérence architecturale du système.
Fiabilité
– Dans SPIN, les spindles sont écrits en Modula et un compilateur garantie leur validité.
– Dans VINO, les grafts sont modifiés pour inclure des vérifications à l’exécution qui empêche
typiquement à une extension d’exécuter ou modifier le code système de manière non-autorisée (ce
qui induit un coût).
– La machine virtuelle Maté interprète un byte-code et par conséquent son exécution est soumise à
validation.
– Les autres systèmes ne font pas de garanties de sûreté des extensions ou du système.
2.3.4
Outils
Pour être utilisés (et pour minimiser le risque d’erreurs), la construction des systèmes reconfigurables
et l’écriture des reconfigurations doivent être simples à utiliser. La notion de simplicité étant intuitive et
subjective4 , nous nous intéréssons au degré d’outillage des systèmes reconfigurables. Le rôle de l’outillage est d’autant plus important pour les systèmes construits à la carte.
Nous avons considéré les outils qui assistent le concepteur du système dans la construction du
système, mais également dans le programmation des reconfigurations. Il y a peu d’informations concernant les outils associés aux différents systèmes, par conséquent dans plusieurs cas nous avons supposé
leur existance.
4
mais importante !
18
Chapitre 2. Etat de l’art
2.3. Synthèse
– Les systèmes qui inclus un compilateur d’extensions (evtl. à l’exécution) – DYMOS, SPIN ou
VINO – offrent des outils nécéssaires pour à la fois construire un système et programmer sa reconfiguration.
– Dans le cas de Maté, le compilateur de programmes pour la machine virtuelle est suffisant pour
construire le système et pour construire les reconfigurations.
– A notre connaissance les autres systèmes ne fournissent qu’un compilateur permettant de construire ces systèmes, mais non leur reconfigurations.
K42
Synthetix
µ-kernels, Kea
DYMOS
SPIN
VINO
Deimos
Apertos, Muse
MetaOS
FlexCup
Maté
Contiki, SOS
MMLite
Think
g
**
**
*
***
***
***
**
**
**
*
*
**
**
**
Flexibilité
e
i
***
** ?
**
*
**
**
***
***
***
**
**
√
?
***
√
***
Efficacité
o
√
?
√
?
-
t
?
-
√
√
√
-
√
√
?
?
-
√
√
√
-
?
√
√
√
Garanties
a
f
√
√
√
√
√
√
√
√
√
√
√
√
-
Outils
*
**
*
***
***
***
*
*
*
**
***
*
*
*
Légende
abbréviations Flexibilité
abbréviations Garanties
g – grain
a – cohérence architecturale
e – évolution architecturale
f – fiabilité
o – optionalité des mécanismes
t – tout système reconfigurable
i – indépendances des mécanismes de la conception du système
évaluation des systèmes
***,**,* qualité
√
la fonctionnalité existe ou la contrainte est garantie
?
aucune information
rien (-)
fonctionalité probablement possible, mais ne représente
pas le but du système, aucune information
TAB . 2.1 – Les systèmes d’exploitation reconfigurables – synthèse.
19
2.4. Conclusion
2.4
Chapitre 2. Etat de l’art
Conclusion
Comme le présente ce chapitre, l’ensemble des choix et critères d’implémentation d’un système
reconfigurable est vaste. Le choix d’une architecture pour un système détermine grandement ses capacités de reconfiguration. De plus, le choix du modèle d’exécution déterminera pour la grande partie
l’implémentation d’un état stable – mécanisme coeur de la reconfiguration dynamique, mais également
le mécanisme dont l’implémentation peut avoir le plus d’impact sur les performances du système. Les
critères associés à l’évaluation des systèmes d’exploitation et des mécanismes de reconfiguration forment
des contraintes très fortes et variées.
Par rapport à nos objectifs, nous constatons que chaque système fige un mécanisme de reconfiguration. Ce mécanisme est étroitement lié à la conception du système et n’est pas optionnel, ce qui implique une dégradation de performances. Ce constat guide notre proposition d’une approche de construction de systèmes reconfigurables à la carte et leurs reconfigurations – l’objectif principal de notre approche, que nous présentons dans les chapitres suivants, est de proposer un modèle de programmation
indépendant d’un système concret et d’un mécanisme concret, avec des outils sous-jacents, qui permettent de construire des systèmes reconfigurables à la carte et également leurs reconfigurations.
20
Deuxième partie
Contributions
21
Chapitre 3
Vers un modèle de construction de
systèmes reconfigurables
La contribution de nos travaux consiste à définir un modèle pour à la fois construire à la carte des
systèmes reconfigurables et programmer les reconfigurations de tels systèmes. L’élément central de notre
approche est l’architecture du système, donnée par un modèle à composants qui donne une représentation
manipulable du système.
– L’utilisation d’un modèle à composants nous permet de construire des systèmes reconfigurables à
la carte, de manière flexible.
– L’analyse de l’architecture du système, telle qu’écrite par le concepteur, permet d’intégrer au
système l’implémentation d’une interface de reconfiguration et donc des mécanismes de reconfiguration, portés par les composants.
– Les reconfigurations dynamiques sont programmées comme les modifications de l’architecture.
Par conséquent leurs validité peut être vérifiée uniquement en analysant l’architecture du système.
La figure 3.1 montre cette approche.
spécification
système
construction
système
système
d'exploitation
exécution
méta-données
pour la reconfiguration
architecture
spécification
reconfiguration
construction
reconfiguration
programme de
reconfiguration
reconfiguration
F IG . 3.1 – Notre proposition d’un modèle de programmation de systèmes reconfigurables, articulé autour
d’une architecture du système à composants.
Dans ce chapitre nous décrivons notre approche. Nous nous intéressons d’abord aux concepts fondamentaux de la reconfiguration dynamique qui ont motivé notre contribution. Ensuite nous décrivons les
grands traits de notre proposition et leur articulation, pour finalement terminer avec la description des
fondements de l’approche – à savoir le modèle à composants F RACTAL et son implémentation appelée
T HINK.
23
3.1. Concepts fondamentaux de la reconfiguration dynamique
3.1
Chapitre 3. Aperçu de la contribution
Concepts fondamentaux de la reconfiguration dynamique
Déroulement d’une reconfiguration Intuitivement, une reconfiguration dynamique se déroule de la
manière suivante (illustré également sur la figure 3.2), il faut :
– identifier et délimiter la partie du système à reconfigurer [ident],
– suspendre son exécution (pour éviter de corrompre le système) [suspd] ,
– modifier la configuration du système (ajouter, supprimer des parties...) [modif],
– transferer l’état vers les nouvelles parties [transf], et
– reprendre l’exécution de la partie interrompue du système [resum].
ident
B
B
suspd
A
A
C
C
modif
D
D
B
B
A'
resum
A'
modif
transf
A
C
C
F IG . 3.2 – Déroulement d’une reconfiguration : ident - identification de la partie à reconfigurer, suspd suspension de l’exécution de cette partie, modif - modification de l’architecture, transf - transfer d’état
vers les instances de l’architecture, et resum - reprise d’exécution.
De cette définition intuitive du déroulement de la reconfiguration découle un certain nombre d’opérations
et de mécanismes de base de la reconfiguration dynamique que nous étudions dans cette partie :
– un modèle d’architecture – permettant d’effectuer les opérations ident et modif, et
– un modèle permettant de capturer et contrôler l’état du système – permettant d’effectuer les
opérations suspd/resum et transf.
3.1.1
Architecture et la reconfiguration dynamique
Identification et délimitation Une architecture logicielle du système est le fondement de la reconfiguration dynamique. Elle permet à la fois d’identifier la partie du logiciel à l’exécution, que nous
appellerons composant, à reconfigurer, ainsi que de ”délimiter” ce composant (component boundaries).
La représentation de l’architecture à l’exécution (et donc la capacité de pouvoir identifier un composant
à l’exécution) est essentielle.
24
Chapitre 3. Aperçu de la contribution
3.1. Concepts fondamentaux
Pour délimiter un composant, il est nécéssaire de localiser le code, les données et les composants qui
peuvent les accéder ou modifier. En d’autres termes, un composant reconfigurable doit encapsuler ses
données self-contained et il doit être possible d’identifier les points d’accés aux services (fonctions) qu’il
offre (well-defined access points).
Modifications architecturales Pour pouvoir modifier l’architecture d’un système, il est nécéssaire de
pouvoir rediriger les appels entre les composants de l’architecture, par exemple, lors d’un remplacement
de composant, il faut rediriger tous les appels vers le nouveau composant. En général, une architecture
faiblement couplée permet de réaliser la redirection des appels – les modules étant liés par une indirection, il suffit de changer la liaison entre les modules (Ghormley et al., 1998; Soules et al., 2003).
De plus, comme nous allons le voir dans la section suivante, la connaissance de dépendence entre les
élements est fondamentale pour pouvoir contrôler l’état d’exécution d’un composant.
3.1.2
Etat et la reconfiguration dynamique
Une reconfiguration, i.e. la modification de données et/ou du code d’une partie du système, ne peut
avoir lieu alors que celle-ci peut être accédée de façon concurrente – il faut garantir que les données de
la partie du système à modifier ne sont pas en train d’être modifiées et que le code de cette partie ne peut
pas s’exécuter pendant la reconfiguration (sous risque de comportement imprévisible et corruption du
système).
Par conséquent il est nécéssaire de connaı̂tre l’état du système. Nous définissons l’état comme un vecteur de variables observables – un ensemble de propriétés mesurables à un instant donné qui caractérise
une situation du système (?). Cette définition comprend deux notions :
– l’état interne de la partie du système à reconfigurer – les données internes (variables et ressources),
et
– l’état de contrôle lié au modèle d’exécution du système, par exemple l’état de la pile dans les
système multi-thread.
L’état d’un système évolue suivant une dynamique décrite en partie dans le programme (modèle
de programmation) et en partie décrite par un modèle d’exécution. Par exemple, le modèle d’exécution
multi-thread spécifie que les threads évoluent de manière concurrente et peuvent se synchroniser à l’aide
de points de synchronisation (sémaphores). A l’opposé, un modèle événementiel organise l’exécution
comme un traitement d’événements indépendent et ne spécifie rien quant à l’évolution concurrente ou
l’ordre d’exécution des événements (spécifié par une politique d’ordonnancement). L’annexe B décrit les
deux modèles d’exécution événementiel et multi-thread.
Cette définition d’état permet alors de définir les deux autres opérations de la reconfigurations dynamique :
– la suspension de l’exécution d’une partie du système (ou sa reprise), comme la détection d’un état
stable, et
– le transfert d’état entre parties du systèmes.
Etat stable et modèle d’exécution L’état stable est un état dans lequel le système (ou une partie du
système) n’évolue pas – l’état est alors observable. Typiquement, dans un système multi-processus, une
partie du système est dans un état stable, lorsqu’elle n’est accédée par aucun thread.
Pour pouvoir caractériser un état stable d’un système (ou d’une partie), il faut prendre en compte
sa dynamique d’exécution, définie par le modèle d’exécution. Suivant le modèle, un état stable peut
être obtenu par construction (modèle événementiel décrit dans le chapitre 7) ou peut être obtenu par
25
3.2. Aperçu de la contribution
Chapitre 3. Aperçu de la contribution
détection à l’exécution, par exemple dans le modèle multi-thread. Dans ce dernier cas, l’état stable est
un état quiescent, voir également la discussion détaillée en annexe B.
Transfert d’état Le transfert d’état est l’opération qui permet de récuperer l’état interne d’une partie
du système à reconfigurer et l’injecter dans une nouvelle instance.
L’état interne (données) d’une partie d’un système peut être complexe, allant d’un ensemble d’attributs, jusqu’à des structures compliquées comme par exemple les listes de processus bloqués sur un
sémaphore. Chaque partie du système défini la sémantique de son état et la façon à laquelle cet état est
maintenu (format). Par exemple, dans le cas du sémaphore, la nouvelle implémentation peut maintenir
son état dans un tableau alloué statiquement (format), avec par exemple plus d’informations concernant
les processus, informations non-disponibles dans l’état actuel (sémantique). Dans ce cas, le transfert
d’état n’est pas uniquement une correspondance 1-à-1 et nécéssite une intervention du programmeur
de reconfiguration pour transformer l’état (format et sémantique). La transformation du format peut
nécéssiter un passage par un format commun (ou générique) aux deux composants, à partir de ce format,
des mécanismes complexes de correspondance de format et sémantique pourraient être bâtis (en utilisant
des langages spécialisés par exemple).
Par conséquent pour effectuer un transfert d’état, il est nécéssaire de :
– disposer d’une spécification de ce qu’est l’état d’un composant – l’ensemble relevant des variables
observables (format et sémantique),
– pouvoir accéder à l’état du composant (pour le récupérer ou l’initialiser),
– pouvoir accéder à cet état de manière cohérente, lorsque le composant est dans un état stable,
– transformer (éventuellement) cet état pour qu’il soit conforme aux spécifications du nouveau composant (format et/ou sémantique).
Un mécanisme de haut-niveau peut être bâti pour automatiser les transformations de format ou
sémantiques lors d’un transfert d’état. Un tel mécanisme nécéssite uniquement une interface de bas
niveau d’accès à l’état interne du composant.
3.2
Aperçu de la contribution
Concrétement notre approche se base sur le modèle à composant F RACTAL (Bruneton et al., 2006;
Bruneton et al., 2004) et sur son implémentation en C appelée T HINK, permettant de construire à la
carte des systèmes embarqués à composants (Fassino et al., 2002; Fassino, 2001). Un systèmes à base
de composants T HINK ne requièrt aucun environment d’exécution supplémentaire – tout est composant.
De plus un composant F RACTAL/T HINK représente à la fois une entité de conception et une entité à
l’exécution, donnant ainsi la possibilité de manipuler l’architecture à l’exécution.
Par rapport à d’autres modèle existants (comme EJB (DeMichiel & Keith, 2006), CCM (OMG, 2001;
OMG, 2002), OpenCOM (Clarke et al., 2001) et d’autres), Fractal présente plusieurs avantages qui ont
conduit à son adoption comme base de nos travaux :
– F RACTAL est un modèle à composant minimal et extensible, où tout concept est optionnel, visant
à construire des systèmes flexibles.
– Le concept des interfaces de contrôle permet de séparer les aspects fonctionnels des aspects nonfonctionnels, telle la reconfiguration dynamique, et permet d’implémenter différents mécanismes
de reconfiguration de façon indépendente et transparente à l’utilisateur (partie fonctionnelle du
composant).
– Le modèle est réflexif, en particulier, un composant Fractal est une entité à l’exécution, donc
identifiable lors de la reconfiguration dynamique. La réflexivité permet de retrouver et manipuler
l’architecture d’un système pendant son exécution.
26
Chapitre 3. Aperçu de la contribution
3.2. Aperçu de la contribution
– Le modèle est hiérarchique – les composants peuvent contenir d’autres sous-composants, permettant de construire des mécanismes de reconfiguration avec des périmètres différents (par exemple
au niveau d’une application entière, construite comme un composant composé d’autres composants, ou au niveau d’un composant de base).
– Il existe plusieurs implémentations de F RACTAL, en particulier le canevas de construction de
systèmes embarqués flexibles appelé T HINK. T HINK n’impose aucune philosophie prédeterminée
de système (micro-noyau, monolithique ou exo-noyau) et son empreinte mémoire permet de construire des systèmes pour les réseaux de capteurs (Jarboui et al., 2006a).
– Le canevas T HINK est accompagné d’un compilateur extensible (Ozcan, 2007; Leclercq et al.,
2007) qui constitue un embryon d’un outil permettant l’intégration des aspects liés à la reconfiguration dans le processus de construction de systèmes.
– Il existe une bibliothèque de composants T HINK, appelée Kortex, pour la construction des systèmes
d’exploitation.
– Récemment un langage de reconfiguration des architectures F RACTAL a été défini et implémenté.
Ce langage, appelé FS CRIPT permet d’écrire les reconfigurations sous forme d’un programme
impératif, manipulant les éléments du modèle F RACTAL (composants, liaisons, interfaces, ...).
Dans notre approche, la reconfiguration dynamique consiste à modifier l’architecture F RACTAL d’un
système à l’exécution, par conséquent avec cette approche nous autorisons plusieurs types de reconfigurations architecturales :
– Modification de liaisons. Dans une architecture Fractal, nous pouvons alterer les liaisons – soit
mettre en place une nouvelle liaison ou la supprimer (dans le cas de liaisons optionnelles), soit
rediriger la liaison vers une autre interface (d’un autre composant).
– Modification d’attributs. Dans Fractal, les attributs de composants sont des éléments d’architecture. Lors d’une reconfiguration, le programmeur peut être ammené à changer un attribut d’un
composant.
– Création de composants. Les composants Fractal peuvent être instanciés à partir des usines de
composants. Un système à l’exécution peut contenir des usines de composants (elles-mêmes des
composants). Dans notre proposition, en plus des usines embarquées dans le système, une instance
de composant peut être téléchargée pendant la reconfiguration. Un composant nouvellement créé
doit être intégré à l’architecture. Le programmeur peut l’insérer dans un autre composant et créer
(ou modifier) les liaisons de ce composant.
– Suppression de composant. A l’exécution, il est possible de supprimer un composant Fractal. La
suppression entraı̂ne la modification ou la suppression des liaisons du composant parent.
– Remplacement de composant. Le remplacement d’un composant est la combinaison de l’ajout d’un
nouveau composant et de la suppression d’un autre composant. Le nouveau composant doit fournir
les mêmes interfaces serveur que le composant à remplacer. L’état encapsulé par le composant à
supprimer peut être transféré vers le nouveau composant.
Par conséquent, avec notre approche, il n’y a pas une reconfiguration dynamique, mais des reconfigurations dynamiques – deux reconfigurations du système peuvent différer, par exemple une reconfiguration
ajoute un composant et le lie au reste de l’architecture, une autre reconfiguration remplace un composant
existant, sans modifier les liaisons.
Interface de reconfiguration Le modèle F RACTAL, à travers les interfaces de contrôle (voir section 3.3.1), permet de séparer les aspects fonctionnels des aspects non-fonctionnels d’une architecture. Nous définissons une interface de programmation de reconfiguration comme un ensemble d’interfaces de contrôle Fractal implémentées par les composants reconfigurables. Ces interfaces permettent
d’implémenter les mécanismes de détection d’un état stable, de transfert d’état etc.
27
3.2. Aperçu de la contribution
Chapitre 3. Aperçu de la contribution
Construction de systèmes reconfigurables à composants Pour faire face à la complexité de construction de systèmes à la carte, en plus avec une interface de reconfiguration, nous avons implémenté un
compilateur permettant de contruire des systèmes à composants reconfigurables. En réalité, nous avons
enrichi le compilateur existant. L’utilisateur spécifie les composants reconfigurables et le compilteur
transforme l’architecture pour y inclure l’implémentation d’une interface de reconfiguration.
Programmation des reconfigurations Le code de reconfiguration utilisant notre interface de reconfiguration peut être écrit en C. Cependant, un tel code peut être complexe, répétitif et difficile à maı̂triser,
car le langage C est de trop bas niveau par rapport à la programmation des reconfigurations. Afin de
palier à ces problèmes nous utilisons le langage de reconfiguration appelé FScript (David & Ledoux,
2005), qui permet de manipuler une architecture à composants F RACTAL.
La seule analyse de l’architecture du système permet de valider le programme de reconfiguration.
Nous avons mis au point un compilateur de programmes FScript (à l’origine FScript vient avec un
interprète en Java) et un support d’exécution minimal qui autorisent l’utilisation de FScript même dans
les environements très contraints en ressources, tels les réseaux de capteurs. Le compilateur FScript est
réalisé comme une extension du compilateur Think et réutilise l’interprète original de FScript.
Rôles du cycle de vie L’utilisation d’un modèle à composants permet la séparation de préoccupations
entre la conception du système et son implémentation, i.e. l’implémentation des composants. De la même
manière, l’utilisation de FScript permet la séparation des préoccupations entre la programmation des
reconfigurations comme modifications de l’architecture et l’implémentation du système.
Par conséquent, il est possible d’identifier trois rôles différents dans le cycle de vie d’un système
reconfigurable :
– programmeur de bas niveau, implémentant des parties du système à partir de leur spécification,
i.e. implémentant les composants,
– concepteur du système, et
– programmeur de reconfigurations, tous deux ayant une visions architecturale du système.
3.2.1
Limitations
La reconfiguration dynamique étant un problème complexe, nous avons voulu proposer une interface de bas-niveau suffisamment riche et puissante au-dessus de laquelle il serait possible de bâtir des
mécanismes plus complexes. En particulier,
– nous considérons qu’un mécanisme de transfert d’état sophistiqué peut être bâti au-dessus des
primitives d’accès à l’état telles que nous les avons définies,
– les compilateurs conçus, à l’état de prototypes, peuvent être sujet d’améliorations visant à fiabiliser l’ensemble des processus de reconfiguration dynamique – par différentes vérifications à la
compilation, l’utilisation d’un système de types, etc.
Les mécanismes de reconfiguration que nous avons définis et implémentés sont minimaux afin de
limiter l’impact sur les performances du système. Comparé à d’autres technologies pour les systèmes
embarqués, la réflexivité de F RACTAL/T HINK induit un surcoût et pour pouvoir construire des systèmes
reconfigurables à plus grande échelle, il faut non seulement disposer de mécanismes de reconfiguration
minimaux, mais il faut également pouvoir maı̂triser l’impact de l’utilisation des composants T HINK.
Dans ce but, nous avons initié un travail sur les optimisations architecturales séléctives qui visent à
eliminer tout surcoût lié au modèle F RACTAL là, où il n’est pas justifié par un besoin de l’utilisateur.
Nous décrivons ces travaux, leur impact sur les performances et l’intégration avec les mécanismes de
reconfiguration en annexe D.
28
Chapitre 3. Aperçu de la contribution
3.2.2
3.3. Fondations de l’approche
Mise-en-oeuvre
Nous avons appliqué notre travail à trois prototypes de systèmes embarqués. Premièrement nous
avons construit un prototype de système embarqué avec un contrôle d’accès très fin et reconfigurable
(Jarboui et al., 2004), alliant l’intégration et la combinaison de deux aspects non-fonctionnels dans un
système embarqué - la sécurité et la reconfiguration.
Deuxièmement, les noeuds de réseaux de capteurs constituent un cadre idéal pour l’application de nos
travaux. Pour la plupart, il s’agit de plate-formes matérielles très contraintes, à base de processeurs AVR
(Atmel, n.d.), ayant 4 ou 8ko de mémoire. L’objectif étant de vérifier que le modèle de programmation
proposé avec son implémentation convient aux plate-formes très contraintes.
Finallement nous avons conçu un décodeur vidéo H.264 reconfigurable. Le décodeur est conçu
comme un système à composants très fins (Layaida et al., 2005), l’objectif étant de quantifier l’impact
sur les performances de l’implémentation des mécanismes de reconfiguration.
3.2.3
Organisation de la contribution
Nous avons découpé notre proposition en trois parties que nous décrivons dans des chapitres séparées,
la figure 3.3 montre ce découpage :
– la construction de systèmes reconfigurables,
– les mécanismes de reconfiguration dynamique et l’exécution du système et des reconfigurations,
et
– la programmation des reconfigurations
spécification
système
Fractal/THINK
construction
du système
image système
d'exploitation
THINK ADL
compiler
Chapitre 6: Construction de
systèmes reconfigurables
exécution
méta-données
pour la reconfiguration
architecture
spécification
reconfiguration
FScript
construction
reconfiguration
programme de
reconfiguration
compilé
THINK ADL
compiler
Chapitre 7: Programmation de reconfigurations
reconfiguration
Chapitre 5:
Mécanismes de
reconfiguration
F IG . 3.3 – Decoupage du modèle de notre proposition pour un modèle de programmation de systèmes
reconfigurables.
3.3
Fondations de l’approche
Notre approche est basée sur le modèle à composant Fractal (3.3.1) et sur son implémentation en C,
appelée Think (3.3.2).
29
3.3. Fondations de l’approche
3.3.1
Chapitre 3. Aperçu de la contribution
Le modèle à composant Fractal
Fractal (Bruneton et al., 2006; Bruneton et al., 2004) est un modèle à composant à la fois simple,
dynamique et extensible. Fractal est un modèle hiérarchique et réflexif – chaque système Fractal peut
retrouver à l’exécution son architecture (introspection), voire la modifier (intercession).
3.3.1.1
Anatomie d’un système Fractal
La figure 3.4 montre l’anatomie d’un composant/système Fractal. Chaque composant implémente
un certain nombre d’interfaces, dites serveurs, et peut être client d’autres composants via des interfaces,
dites clientes. Les composants peuvent être liées entre eux par des liaisons (une interface cliente et liée à
une interface serveur). Les interfaces sont décrites dans un langage de description d’interfaces (IDL) qui
spécifie les méthodes d’une interface. Les interfaces sont typées, par leur description IDL.
Un système Fractal est vu comme un assemblage de composants. Etant donné que Fractal est un
modèle hiérarchique, les composants sont à la fois en relation de parenté, mais également reliés via des
liaisons de communication :
– La relation de parenté/sous-composants défini un graphe de composants 1 . Ce graphe a généralement une racine – le composant englobant le système entier.
– Une liaison est un canal de communication entre une interface cliente d’un composant et une
interface serveur d’un autre composant. Une laison peut être implémentée par exemple comme
une référence (pointeur) vers l’interface serveur détenue par le composant client. Un appel – une
communication – à une interface serveur est un appel d’une méthode de cette interface.
Un composant Fractal est une entité à l’exécution, accédée par des interfaces bien définies. Un composant Fractal est logiquement vu (composé) en deux parties - la membrane (ou le contrôleur) et le
contenu :
– Le contenu implémente la partie fonctionnelle du composant, il peut soit contenir d’autres composants ou implémenter directement ses interfaces fonctionnelles.
– La membrane contient l’implémentation des interfaces dites de contrôle. Ces interfaces implémentent les aspects non-fonctionnels d’une architecture. Concrétement le modèle défini un ensemble
coeur d’interfaces de contrôle, permettant d’accéder et modifier les liaisons, l’architecture d’un
composant (en termes de contenance), gérer le cycle de vie des composants etc. L’implémentation
d’une interface de contrôle peut exercer un contrôle actif sur les sous-composants, i.e. l’interface
de contrôle peut intercepter les appels entrans ou sortants des sous-composants.
Ainsi défini, le contenu d’un composant implémente les aspects techniques ou métiers, alors que la
membranes ou les contrôleurs implémentent les aspects liés à l’administration ou le contrôle de l’architecture. Ce contrôle peut être passif – l’implémentation d’un contrôleur n’altère pas l’exécution de
ses sous-composants (donc l’exécution de la partie fonctionnelle), ou actif – le contrôleur intercepte les
appels de ses sous-composants.
Les interfaces de contrôle sont optionnelles, chaque membrane peut offrir un ensemble arbitraire
d’interfaces et leur présence détermine le niveau de capacité d’introspection et d’intercession d’une architecture. On peut également définir de nouvelles interfaces de contrôle pour implémenter de nouveaux
aspects, comme l’implémentation de certains mécanismes de base pour la reconfiguration dynamique,
comme nous le montrerons au chapitre suivant.
Parmis les interfaces de contrôle standards, définies par le modèle Fractal, nous utiliserons à des fins
de reconfiguration dynamique les interfaces suivantes :
– ComponentIdentity2 , cette interface est à la fois l’identifiant à l’exécution d’un composant
1
2
Dans Fractal les composants peuvent être partagés, par conséquent le graphe de composition n’est pas un arbre.
Component dans la dernière spécification du modèle Fractal.
30
Chapitre 3. Aperçu de la contribution
3.3. Fondations de l’approche
control interface
Component A
Component B
Component C
binding
Component D
content
functionnal interface
Component E
membrane
F IG . 3.4 – Le modèle à composant Fractal – les concepts.
et permet également de retrouver ses interfaces visibles, par exemple pour établir une liaison vers
une interface serveur du composant.
– ContentController permet de retrouver et éventuellement modifier la structure interne d’un
composant (ses sous-composants).
– BindingController permet de modifier une liaison, en modifiant la référence cliente d’une
interface détenue par le composant client.
– LifeCycleController permet d’arrêter ou démarrer un composant. La sémantique de ces
opérations dans la spécification Fractal est floue et son interprétation diverge dans les deux implémentations de références Julia en Java et Think en C (voir également la description de Think,
3.3.2).
– AttributeController autorise l’accès et la modification des attributs d’un composant.
– NameController offre une représentation de l’identifiant d’un composant sous forme de chaı̂ne
de caractères.
Dans le chapitre suivant, nous décrivons une extension du modèle Fractal pour la reconfiguration
dynamique, en particulier nous définissons un ensemble d’interfaces de contrôle permettant de détecter
un état stable et d’accéder à l’état d’un composant lors d’un transfert d’état.
3.3.2
THINK : une implémentation de Fractal en C
Le terme Think désigne plusieurs projets (tous dans le Projet Think (Think, n.d.)) :
– une implémentation du modèle Fractal, qui défini comment sont implémentés les concepts du
modèle – le canevas Think,
– afin de faciliter la construction de systèmes à base de composants Think, le canevas Think vient
avec un langage de description d’architectures (Architecture Description Language, ou ADL),
Think défini également un langage de description d’interfaces – IDL,
– un compilateur de systèmes à base de composants Think (générant les structures de données des
composants Think), et
– bibliothèque de composants Think pour la construction de systèmes d’exploitation, appelée Kortex.
3.3.2.1
THink Is Not a Kernel
THINK (Fassino et al., 2002; Fassino, 2001) (acronyme pour Think is not a Kernel, car le canevas Think n’est pas un système, mais permet de créer des systèmes) est un canevas de construction de
31
3.3. Fondations de l’approche
Chapitre 3. Aperçu de la contribution
systèmes à composant, en C. Think n’est pas un système, mais permet de construire des systèmes. Aujourd’hui, Think implémente le modèle à composant Fractal. Think est un canevas général de construction de logiciels à composants, néanmoins, nous allons décrire et discuter son application à la construction de systèmes d’exploitation.
L’utilisation de composants Think ne requièrt aucun environement d’exécution supplémentaire – tout
est composant. Par conséquent, il est possible de construire des systèmes d’exploitation minimaux, où
uniquement les composants nécéssaires sont inclus. Par ailleurs, le canevas ne définit et n’exclut aucun type d’organisation du système (micro-noyau, exo-noyau, noyau monolithique, événementiel, multithread ...).
En tant qu’implémentation du modèle Fractal, Think définit l’implémentation concrète des différents
concepts du modèle - interfaces, interfaces de contrôle et leurs méta-données, liaisons, références etc.
Plus spécifiquement, le canevas définit les structures de bases suivantes :
– l’implémentation des interfaces fonctionnelles et des liaisons (intéraction fonctionnelle entre les
composants), et
– l’implémentation et méta-données des interfaces de contrôle Fractal (contrôle).
Implémentation fonctionnelle La figure 3.5 montre l’implémentation standard3 d’un composant Think.
Chaque interface serveur d’une instance d’un composant est matérialisée par un descripteur d’interface.
Le descripteur contient un pointeur vers la table des méthodes de l’interface (meth, cf. vtable en C++)
et un pointeur vers les données d’instance du composant (selfdata). La table des méthodes de l’interface contient les adresses effectives des méthodes. Dans Think, toutes les méthodes d’interface acceptent comme premier paramètre un pointeur vers les données d’instance du composant. Ces données
contiennent d’une part les données privées au composant (ces variables d’instances) et les méta-données
du composant – références d’interfaces clientes et éventuellement d’autres données comme attributs,
noms d’interfaces etc. En particulier, l’adresse des données permet d’identifier de manière unique l’instance d’un composant quelconque dans le système.
Une référence cliente est représentée par un pointeur référençant le descripteur de l’interface serveur.
Ce pointeur matérialise également la liaison entre les composants, il s’agit d’une liaison dynamique (elle
peut-être changé à l’exécution, en modifiant la référence). Les liaisons dynamiques offrent la flexibilité
nécéssaire pour implémenter les différents mécanismes de reconfiguration dynamique, notamment les
opérations de redirection des références. Les références clientes peuvent être modifiées via l’interface
de contrôle BindingController. Cette interface peut également servir à leur initialisation lors du
démarrage du système à composant.
Pour appeler une méthode d’une interface serveur, il suffit de déréferencer la référence cliente pour
retrouver le descripteur d’interface serveur qui donne accès aux méthodes et aux données du composant
serveur. Par exemple, pour appeler à partir du composant A la méthode f() de l’interface cliente Itf_I,
implémentée par l’interface Itf_I_impl du composant B, le code C suivant est nécéssaire :
Itf_I->meth->f(Itf_I->data, arg1, arg2, ...);
Pour l’utilisateur ce code est caché par la construction suivante :
CALL(Itf_I, f, arg1, arg2, ...);
L’implémentation de la méthode f() est une fonction qui accepte en premier paramètre un pointeur
vers ses données d’instance (par conséquent dont le type est connu et déclaré au même endroit), par
conséquent l’implémentation a la signature suivante :
void f(struct myData* _this, int arg1, int arg2, ...);
3
Le présent chapitre montre l’implémentation standard de Think, voir annexe D pour la description des travaux en cours sur
les optimisations architecturales.
32
Chapitre 3. Aperçu de la contribution
3.3. Fondations de l’approche
Itf_I
A
B
conceptual view
implementation view
virtual method
table
Itf_I_impl
interface
descriptor
component data
f()
g()
meth
f()
implem.
...
data
g()
implem.
client interface
references
Itf_I
component
data
B
A
F IG . 3.5 – L’implémentation des interfaces dans Think.
De la même manière que pour l’accès aux interfaces, Think défini un accès aux attributs d’un composant, déclarés dans son ADL.
Implémentation du contrôle par défaut L’implémentation actuelle de Think n’implémente qu’un
sous-ensemble des interfaces de contrôle définies par le modèle Fractal. Ces interfaces de contrôle par
défaut implémentent un contrôle passif (les membranes de composants composites n’interceptent pas les
appels). Concrétement le canevas Think fournit une implémentation des interfaces ComponentIdentity, BindingController, AttributeController, ContentController, LifeCycleController et Factory (qui permet d’implémenter des usines de composants – l’implémentation
est générée par le compilateur avec le code d’instantiation et d’initialisation du composant).
Les interfaces de contrôles sont ajoutées à un composant par le compilateur et ont le même format
binaire que les interfaces fontionnelles. Le compilateur génère un certain nombre de méta-données qui
permettent d’implémenter ces interfaces. Ces méta-données sont référencées par le pointeur des données
d’instance dans le descripteur d’interface. Les données d’implémentation de l’interface ComponentIdentity sont particulières, car cette interface permet de retrouver toutes les autres interfaces serveurs
d’un composant. Par conséquent, ces données contiennent une structure avec tous les desripteurs d’interface du composant, associée au nom de l’interface serveur correspondante.
3.3.2.2
Architecture Description Language
Les composants Think peuvent être décrits en utilisant un langage de description d’architecture
(ADL). L’ADL de Think est un langage déclaratif de haut niveau dans lequel le programmeur peut exprimer la configuration d’une architecture Think en utilisant les concepts du modèle Fractal (interfaces,
composants, liaisons etc.).
Concrétement, l’ADL de Think permet de :
– définir des types abstraits de composants,
– décrire les composants de base en précisant les interfaces implémentées, les interfaces requises
et le fichier d’implémentation en C de ce composant, un composant peut implémenter un type de
composant,
– décrire des composants plus complexes, contenant d’autres composants et ayant des liaisons entre
ses composants,
33
3.3. Fondations de l’approche
Chapitre 3. Aperçu de la contribution
– surcharger une définition de composant, typiquement une description d’architecture de haut-niveau
est spécialisée pour une plate-forme matérielle donnée en surchargeant les composants dépendants
de la plate-forme,
– spécifier quelle membrane doit être générée pour un composant donné, et
– définir et initialiser les attributs des composants
La figure 3.6 montre un exemple d’un système d’exploitation sous forme d’un composant Think et
sa description en ADL.
CI, BC, LCC, RC, CC, NC
CI, BC, LCC, NC
net
CI,LCC,SC
driver
composite SmallNetKernel {
provides net.api.Net as net
provides util.api.Buffer as buffer
eth
net
contains
contains
contains
contains
CI, BC, LCC, NC
CI, LCC, SC, NC
buffer
binds
binds
binds
binds
binds
buffer
allocator
alloc
SmallNetKernel
CI: ComponentIdentity
BC: BindingController
CC: ContentController
LCC: LifeCycleController
RC: ReconfigurationController
SC: StateTransferController
NC: NameController
net = net.lib.tcpip
eth = chip.net.tulip
buffer = util.lib.buffer
alloc = memory.lib.malloc
net.driver to eth.driver
net.alloc to alloc.alloc
buffer.alloc to alloc.alloc
this.net to net.net
this.buffer to buffer.buffer
membrane Reconfig_ThreadCounting
}
F IG . 3.6 – Exemple d’un système à composant Think, vue conceptuelle et ADL.
3.3.2.3
Compilateur Think
Les composants Think décrits en ADL sont assemblés à l’aide d’un compilateur ADL. A partir
des ADL et des IDL, ce compilateur génère du code C, appelé glue code. Le code C généré, avec le
code fonctionnel écrit par le programmeur de composant, est compilé avec un compilateur C standard
et lié sous forme d’une image exécutable sur la plate-forme cible. La figure 3.7 montre le processus de
compilation d’un système à base de composants Think.
architectural code
functional code
.adl
.idl
Think
compiler
adl + idl
.adl.c
.idl.h
terminal
kernel
.c
.h
C
compiler
.o
.o
.o
dynamic
loader
linker
boot
loader
kernel
F IG . 3.7 – La chaı̂ne de compilation pour construire un système à composant Think.
Le compilateur Think étant la pièce principale dans notre approche pour la construction de systèmes
34
Chapitre 3. Aperçu de la contribution
3.3. Fondations de l’approche
reconfigurables, nous détaillons son architecture et le fonctionnement dans le chapitre 5. L’annexe D
décrit l’évolution de ce compilateur afin de supporter des optimisations architecturales séléctives.
3.3.2.4
Kortex : une bibliothèque de composants
Kortex est une bibliothèque de composants Think destinée à la construction des systèmes d’exploitation – ordonnanceurs, allocateurs, protocoles réseaux, différents pilotes matériels (réseau, disque, vidéo
etc.), systèmes de fichiers etc. L’objectif de cette bibliothèque est de fournir un cadre expérimental pour
de nouveaux concepts en systèmes d’exploitation. Nous avons réutilisé Kortex pour construire les prototypes de reconfiguration dynamique (qui seront détaillés au chapitre 7).
Multi-programmation Kortex définit une architecture générique pour la multi-programmation, autorisant l’utilisation de différents ordonnanceurs et simplifiant l’écriture des systèmes multi-programmé.
Dans Kortex un thread est matérialisé par un composant job géré par un ordonnanceur (composant
scheduler). Chaque job est associé à un composant utilisateur qui contient la logique d’exécution.
Uniquement ce dernier composant est écrit par l’utilisateur. A tout moment, l’identité du thread courant,
donc du composant job, peut être retrouvée par la méthode getJob() de l’interface Scheduler du
composant scheduler. La figure 3.8 montre un example d’un système avec trois threads, ordonnancé par
un ordonnanceur à priorités.
runner
runner
runner0
job
runner
runner1
job
job0
runner
scheduler
runner2
job
job1
runner
scheduler
job2
runner
scheduler
scheduler
...
scheduler
generic architecture application independent
F IG . 3.8 – Kortex – L’architecture des composants pour le multi-threading.
Interruptions Kortex définit une architecture générique pour la gestion des interruptions. Au plus
bas niveau se trouve le composant trap, dépendant de la plate-forme matérielle, encapsulant le vecteur d’interruptions du processeur. Toutes les interruptions sont réifiées sous forme d’interfaces clientes
optionnelles qui peuvent être liées (ou non) à un composant gestionnaire d’une interruption concrète.
Une telle réification d’une interruption peut être répétée à plusieurs niveau. Lorsqu’une interruption a
lieu, le composant trap appelle le composant gestionnaire lié à l’interface cliente correspondante. Par
conséquent, le même composant trap peut être réutilisé dans des architectures différentes.
La figure 3.9 montre le cas le plus typique d’implémentation sur un processeur ARM, où un composant trap est lié à un composant pic qui gère les interruptions des périphériques rattachés au processeur. Lors d’une interruptions d’un périphérique, le trap remonte l’événement au pic qui acquitte
35
3.3. Fondations de l’approche
Chapitre 3. Aperçu de la contribution
l’interruption et remonte l’événement à un gestionnaire de plus haut niveau, si celui-ci est liée à l’interface cliente correspondante (potentiellement indépendent de la plate-forme matérielle). La conséquence
de ce fonctionnement est que les composants trap et pic peuvent être réutilisés dans des configurations
architecturales différentes.
application
kbd
keyboard
driver
serial
trap
pic
radio
radio
driver
pic
ARM processor
exceptions
...
RESET
UNDEF
handler
IRQ FIQ
ARM processor
keypad
radio
link
screen
...
F IG . 3.9 – Kortex – l’architecture des composants gestionnaires d’interruptions.
36
Chapitre 4
Interface de programmation pour la
reconfiguration dynamique
Au chapitre précédent nous avons identifié les mécanismes pour la reconfiguration dynamique. Dans
ce chapitre nous décrivons une interface1 flexible de programmation des reconfigurations, permettant
d’implémenter dans un système à composants les différents mécanismes de reconfiguration. L’interface
de programmation que nous proposons est basée sur la notion des interfaces de contrôle de Fractal –
chaque mécanisme est accessible via une interface de contrôle spécifique, chaque composant fournissant
un ensemble approprié d’interfaces de contrôle et leurs implémentations. L’interface que nous définissons
est indépendante du modèle d’exécution.
Nous décrivons d’abord les différentes interfaces de contrôle Fractal constituant l’interface de programmation des reconfigurations. Nous discutons ensuite de l’utilisation de cette interface de programmation et montrons quelques exemple de l’utilisation. Nous montrerons également deux implémentations
de la détection d’un état stable de composant.
4.1
Interface de programmation des reconfigurations
Une interface de programmation des reconfigurations de bas niveau doit permettre de programmer
les actions suivantes :
– identifier à l’exécution la partie de l’architecture à reconfigurer - composant, liaison, l’attribut,
– contrôler l’état d’un composant (détection d’un état stable ou quiescent, accès à son état interne
afin de pouvoir le transférer),
– modifier l’architecture (ajouter, supprimer ou remplacer des composants).
Nous avons étendu le modèle F RACTAL en définissant de nouvelles interfaces de contrôle (notamment pour la détection d’un état stable et le transfert d’état) et nous avons également fourni une
implémentation de ces interfaces pour le canevas Think.
4.1.1
Motivation des choix de conception
L’API de reconfiguration que nous définissons répond aux objectifs que nous avons identifiés (cf. chapitre 1) de la manière suivante :
1
A distinguer interface de programmation et interface de contrôle. L’interface de programmation est l’ensemble de
méthodes mises à dispositions du programmeur de reconfigurations, une interface de contrôle est un concept du modèle à
composant F RACTAL.
37
4.1. Interface de programmation des reconfigurations
Chapitre 4. Interface de programmation
Flexibilité Dans notre approche, les composants reconfigurables implémentent un certain nombre d’interfaces de contrôle permettant de programmer les reconfigurations. Une telle interface de programmation est de bas niveau et permet de maı̂triser au grain fin la reconfiguration. En revanche, l’implémentation
de cette interface garantit uniquement la sémantique des opérations de bas niveau de la reconfiguration,
mais non leur ensemble.
Par exemple, dans un système où l’interface de reconfiguration est donnée par une méthode replace(old, new, ...), l’implémentation de cette interface garantirait que le composant old soit dans
un état stable avant sa manipulation, un transert d’état entre les composants etc. Dans notre approche,
c’est au programmeur de reconfigurations de s’assurer de la validité sémantique de son programme de
reconfiguration.
Cette approche autorise une flexibilité dans la construction d’un système reconfigurable – pour
chaque composant reconfigurable, le concepteur choisit les implémentations des mécanismes de reconfiguration. Le concepteur doit également s’assurer que le système à composants reconfigurable implémente
bien une interface de reconfiguration complète.
Nous allons montrer dans le chapitre 6 comment les reconfigurations peuvent être programmées
en utilisant un langage de reconfiguration de haut niveau, FScript dans notre cas, qui permet la compilation et la vérification des programmes de reconfiguration. Néanmoins, la reconfiguration peut être
programmée sans recours à FScript.
Indépendance des implémentations des différents mécanismes Les implémentations des différentes
interfaces de contrôle composant l’interface de reconfiguration sont indépendante les unes des autres
et de la partie fonctionnel du système. C’est le concepteur du système qui choisit la combinaison des
différentes implémentations que fournit un composant reconfigurable. Il est tout à fait possible que deux
composants implémentent le même mécanisme d’accès à leurs états (càd l’interface StateTransferController) mais implémentent différentes stratégies pour détecter un état stable (interface ReconfigurationController, par example par comptage de référence ou à l’aide des intercepteurs dynamiques - décrits ci-dessous).
Indépendance des implémentations vis-à-vis des programmes de reconfiguration Grâce à la séparation stricte des interfaces et leurs implémentations dans le modèle F RACTAL, les programmes de reconfigurations utilisant l’interface de programmation sont indépendants de l’implémentation des mécanismes
sous-jacents (fournis par le composant). Lors de la programmation des reconfigurations, il est aisé de raisonner uniquement en termes d’architectures et d’opérations nécéssaires à la reconfiguration, sans se
soucier des particularités des implémentations des interfaces de contrôle.
Respect des contraintes de performances du système Toutes les interfaces de contrôle sont optionnelles, uniquement les composants reconfigurables doivent les implémenter. Dans le chapitre 7 nous
évaluons l’impact de l’implémentation de l’interface de programmation en terme d’occupation mémoire
et de surcoût à l’exécution.
4.1.2
Identification et introspection
Dans F RACTAL l’interface ComponentIdentity identifie de façon unique un composant dans un
système. Concrétement, dans T HINK, les différentes structures générées pour un composant occupent un
emplacement unique en mémoire et par conséquent il est possible d’identifier le composant par le biais
de ces adresses. En particulier, l’adresse mémoire du descripteur de l’interface ComponentIdentity constitue un identifiant unique d’un composant, de même que l’adresse de données d’instance
d’un composant (this).
38
Chapitre 4. Interface de programmation
4.1. Interface de programmation des reconfigurations
Le modèle Fractal étant hiérarchique, pour retrouver un composant quelconque dans une architecture,
il faut être capable de parcourir cette dernière ou l’introspecter. L’interface ContentController,
également définie dans Fractal, répond à ce besoin et permet de retrouver tous les sous composants
d’un composant parent. Le programme de reconfiguration doit connaı̂tre la poignée (handle) de la racine
de l’architecture et un chemin vers le composant à partir de la racine. Ensuite tout composant parent du
composant recherché doit implémenter l’interface ContentController et l’interface ComponentIdentity.
Les interfaces ComponentIdentity et ContentController sont définies de la manière suivante :
interface ComponentIdentity {
any getInterface(String name);
any[] getInterfaces();
}
interface ContentController {
void addSubComponent(ComponentIdentity c);
void removeSubComponent(ComponentIdentity c);
any[] getSubComponents();
}
L’interface NameController permet de retrouver le nom d’un composant. Cette interface sera
utile à l’implémentation du support d’un langage de haut-niveau tel que FScript, où l’utilisateur désigne
les composants par leur nom. L’interface NameController est définie de la manière suivante :
interface NameController {
String getName();
void setName(String name);
}
La figure 4.1 montre les interfaces d’introspection et comment celles-ci permettent de parcourir une
architecture Fractal. Par exemple, en détenant une référence vers le composant C (donc vers l’interface
CI de ce composant), il est possible d’obtenir l’interface CC de ce même composant, qui donne accès
aux sous-composants A et B. De cette façon, et en utilisant le NC pour comparer les noms, nous pouvons
trouver le composant désigné par le chemin absolu C.B.
CI
CI
NC
CC
BC
NC
CI
A
NC
B
C
F IG . 4.1 – Les interfaces d’introspection.
39
4.1. Interface de programmation des reconfigurations
4.1.3
Chapitre 4. Interface de programmation
Contrôle d’état
Comme décrit au chapitre 3, le contrôle d’état pour la reconfiguration dynamique comprend deux
opérations : la suspension de l’exécution d’un composant et le transfert d’état entre des instances de
composants. A ces deux opérations nous ajoutons également l’opération d’initialisation et arrêt de composants (qui correspond au constructeur et desctructeur de composants).
4.1.3.1
Initialisation et arrêt des composants
Dans Think, l’interface de contrôle LifeCycleController est utilisée pour initialiser un composant (méthode start()) ou pour l’arrêter (méthode stop()), par exemple pour initialiser un driver
matériel (port série, carte ethernet etc.). L’implémentation de cette interface est appelée lors de l’initialisation du système à composant, avant l’exécution propre du système. Tout composant nécéssitant d’une
phase d’initialisation doit implémenter cette interface.
L’appel à cette interface doit aussi être effectué lors d’une reconfiguration (si cette interface est
implémentée par le composant en question), par exemple lors de la suppression d’un driver – il faut
l’arrêter proprement.
interface LifeCycleController {
void start();
void stop();
}
4.1.3.2
Etat stable
Pour implémenter un algorithme de détection d’un état stable, nous avons défini une interface de
contrôle, appelée ReconfigurationController, qui permet de contrôler l’état d’un sous-composant en demandant la suspension de son exécution (état stable ou quiescent).
L’interface ReconfigurationController est définie comme suit :
interface ReconfigurationController {
void suspend(ComponentIdentity subcomponent, Callback cb);
resume(ComponentIdentity subcomponent);
}
La méthode suspend() de l’interface ReconfigurationController permet de déclencher
la détection d’un état stable du sous-composant subcomponent et, lorsque celui-ci est atteint, suspendre son exécution. L’argument subcomponent permet à la fois d’identifier le composant à suspendre, ainsi qu’identifier la requête de détection d’état stable (cet identifiant permet de reprendre l’exécution après une reconfiguration).
Afin de pouvoir détecter l’état stable de plusieurs composants en même temps, l’implémentation de
la méthode suspend() est impérativement non-bloquante et c’est à l’appelant de cette méthode d’attendre jusqu’à ce que les différents composants aient atteint des état stables. Par conséquent suspend()
prend en paramètre une référence d’interface, cb, qui doit être appelée lorsqu’un état stable est atteint
(plus précisément la méthode notify() de cette interface). C’est à l’appelant d’implémenter cette interface et de gérer un état (compteur par exemple) qui lui permet de savoir si tous les composants à
reconfigurer sont dans un état stable. Ce mode de fonctionnement est illustré sur la figure 4.2.
L’interface auxiliaire Callback est définie comme suit :
interface Callback {
void notify(int waiting);
}
40
Chapitre 4. Interface de programmation
requester
4.1. Interface de programmation des reconfigurations
C0
Cn
C1
request()
request()
n times, for
n components
request()
request done, action:
return or block(), P()
callback()
n times, for
n components
callback()
callbacks not
necessery
in order
callback()
request done, action:
callback() or unblock(), V()
F IG . 4.2 – Callbacks – fonctionnement.
La méthode resume() permet de reprendre l’exécution des composants suspendus. L’argument
subcomponent est l’identifiant permetant à l’implémentation de l’interface ReconfigurationController d’identifier quel composant peut reprendre l’exécution, en particulier si le composant
identifié à l’origine par l’argument subcomponent a été remplacé, dans ce cas, c’est le nouveau composant qui reprend l’exécution.
L’interface ReconfigurationController ainsi proposée est simple et l’implémentation d’un
algorithme d’état stable est local à un composant. Par conséquent, avec le modèle multi-thread et le comptage de référence, il est possible de créer un interblocage (deadlock) à la reconfiguration. (Par example,
en demandant simultanément la détection d’un état quiescent de deux composants liées. Si le composant serveur atteint un état quiescent, il bloque tout nouvel appel. Le composant client n’arrivera jamais
dans un état quiescent, car en attente de terminaison des appels en cours, bloqués au composant client.)
Notre approche pour la programmation de reconfigurations, cf. 6, permet d’analyser le programme de
reconfiguration et détecter cette situation, voire la corriger en réordonnanceant le code.
4.1.3.3
Transfert d’état
Dans ce travail, nous considérons uniquement des mécanismes de bas niveau permettant un transfert
d’état complet, comme décrit au chapitre 3, section 3.1. Par conséquent, nous définissons uniquement une
interface pour accéder à l’état d’un composant (lecture, écriture). Cette interface doit être implémentée
par le programmeur du composant
Afin d’accéder à la représentation de l’état d’un composant nous définissons une interface de contrôle
appelée StateTransferController définie comme suit :
interface StateTransferController {
void* getState();
void setState(void* state);
}
Les deux méthodes permettent d’accéder à l’état du composant (getState() permet de le retrou-
41
4.2. Utilisation
Chapitre 4. Interface de programmation
ver, setState() permet de l’insérer). Ces deux méthodes sont suffisantes pour bâtir des mécanismes
de transfert d’état plus complexes, en particulier l’interface StateTransferController ainsi définie ne fait aucune hypothèse sur la structure de l’état interne du composant. C’est au programmeur du
composant d’implémenter cette interface et c’est à l’appelant de connaı̂tre la structure de l’état et de
la manipuler si nécessaire (i.e. lorsque lors d’un remplacement de composant les deux formats pour
maintenir l’état interne – le nouveau et l’ancien – ne sont pas identiques).
4.1.4
Modifications de l’architecture
Le modèle Fractal définit déjà un certain nombre d’interfaces de contrôle qui permettent de modifier
une architecture à base de composants Fractal. Nous autorisons :
– les modifications de liaisons,
– les modifications des attributs, et
– les modifications de l’architecture, i.e. de l’assemblage des composants.
4.1.4.1
Modifications de liaisons
Une liaison est matérialisée par une référence cliente du composant client vers une interface serveur du composant serveur. L’interface BindingController implémentée par le composant client
permet d’accéder et modifier cette référence et par conséquent d’établir une nouvelle liaison en cas de
reconfiguration (ou la supprimer).
L’interface BindingController est définie de la manière suivante :
interface BindingController {
void bind(String name, any itf);
void unbind(String name);
any lookup(String name);
}
4.1.4.2
Modification d’attributs
Les attributs d’un composant peuvent être modifiés grâce à l’interface de contrôle AttributeController, si le composant en question implémente cette interface :
interface AttributeController {
any get(String name);
void set(String name, any value);
}
4.1.4.3
Modifications de l’assemblage des composants
La composition, ou l’assemblage des composants, d’un système à composants Fractal peut être modifiée grâce aux implémentations de l’interface de contrôle ContentController (définie plus haut)
des différents composants. Cette interface permet à chaque composant qui l’implémente, d’ajouter ou de
supprimer ses sous-composants.
4.2
Utilisation
L’API de reconfiguration ainsi définie est riche en combinaisons et en cas d’utilisation - par exemple
il est possible d’ajouter un sous-composant supplémentaire à un composant composite CC (Content-
42
Chapitre 4. Interface de programmation
interface de contrôle
ComponentIdentity
getInterface()
getInterfaces()
NameController
getName()
setName()
ContentController
addSubComponent()
removeSubComponent()
getSubComponents()
BindingController
bind()
unbind()
lookup()
AttributeController
set()
get()
4.2. Utilisation
intercession
introspection sans état stable
intercession
avec état stable
x
x
-
-
x
-
x
-
x
x
-
x
-
x
x
x
-
x
x
-
x
x
-
x
-
TAB . 4.1 – L’API de reconfiguration – introspection et intercession.
Controller du composant composite CC) et le lier à une interface optionnelle d’un autre composant (BindingController du composant client). Ou alors il est possible de remplacer un souscomposant d’un composant composite nécéssitant la détection d’un état stable du sous-composant à
remplacer (donc implication de l’utilisation des interfaces ContentController, ReconfigurationController, StateTransferController et BindingController ...).
Les interfaces de contrôle, et plus précisément les méthodes des interfaces de contrôle, tombent dans
différentes catégories :
– introspection uniquement, donc aucune modification de l’architecture,
– intercession sans nécéssité d’un état stable du composant,
– intercession avec nécéssité d’un état stable du composant,
– méthodes permettant de contrôler l’état, en particulier de détecter un état stable,
Les tableaux 4.1 et 4.2 détaillent les catégories de chaque méthode de l’API.
L’utilisation correcte des différentes méthodes des interfaces de contrôle est dirigée par les règles
suivantes :
– Toute interface de contrôle est optionnelle et c’est au constructeur du système de s’assurer que le
système inclut toutes les interfaces de contrôle nécéssaires à la reconfiguration dynamique. (Au
chapitre suivant nous allons montrer comment on peut automatiser la construction des systèmes
reconfigurables avec toutes les interfaces de contrôle nécessaires.)
– Les méthodes d’introspection peuvent être utilisées sans aucune contrainte pendant la reconfiguration.
– Les méthodes d’intercession ne nécéssitant pas que le composant soit dans un état stable peuvent
être utilisées sans aucune contrainte pendant la reconfiguration.
– Les méthodes d’intercession nécéssitant qu’un ou plusieurs composants soient dans un état stable
peuvent être utilisées une fois qu’un état stable a été détecté par l’implémentaiton de l’interface
ReconfigurationController.
43
4.3. Exemple d’un programme de reconfiguration
Chapitre 4. Interface de programmation
interface de contrôle
ReconfigurationController
suspend()
resume()
LifeCycleController
start()
stop()
StateTransferController
getState()
setState()
état
d’exécution
état
interne
x
x
-
-
x
x
-
x
x
TAB . 4.2 – L’API de reconfiguration – contrôle d’état.
– Les interfaces de contrôle d’état interne LifeCycleController et StateTransferController doivent être utilisées alors que le composant est dans un état stable2 .
– Les méthodes des interfaces BindingController et AttributeController peuvent
nécéssiter que le composant soit dans un état stable, selon l’implémentation du composant. C’est
au programmeur de reconfiguration de connaı̂tre la sémantique du composant et décider si un état
stable est nécéssaire à la manipulation des attributs ou des liaisons.
4.3
Exemple d’un programme de reconfiguration
Considérons un système à composant fictif comme montré sur la figure 4.3.
CI
CC
CI
BC
LCC
RC
LCC*
CI
LCC*
SC
alloc
(server)
composant lié
à un composant
reconfigurable
alloc
(client)
xyz
composant
reconfigurable
alloc
kernel
CI:
BC:
CC:
LCC:
ComponentIdentity
RC: ReconfigurationController
BindingController
SC: StateTransferController
ContentController
LifeCycleController (optionnel)
F IG . 4.3 – Un exemple de système reconfigurable.
Considérons un exemple de reconfiguration qui consiste à remplacer le sous-composant alloc du
composant kernel. Cette reconfiguration nécéssite la détection d’un état stable du composant alloc,
l’instantiation du nouveau composant, la modification des liaisons vers ce composant et finalement la
suppression de l’ancien composant alloc.
Avec l’API décrite ci-dessus, nous pouvons programmer cette reconfiguration de la manière suivante
(nous supposons que le programme dispose d’une poignée vers la racine de l’architecture – composant
2
Nous considérons qu’arrêter un composant, i.e. appeler la méthode stop() du LifeCycleController alors qu’il
n’est pas en état stable, est une erreur.
44
Chapitre 4. Interface de programmation
4.3. Exemple d’un programme de reconfiguration
kernel, et la poignée vers le composant déjà instancié) :
/∗
CI t
: C type
CC t : C t y p e
: C type
BC t
LCC t : C t y p e
: C type
RC t
SC t
: C type
NC t : C t y p e
for
for
for
for
for
for
for
ComponentIdentity
ContentController
BindingController
LifeCycleController
ReconfigurationController
StateTransferController
NameController
S e m t : C t y p e f o r Semaphore i n t e r f a c e
I t f d e s c t : C t y p e f o r an i n t e r f a c e d e s c r i p t o r ( g e n e r i c )
∗/
/∗ helper functions ∗/
C I t ∗ h e l p e r f i n d c o m p o n e n t ( C I t ∗ p a r e n t , char ∗ cName )
{
CC t ∗ c c = p a r e n t −>g e t I n t e r f a c e ( ” c o n t e n t − c o n t r o l l e r ” ) ;
i n t n = cc−>g e t S u b C o m p o n e n t s ( 0 ) ;
C I t ∗ ∗ subcomps = a l l o c ( n∗ s i z e o f ( C I t ∗ ) ) ;
int i = 0;
cc−>g e t S u b C o m p o n e n t s ( subcomps ) ;
for ( i = 0 ; i < n ; i ++) {
C I t ∗ subcomp = subcomps [ i ] ;
NC t ∗ nc = subcomp−>g e t I n t e r f a c e ( ” name− c o n t r o l l e r ” ) ;
char ∗ name = nc−>getName ( ) ;
i f ( ! s t r c m p ( name , cName ) )
r e t u r n subcomp ;
}
r e t u r n 0 ; / / no match
}
/ ∗ s i m p l i f i e d p r i v a t e d a t a , s h a r e d by C a l l b a c k and main program ∗ /
int counter ;
Sem t ∗ sem ;
/∗ Callback i n t e r f a c e impleentation , s i m p l i f i e d ∗/
void C a l l b a c k n o t i f y ( )
{
c o u n t e r − −; / / i d e a l l y s h o u l d be p r o t e c t e d a g a i n s t c o n c u r r e n t a c c e s s
i f ( ! counter )
sem−>V ( ) ; / / ok , l a s t q u i e s c e n t s t a t e d e t e c t e d
}
/ ∗ main r e c o n f i g u r a t i o n program ∗ /
v o i d r e c o n f i g u r a t i o n ( C I t ∗ C I k e r n e l , C I t ∗ CI new )
{
/∗ i n i t ∗/
c o u n t e r = 1 ; / / o n l y one q u i e s c e n t s t a t e d e t e c t i o n r e q u e s t
sem−> i n i t ( 1 ) ;
45
4.4. Exemples d’implémentation
Chapitre 4. Interface de programmation
CC t ∗ C C k e r n e l = C I k e r n e l −>g e t I n t e r f a c e ( ” c o n t e n t − c o n t r o l l e r ” ) ;
RC t ∗ R C k e r n e l = C I k e r n e l −>g e t I n t e r f a c e ( ” r e c o n f i g u r a t i o n − c o n t r o l l e r ” ) ;
CI t ∗ CI old = helper find component ( CI kernel , ” alloc ” ) ;
C C k e r n e l −>add ( CI new ) ;
/∗ Quiescent s t a t e request ∗/
R C k e r n e l −>s u s p e n d ( C I o l d ) ;
Semaphore−>P ( ) ; / / b l o c k s
/∗ Quiescence detected ∗/
/ ∗ s t o p old a l l o c component ∗ /
LCC t ∗ LCC old = C I o l d −>g e t I n t e r f a c e ( ” l i f e c y c l e − c o n t r o l l e r ” ) ;
i f ( ! LCC old ) LCC old−>s t o p ( ) ;
S C t ∗ S C o l d = C I o l d −>g e t I n t e r f a c e ( ” s t a t e −t r a n s f e r − c o n t r o l l e r ” ) ;
v o i d ∗ s t a t e = SC old−>g e t S t a t e ( ) ;
/ / state transformation ?
S C t ∗ SC new = CI new−>g e t I n t e r f a c e ( ” s t a t e −t r a n s f e r − c o n t r o l l e r ” ) ;
SC new−>s e t S t a t e ( s t a t e ) ;
/∗
Itf
CI
BC
BC
BC
rebind ∗/
d e s c t ∗ I t f a l l o c n e w = CI new−>g e t I n t e r f a c e ( ” a l l o c ” ) ;
t ∗ C I x y z = h e l p e r f i n d c o m p o n e n t ( C I k e r n e l , ” xyz ” ) ;
t ∗ BC xyz = CI xyz −>g e t I n t e r f a c e ( ” b i n d i n g − c o n t r o l l e r ” ) ;
xyz−>u n b i n d ( ” a l l o c ” ) ;
xyz−>b i n d ( ” i t f ” , I t f a l l o c n e w ) ;
/ ∗ s t a r t new a l l o c c o m p o n e n t ∗ /
LCC t ∗ LCC new = CI new−>g e t I n t e r f a c e ( ” l i f e c y c l e − c o n t r o l l e r ” ) ;
i f ( ! LCC new ) LCC new−> s t a r t ( ) ;
/ ∗ resume o p e r a t i o n ∗ /
R C k e r n e l −>r e s u m e ( C I o l d ) ; / / C I o l d i s an i d !
C C k e r n e l −>remove ( C I o l d ) ;
}
4.4
Exemples d’implémentation
Alors que l’implémentation des interfaces BindingController, LifeCycleController ou
AttributeController reste relativement simple et standard dans l’implémentation Think, l’interface ReconfigurationController est la plus complexe à réaliser. Dans cette section nous
décrivons deux différentes implémentations de cette interface, implémentant deux algorithmes différents
de détection d’un état stable d’un composant – par comptage de références et avec les intercepteurs
dynamiques.
4.4.1
Comptage de références
Dans un système avec un modèle d’exécution multi-thread, pour détecter un état quiescent d’un
composant (un état quiescent est la trivilialisation d’un état stable, cf. chapitre 2), le système peut compter
les invocations et leurs retours. Ainsi, quand le compteur de références est à zéro, aucune invocation n’est
46
Chapitre 4. Interface de programmation
4.4. Exemples d’implémentation
en cours et le composant est donc dans un état quiescent. Le composant (ou le système) bloque tout les
nouvelles requêtes jusqu’à la fin de la reconfiguration – jusqu’à l’appel de resume(). Cet algorithme
classique, que nous appelons comptage de référence, a l’avantage d’être simple. Il a été implémenté dans
MMlite (mutation), Synthetix (read-write locks) ou d’autres systèmes.
Dans THINK, les invocations de composants sont des appels de méthodes de ses interfaces. Pour
compter ces appels, nous avons utilisé des composants intercepteurs spécifiques reliés et contrôllés par
l’implémentation de l’interface ReconfigurationController. Ces intercepteurs sont déployés
pour chaque interface d’un composant reconfigurable, comme le montre la figure 4.4. L’état stable du
composant est déterminé à partir des états stables partiels – un état stable pour une interface. Le rôle d’un
intercepteur est de maintenir un compteur des invocations actives de l’interface interceptée pour pouvoir
détecter un état quiescent si nécéssaire (i.e. lorsqu’une requête de détection a été émise) et bloquer les
nouvelles invocations. Pour cela, chaque intercepteur maintient un état relatif aux invocations en cours –
un des états possibles est l’état stable partiel pour cette interface.
CI
RC
implementation
CI
SC
LC
I-0
a client component
I-1
a client component
reconfigurable
component
I-2
F IG . 4.4 – Deploiement des intercepteurs de comptage de références.
Anatomie et type d’intercepteur Les composants intercepteurs font partie de l’implémentation de
la membrane d’un composant, concrètement de l’implémentation de l’interface ReconfigurationController. Un intercepteur est spécifique à un type d’interface (type au sens IDL), on parle alors
de type d’intercepteur. Par example, la figure 4.5 montre un intercepteur de type I pour un type d’interface I3 .
Un intercepteur de comptage de références type I fournit les interfaces suivantes :
– une interface serveur du type I,
– les interfaces de contrôle standard (ComponentIdentity, BindingController et LifeCycleController),
– une interface de contrôle spécifique, appelée InterceptorStateController, permettant
de demander un changement d’état d’un intercepteur (suite à une requête de détection d’un état
stable, voir suite),
Chaque intercepteur de comptage de références de type I requièrt les interfaces suivantes :
– une interface cliente du type I,
3
Pour les raisons de simplicité nous confondons le type de l’intercepteur avec le type d’interface.
47
4.4. Exemples d’implémentation
Chapitre 4. Interface de programmation
– l’interface sf (semaphorefactory), utilisée lors de l’initialisation pour créer deux sémaphores et
les lier vers les interfaces clientes mutex et sem
– l’interface mutex, sert à implémenter l’exclusion mutuelle pour manipuler le compteur
– l’interface sem, sert à bloquer les nouveaux threads entrant lorsque le composant est dans un état
stable,
– l’interface client cb (ou callback), liée au moment d’une requête de détection d’un état stable
et servant à informer l’appelant lorsqu’un état stable est atteint.
CI
BC
LCC
LC
I
I
interception logic:
forward, reject, block
interceptor
component
mutex
sem
cb
interface
type I
sf
F IG . 4.5 – Un intercepteur de comptage de références de type I.
Etats des intercepteurs Pour décider si un appel peut être transmis à l’interface interceptée, chaque
intercepteur maintient un état relatif aux appels en cours et à la présence d’une requête de détection d’un
état quiescent. Les transitions entre les états sont soit implicites (déterminées à partir de la valeur du
compteur) ou doivent être déclenchées explicitement en appelant la méthode change state() fournie par l’interface de contrôle InterceptorStateControl. Les différents états et les transitions
associées sont décrits dans la figure 4.6.
Après l’initialisation des intercepteurs (pendant l’initialisation du système – appels récursif aux interfaces LifeCycleController), les intercepteurs passent en mode de fonctionnement normal, càd où
aucune requête de détection d’état quiescent n’est en cours. Dans ce mode, l’intercepteur peut se trouver
dans un état actif – lorsque le compteur de référence est à zéro, donc aucune invocation de méthode ne
s’exécute alors, ou dans un état busy – au moins une invocation de méthode est en train d’être exécutée.
Les transitions entre ces deux états sont implicites, déterminées uniquement par la valeur du compteur.
En particulier le changement entre l’état busy vers l’état actif survient lorsque le dernier thread actif
retourne du composant vers l’intercepteur.
Une requête de détection d’un état quiescent est traduite par un changement d’état explicite, donc
par un appel à change state(). Au moment de cet appel, si l’intercepteur se trouve dans un état
actif, l’état devient suspendu et l’état quiescent pour cette interface est atteint directement et tout nouvel
appel sera bloqué. Si par contre l’intercepteur se trouve dans un état busy, la requête est temporairement
suspendue (par l’appelant) jusqu’à ce que la dernière invocation en cours se termine et qui fait basculer
l’état de l’intercepteur dans un état suspendu, donc dans un état quiescent. A ce moment, la méthode
notify() de l’appelant est appelée (implementée par l’interface Callback de l’appelant).
Algorithme général L’algorithme de détection d’un état quiescent (méthode suspend() de l’interface ReconfigurationController) est implémenté comme suit (pseudo-code C, l’algorithme
48
Chapitre 4. Interface de programmation
4.4. Exemples d’implémentation
*) externally triggered transitions,
all other transitions are triggered
by the interceptor itself
NeedInit
initialization
Activated
a thread exits the
component and was
the last one to execute
a thread enxters
the component
reconfiguration
request (*)
Busy
incoming service requests
(thread) proceeds
reconfiguration
terminated (*)
Suspended
Quiescent State
reconfiguration
request (*)
InSuspendRequest
last thread active
in the component
exited
F IG . 4.6 – Les états des intercepteurs de comptage de références.
suppose l’existence d’un mutex pour l’accès en exclusion mutuelle aux données et une implémentation
de l’interface Callback, discuté plus bas) :
v o i d s u s p e n d ( C o m p o n e n t I d e n t i t y component , C a l l b a c k cb )
{
InterceptorStateController ∗ istate ;
ComponentIdentity i n t e r c e p t o r s [ ] ;
i n t e r c e p t o r s = . . . / / r e t r i e v e from p r i v a t e data ;
. . . = cb ; / / s a v e cb t o p r i v a t e d a t a
for ( i n t e r c e p t o r : i n t e r c e p t o r s ) {
i s t a t e = i n t e r c e p t o r s −>g e t I n t e r f a c e ( ” s t a t e − c o n t r o l l e r ” ) ;
i n t a c t i v e = i s t a t e −>c h a n g e s t a t e ( S u s p e n d ) ;
if ( active ) {
CALL( s e l f −>mutex , P ) ;
s e l f −>w a i t i n g ++;
CALL( s e l f −>mutex , V ) ;
}
}
CALL( s e l f −>mutex , P ) ;
CALL( cb , n o t i f y , s e l f −>w a i t i n g ) ;
CALL( s e l f −>mutex , V ) ;
}
L’implémentation de la méthode suspend() demande un changement d’état aux intercepteurs et
remonte à l’appelant le nombre d’intercepteurs encore en attente d’un état stable (cf. appel à l’interface
cb de l’appelant).
La méthode notify() de l’interface Callback, appelé depuis les intercepteurs lorsqu’un état
stable est atteint, est implémentée comme suite :
49
4.4. Exemples d’implémentation
Chapitre 4. Interface de programmation
void n o t i f y ( )
{
CALL( s e l f −>mutex , P ) ;
s e l f −>w a i t i n g −−;
i f ( s e l f −>w a i t i n g = = 0 ) {
/ / ok , no more i n t e r c e p t o r s t o w a i t f o r
C a l l b a c k cb = . . . / / r e t r i e v e f r o m p r i v a t e d a t a
CALL( s e l f −>mutex , V ) ;
CALL( cb , n o t i f y , 0 ) ;
} else {
CALL( s e l f −>mutex , V ) ;
}
}
Un composant peut avoir plusieurs interfaces, donc l’implémentation de notify() ne notifie l’appelant de suspend() uniquement losrque le dernier état stable partiel a été atteint.
La figure 4.7 montre l’intéraction entre les différents éléments (implémentation de ReconfigurationController et les intercepteurs d’interfaces des deux composants) pour détecter un état quiescent, ici lors de la détection d’un état quiescent de deux composants en même temps. A noter que les
phases de déclanchement de changement d’état et la notification d’un état stable partiel peuvent être entrelacées. L’implémentation utilise des callbacks à deux niveaux - entre l’implémentation de l’interface
ReconfigurationController et les intercepteurs, entre le programme de reconfiguration et les
différents composants à reconfigurer. Dans le premier cas le callback décrémente le compteur des interfaces encore actives, lorsqu’il est à zéro, le programme de reconfiguration est notifié par un callback.
Dans le deuxième cas, le programme de reconfiguration maintient un compteur de composants encore
actifs. Lorsque ce compteur tombe à zéro (appel du dernier callback), le programme de reconfiguration
est débloqué (appel au sémaphore).
component-0
quiescent state
request
(component-0)
interceptor-n
InterceptorLifeCycle
InterceptorLifeCycle
ReconfigurationController
reconfiguration
program
change_state()
change_state()
suspend()
block(), P()
callback()
ReconfigurationController
blocking incoming
threads
suspend()
n-times
quiescent state
request
(component-1)
component-1
interceptor-0
change_state()
last thread
exited
callback()
n-times
callback()
quescient state
achieved
(component-0)
callback()
callback()
quescient state
achieved
(component-1)
unblock(), V()
reschedule
(by scheduler)
reconfiguration
continuation
F IG . 4.7 – L’intéraction des différents éléments de l’implémentation de la détection d’un état quiescent
avec le comptage de références.
50
Chapitre 4. Interface de programmation
4.4.2
4.4. Exemples d’implémentation
Intercepteurs dynamiques
L’utilisation des intercepteurs dynamiques pour détecter un état quiescent d’un composant est directement inspirée du mécanisme de hot-swapping implémenté dans K42 (Soules et al., 2003; Baumann
et al., 2005).
Le mécanisme est déployé dans un modèle d’exécution multi-thread avec deux hypothèses particulières – les threads doivent être non-bloquants et de durée déterminée. De cette façon les threads
peuvent être groupés dans le temps et constituent des générations de threads. Une génération est un
groupement arbitraire de threads à un moment donné de l’exécution du système. Une génération prend
naissance lorsqu’un changement de génération est explicitement demandé. Etant donné la nature nonbloquante et la durée limitée de ces threads, une génération se termine toujours, et ce moment est détecté
et donne suite à un changement de génération implicite.
Lorsqu’un intercepteur dynamique est déployé à l’exécution, il n’a aucune connaissance de l’historique de l’exécution du composant, en particulier, si un appel quelconque est encore en train de
s’exécuter. Au déploiement des intercepteurs dynamiques, le système demande explicitement un changement de génération et attend la notification de la terminaison de cette dernière. De son côté, l’intercepteur
enregistre l’identité des appelants à chaque invocation du composant. Au moment où la génération de
threads s’est terminée, le composant intercepté n’exécute que des threads de la génération courante, enregistrés alors par l’intercepteur. Un état quiescent est en principe atteint au changement de génération –
tout nouvel appel est bloqué, les appels récursifs peuvent néanmoins rentrer à nouveau dans le composant
(ré-entrance).
La figure 4.8 illustre le mécanisme de générations de threads et leur traçabilité par un intercepteur. Au
moment où l’intercepteur est déployé les threads existants (en noirs) peuvent potentiellement être en train
d’exécuter des méthodes du composant intercepté. Tous les nouveaux threads (en gris) sont enregistrés.
Au changement de génération, aucun thread de l’ancienne génération n’existe, alors tous les threads qui
s’exécute dans le composant intercepté sont connus. Par conséquent l’intercepteur contrôle totalement
l’état d’exécution du composant et peut déterminer un état stable.
thread id
0
t
dynamic interceptor deployement
=> generation swap request
generation termination
=> notification
F IG . 4.8 – Les générations de threads.
Pour gérer les générations de threads, nous avons ajouté un attribut generation aux composants job (voir chapitre 3, figure 3.8) et nous interposons un composant de gestion de générations de
threads au composant scheduler (figure 4.9). Ce composant intercepte les méthodes createJob() et
destroyJob() de l’interface Scheduler pour maintenir un compteur de générations de threads.
C’est également ce composant qui accepte les requêtes de changement de génération et qui notifie l’ap-
51
4.4. Exemples d’implémentation
Chapitre 4. Interface de programmation
pelant quand une génération s’est terminée. Cette notification est implémentée comme un callback sur
une interface de l’appelant.
job
job
job0
runner
scheduler
job
runner
scheduler
job1
job2
runner
scheduler
scheduler
K42
scheduler
...
thread
generation
management
scheduler
scheduler
F IG . 4.9 – L’architecture modifié des composants pour le multi-threading.
Anatomie et type d’intercepteur De la même façon que pour les intercepteurs de comptage de références, le type d’un intercepteur dynamique est confondu avec le type de l’interface qu’il peut intercepter.
La figure 4.10 montre un intercepteur dynamique de type I pour un type d’interface I.
Un intercepteur dynamique de type I fourni les interfaces suivantes :
– une interface serveur du type I,
– les interfaces de contrôle standard ComponentIdentity, BindingController et LifeCycleController,
– une interface de contrôle spécifique, appelée DynamicInterceptorStateController,
permettant de demander un changement d’état d’un intercepteur (suite à une requête de détection
d’un état stable, voir suite).
Chaque intercepteur dynamique de type I requière les interfaces suivantes :
– interface client du type I,
– une interface (mutex) pour implémenter l’exclusion mutuelle pour manipuler les données privées
de l’intercepteur,
– une interface sem (sémaphore), sert à bloquer les appels entrant lors d’un état stable,
– l’interface scheduler, sert à retrouver l’identifiant du thread courant lors d’un appel et son
enregistrement.
Déploiement des intercepteurs Contrairement aux intercepteurs de comptage de références, les intercepteurs dynamiques sont déployés à l’exécution. Lors du déploiement, les composants suivants doivent
être instanciés et liés (en utilisant des usines à composants) :
– pour chaque interface (de type I) du composant, un composant intercepteur (de type I),
– un composant sémaphore, dont l’interface semaphore sera liée à l’interface mutex de l’intercepteur nouvellement installé,
– un composant sémaphore, dont l’interface semaphore sera liée à l’interface sem de l’intercepteur nouvellement installé.
Par conséquent un système reconfigurable avec les intercepteurs dynamiques doit inclure les usines
de composants pour chaque type d’interface et une usine de sémaphores. C’est l’implémentation de
52
Chapitre 4. Interface de programmation
CI
4.4. Exemples d’implémentation
BC
LCC
LC
interception logic:
forward, reject, block
I
interceptor
component
I
mutex
sem
scheduler
interface
type I
F IG . 4.10 – Un intercepteur dynamique de type I.
l’interface ReconfigurationController qui instancie ces composant et qui est liée aux usines
respectives. La figure 4.11 montre un composant reconfigurable avec les intercepteurs dynamiques. Les
usines de composants (intercepteurs et sémaphores) sont des composants partagés.
CI
RC
implementation
CI
SC
interceptor
factory
(shared)
a client component
reconfigurable
component
semaphore
factory
(shared)
a client component
F IG . 4.11 – Déploiement des intercepteurs dynamiques.
Etats des intercepteurs Les intercepteurs dynamiques peuvent être dans trois états - Forward, Block,
ou Transfert (cf. (Soules et al., 2003)). Dans état Forward un intercepteur enregistre l’identifiant du
thread des appels entrants et les fait suivre au composant intercepté. Dans l’état Block, seuls les appels
récursifs peuvent poursuivre l’exécution, les autres threads étant bloqués. L’état Transfert correspond à
un état quiescent.
Algorithme général De la même manière que pour le comptage de référence, l’algorithme de détection
d’un état quiescent est éclaté dans la méthode suspend() de l’interface ReconfigurationController et la méthode notify() de l’interface Callback :
53
4.4. Exemples d’implémentation
Chapitre 4. Interface de programmation
v o i d s u s p e n d ( C o m p o n e n t I d e n t i t y component , C a l l b a c k cb )
{
ComponentIdentity i n t e r c e p t o r s [ ] ; / / in p r i v a t e data
. . . = cb ; / / s a v e cb t o p r i v a t e d a t a
DynamicInterceptorStateController ∗ istate ;
/∗ deploy i n t e r c e p t o r s ∗/
i t f s = CALL( component , g e t I n t e r f a c e s ( ) ) ;
for ( i t f : i t f s ) {
i t o r = CALL( i t o r f a c t o r y , new , i t f . t y p e ) ;
sem = CALL( s e m f a c t o r y , new ) ;
mutex = CALL( s e m f a c t o r y , new ) ;
B C i t o r = i t o r −>g e t I n t e r f a c e ( ” b i n d i n g − c o n t r o l l e r ” ) ;
CALL( B C i t o r , b i n d , ” sem ” , sem ) ;
CALL( B C i t o r , b i n d , ” mutex ” , mutex ) ;
/ / s c h e d u l e r w e l l −known
CALL( B C i t o r , b i n d , ” s c h e d u l e r ” , s c h e d u l e r ) ;
i n t e r c e p t o r s . add ( i t o r ) ;
}
/∗ request a suspend ∗/
c h a n g e i n t e r c e p t o r s s t a t e s ( Forward ) ;
}
void c h a n g e i n t e r c e p t o r s s t a t e s ( i n t s t a t e )
. . = s t a t e ; / / save s t a t e in p r i v a t e data
for ( i n t e r c e p t o r : i n t e r c e p t o r s ) {
i s t a t e = i n t e r c e p t o r s −>g e t I n t e r f a c e ( ” s t a t e − c o n t r o l l e r ” ) ;
CALL( i s t a t e , c h a n g e s t a t e , s t a t e ) ;
CALL( s e l f −>mutex , P ) ;
s e l f −>w a i t i n g ++;
CALL( s e l f −>mutex , V ) ;
}
L’implémentation de la méthode suspend() instancie les intercepteurs et les sémaphores, établit
les liaisons nécéssaires et demande un changement d’état aux intercepteurs. Le reste de l’algorithme est
implémenté dans la méthode notify() appelée à partir des intercepteurs.
La méthode notify() de l’interface Callback, appelée depuis le mécanisme de génération de
threads, est implémentée comme suit :
void n o t i f y ( )
{
int c u r r e n t s t a t e = s t a t e ; / / in p r i v a t e data ;
switch ( c u r r e n t s t a t e ) {
case Forward :
c h a n g e i n t e r c e p t o r s s t a t e s ( Block ) ;
case Block :
change interceptors states ( Transfer );
case Transfer :
C a l l b a c k cb = . . . / / r e t r i e v e f r o m p r i v a t e d a t a
CALL( cb , n o t i f y , 0 ) ;
}
}
A chaque changement de génération, cette implémentation fait évoluer l’état de l’intercepteur, quand
54
Chapitre 4. Interface de programmation
4.5. Conclusion
l’état Transfer est atteint, un état quiescent du composant est atteint – l’implémentation notifie l’appelant
(appel du callback de l’appelant).
La figure 4.12 montre l’intéraction entre les différents éléments d’un composant reconfigurable avec
le mécanisme des intercepteurs dynamiques – l’implémentation de ReconfigurationController,
les usines des intercepteurs et les intercepteurs eux-mêmes. La figure montre uniquement l’interaction
pour un intercepteur d’une interface du composant reconfigurable. Lors d’un changement de génération,
le mécanisme de génération de threads notifie l’appelant – méthode notify() décrite ci-dessus. Ce
motif d’interaction est répeté pour tous les composants à suspendre et par conséquent à tous les intercepteurs d’interface déployés. En particulier, le programme de reconfiguration est débloqué lorsque tous
les états quiescents sont atteints – le dernier callback du programme de reconfiguration est exécuté et
débloque le programme en appelant V() sur le sémaphore associé.
component-0
interceptor-0
reconfiguration
program
quiescent
state request
component-0
ReconfigurationController
thread
generation
management
suspend(callback)
dynamic
interceptor
factory
semaphore
factory
BindingController
LifeCycle
instanciate()
2x instanciate()
generation_swap
request(callback)
bind(sem)
bind(mutex)
n-times, for
n-interceptors
change_state
(Forward)
n-times, for
n-interceptors
callback()
quiescent
state request
component-i
suspend()
generation_swap
request(callback)
last thread
of current
generation
change_state
(Block)
n-times, for
n-interceptors
block(), P()
callback()
last thread
of current
generation
generation_swap
request(callback)
quiescent
state achieved
component-0
change_state
(Transfer)
n-times, for
n-interceptors
callback()
F IG . 4.12 – L’interaction des différents éléments de l’implémentation de la détéction d’un état quiescent
avec les intercepteurs dynamiques.
4.5
Conclusion
Dans ce chapitre, nous avons présenté une interface de programmation flexible et de bas-niveau, permettant d’ajouter aux composants d’un système Fractal les différents mécanismes pour la reconfiguration
dynamique.
Implémentation de l’interface de programmation Nous pouvons implémenter une variété de mécanismes de reconfiguration uniquement en combinant du contrôle actif (intercepteurs) et du contrôle passif
(implémentation des interfaces de contrôle en général). Par conséquent il est possible d’implémenter
l’interface de reconfiguration de façon orthogonale à la partie fonctionnelle du système, voire l’ajouter
de façon quasi-automatique par un compilateur.
55
4.5. Conclusion
Chapitre 4. Interface de programmation
Difficultés Ce chapitre révèle néanmoins les difficultés liées soit à l’implémentation des interfaces de
contrôle, soit à la programmation des reconfigurations :
– Les interfaces de contrôle étant indépendentes, il faut s’assurer que le système soit construit correctement, i.e. que toutes les interfaces nécéssaires soient incluses.
– La conception de l’interface de programmation ne garantit pas son utilisation correcte (par exemple
le bon ordre dans les invocations).
– Lors de la détection d’un état stable, suivant l’implémentation de l’interface ReconfigurationController, il est possible de créer un interblocage.
– Les exemples d’implémentation montrent une dépendance entre l’implémentation des interfaces
de contrôle et la partie fonctionnelle du système (sémaphores ou scheduler par exemple), par
conséquent il faut s’assurer que le système soit construit correctement, i.e. que toutes les dépendances soient satisfaites.
– Le programme de reconfiguration en C (pseudo-C) peut devenir complexe et reste de trop basniveau pour pouvoir bâtir une analyse du programme en vue d’une validation ou optimisation de
l’exécution. Un tel programme est également source d’erreur.
Vers la compilation de systèmes reconfigurables Les difficultés énumérées peuvent être levées en
adoptant une approche de construction de systèmes reconfigurables par compilation d’une part, et de
la compilation de programmes de reconfiguration d’autre part. Nous décrivons notre approche dans les
deux chapitres suivants : Compilation de systèmes reconfigurables et Compilation des programmes de
reconfiguration.
56
Chapitre 5
Compilation des systèmes reconfigurables
Dans le chapitre précédent nous avons présenté une interface de programmation flexible donnant
un accès de bas-niveau aux différents mécanismes de reconfiguration dynamique. Cette interface est
constituée de l’ensemble des interfaces de contrôle du système à l’exécution. Ces interfaces de contrôle
sont indépendantes de la partie fonctionnelle du système (ou des composants) et par conséquent il est
possible de les ajouter à l’architecture du système après la conception de cette dernière.
Dans ce chapitre nous décrivons comment cette interface de programmation de reconfigurations peut
être ajoutée automatiquement, par le compilateur de systèmes reconfigurables. L’automatisation de ce
processus présente l’intérêt de à la fois simplifier la construction des systèmes reconfigurables, mais
également à rendre ce procesus plus robuste dans la mesure où le compilateur vérifie la cohérence de la
spécification du système.
L’idée principale du compilateur de systèmes reconfigurables étant de transformer l’architecture
conçue par le concepteur du système en y ajoutant l’implémentation d’une interface de programmation
de reconfigurations.
Dans ce chapitre nous décrivons notre approche pour la compilation de systèmes reconfigurables.
Pour cela nous avons enrichi le compilateur Think ADL existant (décrit déjà dans (Ozcan, 2007; Leclercq
et al., 2007)). Plus particulièrement, nous discutons :
– le principe de la compilation des systèmes reconfigurables dans le contexte de la construction de
systèmes reconfigurables et de la programmations des reconfigurations,
– la structure du compilateur Think ADL existant,
– notre contribution au compilateur – les extensions pour spécifier les composants reconfigurables,
les transformations de l’architecture et génération des intercepteurs,
– un exemple de compilation d’un système reconfigurable.
5.1
Le principe de la compilation des systèmes reconfigurables
La compilation des systèmes reconfigurables, une des trois parties de notre proposition d’un modèle
de programmation de systèmes reconfigurables, est l’étape clé de ce processus – c’est l’étape qui détermine à la fois la constitution finale du système (i.e. les différents mécanismes de reconfiguration pour
chaque composant) et les méta-informations à transmettre au compilateur de programmes de reconfiguration.
Le support de compilation que nous avons réalisé peut être généralisé généralisées pour pouvoir être
réutilisé pour ajouter au compilateur le support de compilation d’autres aspects non-fonctionnels (comme
les composants sécurisés, comme décrit au chapitre 7).
57
5.2. Le compilateur Think ADL
Chapitre 5. Compilation des systèmes reconfigurables
Définition Sous la notion de compilation ou construction d’un système reconfigurable, nous comprenons le procédé suivant :
A partir d’une description architecturale d’un système, de l’implémentation des composants
et d’une spécification de composants reconfigurables, le compilateur produit à la fois une
image exécutable de ce système et des méta-données.
Ainsi, suivant cette définition, le concepteur spécifie les composants reconfigurables du système et le
compilateur en produit une image binaire, exécutable. L’ajout des différentes interfaces de contrôle et de
leurs implémentations est automatique et reste transparent au dévelopeur du système. L’image exécutable
du système peut être chargée et exécutée sur la plate-forme cible (load and boot). Les méta-données
peuvent être exploitées pendant la compilation des programmes de reconfiguration, décrite au chapitre
suivant. De plus cette définition dissocie la description architecturale du système et la spécification des
parties reconfigurables.
Les principes de compilation sont les suivants :
– Automatisation et simplification de la construction des systèmes reconfigurables. Le compilteur assiste le concepteur du système dans l’ajout des mécanismes de reconfiguration, laissant au concepteur le focus sur la conception du système lui-même. En effet, les éléments (interface de contrôle,
intercepteurs et autres composants) requis par les différents mécanismes de reconfiguration complexifient l’architecture du composant (ou du système entier). L’utilisation d’un compilateur rend
la construction des composants reconfigurables plus simple et moins sujet à l’erreur – le compilateur transforme l’architecture.
– Vérification de la cohérence. Le compilateur complète et vérifie que tous les éléments nécéssaires
aux composants reconfigurables soient bien inclus et liés correctement : implémentations des
interfaces de contrôle, intercepteurs, usines d’intercepteurs, liaisons, présence des interfaces de
transfert d’état etc. En particulier, comme les implémentations d’interfaces de contrôle peuvent
dépendre des composants fonctionnels (e.g. dépendance vers les usines de sémaphores), le compilateur vérifie les liaisons des implémentations d’interfaces de contrôle vers les composants fonctionnels.
– Génération des méta-données de reconfiguration. Le compilateur est capable de générer des métadonnées d’architecture, comme la description de l’architecture sous forme d’ADL, des informations sur l’endroit des symboles binaires associés à un composant données etc. Ces méta-données,
pouvant prendre des formes différentes, sont utilisées pour compiler et vérifier les programmes de
reconfiguration. Dans le chapitre 6, nous décrivons un compilateur de programmes de reconfiguration, utilisant uniquement les descriptions architecturales (ADL) et la spécification des composants
reconfigurables (décrites dans ce chapitre).
– Indépendance de la spécification de composants reconfigurables et la description d’architecture. La spécification des systèmes reconfigurables est indépendante de la description architecturale du système et constitue une entrée supplémentaire au compilateur. Cette indépendance
permet la réutilisation des composants dans des contextes différents - reconfigurables ou nonreconfigurables. Pour les mêmes raisons, il est simple de faire plusieurs versions d’un système,
reconfigurable ou non, selon les requis dans le temps, sans changer son architecture.
5.2
Le compilateur Think ADL
Pour mettre en oeuvre un compilateur de systèmes reconfigurables, nous avons étendu le compilateur
Think ADL existant, capable de compiler des images exécutables de systèmes à composants T HINK. A
cela, nous avons ajoutés des extensions qui ont pour but de permettre une mise-en-oeuvre d’une interface
de programmation de reconfigurations, telle que spécifiée par le concepteur du système reconfigurable.
58
Chapitre 5. Compilation des systèmes reconfigurables
5.2. Le compilateur Think ADL
Le compilateur actuel est décrit dans les travaux d’Erdem Özcan (Ozcan, 2007; Leclercq et al., 2007)
(voir également l’historique du compilateur Think ADL en annexe C). Ce compilateur est extensible –
peut être étendu par des tiers, à moindre effort – ce qui a permis de réaliser un ensemble d’extensions
(optionnelles) afin de construire des systèmes reconfigurables. Ici nous donnons uniquement un aperçu de
fonctionnement du compilateur pertinent à la description des extensions pour la construction de systèmes
reconfigurables.
Fonctionnalités du compilateur Le compilateur a les fonctionnalités suivantes :
– Support en entrée des langages ADL et IDL (concrètement des parseurs vers un format interne du
compilateur),
– Vérification de la cohérence architecturale,
– Génération du code C (ou glue code) pour un composant à partir de sa description architecturale
en format interne, en particulier la membrane du composant,
– Interface avec un compilateur C standard, tel que gcc pour produire une image binaire à partir des
sources C générés.
– Le compilateur est extensible à tout niveau d’architecture, par un mécanisme de plugin.
Architecture La figure 5.1 montre une architecture à gros grain simplifié du compilateur Think ADL.
Quatre composants sont le coeur du compilateur, chaque composant est lui-même découpé en composants à grain fin :
– Le module de chargement est responsable de construire un AST (abstract syntax tree) complet du
système à compiler à partir de sa description ADL et IDL pour les interfaces. L’architecture interne
de ce composant est une chaı̂ne de composant de chargement, chacun responsable que d’une tâche
spécifique, par exemple construire un noeud AST pour une interface, pour un composant ou pour
une liaison.
– Le module de traitement d’AST parcours l’AST (visiteur) et pour chaque noeud d’un type enregistre auprès de l’ordonnanceur un certain nombre de tâches de compilation à effectuer. Les tâches
peuvent avoir des dépendences vers d’autres tâches (par exemple pour générer une instance d’un
composant, il est nécéssaire de générer la définition du composant).
– Le module de génération de code contient l’implémentation des tâches de génération de code,
sous forme de composants de grain fin, par exemple le descripteur d’une interface est généré par
un composant, la définition du composant par un autre et son instance par un troisième composant.
– L’ordonnanceur exécute les tâches de compilation, après avoir ordonnée l’arbre de tâches enregistrées.
Le point essentiel de cette architecture est le découplage des dépendances entre les différentes tâches
de génération de code, via l’ordonnanceur, et la capacité de charger un composant (de chargement, de
traitement ou de génération de code) dynamiquement par le mécanisme de plugin, ce qui permet de
réaliser des extensions à un niveau arbitraire.
Flot d’execution, flot de données La figure 5.2 montre le flot d’exécution dans le compilateur. D’abord
un AST complet est construit par le module de chargement (vérification syntaxique, puis sémantique).
Ensuite cet AST est parcouru par le module de traitement qui est lié au module de génération de code
et par conséquent peut enregistrer les tâches de génération de code en parcourant l’AST. Finalement,
l’ordonnanceur exécute ces tâches de génération de code et les tâches liée à l’appel d’un compilateur C
pour produire l’exécutable final.
59
5.3. Mise-en-oeuvre avec Think ADL
Chapitre 5. Compilation des systèmes reconfigurables
module de
chargement
module de
traitement
d'AST
module de
génération
de code et
driver compil. C
ordonnanceur
Compilateur Think ADL
F IG . 5.1 – Architecture du compilateur Think ADL.
Formats internes L’architecture du système à compiler est représentée sous forme d’un AST. Cet AST,
dont la syntaxe est explicitée dans une grammaire explicite (sous forme de DTD), comprend à la fois la
représentation de l’ADL et de l’IDL. L’AST est construit pas les modules de chargement.
5.3
Mise-en-oeuvre avec Think ADL
Les extensions du compilateur pour ajouter un support de compilation d’aspects non-fonctionnels,
en particulier une interface de programmation de reconfigurations, sont au nombre de trois :
– la spécification des composants reconfigurables, indépendante de la description architecturale du
système, dans un langage dédié1 ,
– un support pour les transformations architecturale (d’AST), afin de d’étendre l’architecture de
l’utilisateur avec l’interface de reconfiguration, telle que spécifiée, en particulier l’inclusion des
différentes implémentations des interfaces de contrôle, et
– un support pour la génération des intercepteurs d’interfaces à partir de leurs descriptions IDL,
nécéssaire à l’implémentation des interfaces de contrôle.
Flot d’exécution La figure 5.3 complète le flot d’exécution de la compilation d’un système reconfigurable :
– L’utilisateur soumet au compilateur une spécification du système – description d’architecture et
spécification des composants reconfigurables.
– La spécification est évaluée et le support de FlexProp ajoute les propriétés aux noeuds AST des
composants reconfigurables.
– Le chargeur des plugins pour les transformations architecturales charge le plugin de la reconfiguration, tel que spécifié dans la partie definition de la propriété du noeud AST.
– La transformation architecturale est réalisée, modifiant l’architecture en incluant une interface de
reconfiguration, nécessitant la génération des intercepteurs.
– A partir de cet instant le processus de compilation de l’architecture est identique au compilateur
original – l’AST est vérifié sémantiquement et ensuite le module de traitement d’AST crée les
tâches de génération de code qui seront exécutées suivant leurs dépendances par l’ordonnanceur.
1
Dans les travaux en cours, (Think, n.d.), nous avons étendu l’expressivité de l’ADL et il est désormais possible d’appliquer
à un système des extensions écrites également en ADL, rendant inutile l’emploie d’un langage dédié.
60
Chapitre 5. Compilation des systèmes reconfigurables
.fractalA
.fractalA
DSL
DL
DL
.fractalA
.fractalA
IDL
DL
DL
.fractal
Implém
.fractal
.c,
cpp,
ADL
ADL
DSL
L
ADL
...
.java
ID
.fractal
ADL
.fractal
ADL
ADL
5.3. Mise-en-oeuvre avec Think ADL
Analyseurs
syntaxiques
AST
Analyseurs
sémantiques
AST
Correct
Module de
traitement
d'AST
Module de chargement
Graphe
de
tâches
Génération
de code
Ex
ec
Vérification
uti
on
Execution
Moteur
d'exécution
Liste de
tâches
Résolution de
dépendences
n
tio
cu
e
Ex
Tâche
1
Ordonnanceur
Graphe
de
tâches
Tâche
2
Tâche
3
Tâche
4
Déploiement
F IG . 5.2 – Flot de données et flot d’exécution dans le compilateur Think ADL (figure reproduite avec
l’aimable autorisation d’A. E. Özcan).
– A la fin, le compilateur aura généré une image binaire d’un système reconfigurable.
5.3.1
Spécification des composants reconfigurables
Les composants reconfigurables d’un système concret sont spécifiés dans un fichier indépendant de
sa description architecturale. Ce fichier contient la spécification des composants que le concepteur veut
reconfigurables et des paramètres nécessaires à la transformation de l’architecture. Les spécifications sont
écrites dans un langage déclaratif, appelé FlexProp. Une spécification permet d’associer des propriétés
à un composant, en particulier la propriété que le composant est reconfigurable2 . Le compilateur lit et
interprète ce fichier, en attachant les propriétés spécifiées aux noeuds de l’AST concernés.
5.3.1.1
Un langage déclaratif
Spécifications comme propriétés La spécification d’un composant reconfigurable est réalisée comme
une propriété particulière attachée au noeud AST représentant le composant. La conception du langage
FlexProp est fortement liée au format des noeuds AST des propriétés :
properties ::= (property)*
property ::= definition (parameter)*
parameter ::= name, value
definition ::= <identifier>
Chaque propriété est identifiée par un champ, nommé definition. Le noeud propriété est un
conteneur de paramètres. Un paramètre est un couple associant un nom à une valeur. Ces paramètres se2
Dans le chapitre 7, nous montrons comment les extensions du compilateur, et donc en particulier le langage FlexProp, sont
utilisées pour construire des architectures sécurisées
61
5.3. Mise-en-oeuvre avec Think ADL
.fractalA
.fractalA
Implém
DL
DL
C
.fractal
.fractal
FlexProp
ADL
ADL
SL
D
L
ADL
Analyseurs
syntaxiques
AST
AST
génération
intercepteurs
AST
ID
.fractal
ADL
.fractal
ADL
ADL
extension
Reconfiguration
AST
.fractalA
.fractalA
IDL
DL
DL
Chapitre 5. Compilation des systèmes reconfigurables
Transformations
d'architecture
AST
Analyseurs
sémantiques
AST
Correct
Module de
traitement
d'AST
Module de chargement
Graphe
de
tâches
Tâche
1
Ordonnanceur
Génération
de code
Execution
Moteur
d'exécution
Liste de
tâches
Résolution de
dépendences
Graphe
de
tâches
Tâche
3
Tâche
2
Tâche
4
extensions au compilateur existant
F IG . 5.3 – Flot de données et d’exécution dans le compilateur Think ADL étendu pour compiler des
architectures reconfigurables (figure modifiée à partir de l’original d’A. E. Özcan).
ront passés au plugin de transformation d’architecture et par conséquent sont spécifiques à une propriété
et plugin donnés.
Syntaxe du langage
– A chaque système reconfigurable est associé un fichier FlexProp, de spécification de propriétés.
– Un fichier FlexProp est constitué d’une suite de spécifications de propriétés.
– Chaque spécification est composée d’une partie droite – séléction de composants – et d’une partie
gauche – spécification de propriétés. La partie droite est affectée à la partie gauche ( :).
– La séléction des composants (partie droite) permet de spécifier à quel composant dans l’architecture du système doit être appliquée la propriété. Il s’agit d’une expression de chemin dans le
système à composant, les différents éléments du chemin sont séparés par un ’slash’ (/).
– La spécification des propriétés est une expression s’apparentant à un appel de fonction – le nom
correspond à l’identifification de la propriété (champ definition), les arguments étant des
paires de paramètres (nom = valeur).
Le langage FlexProp sert à spécifier toute propriété non-fonctionnelle liée à un composant. A titre
d’exemple, à part la spécification des composants reconfigurables, nous l’utilisons aussi afin de spécifier
les composants sécurisés, les optimisations architecturalles souhaitées etc. Dans sa forme déclarative
actuelle, l’expressivité du langage reste très restreinte et verbeuse, nous envisageons des évolutions,
permettant notamment de spécifier de façon cohérente plusieurs propriétés qui donnent lieu à des transformations d’architecture.
Exemple Pour spécifier que le sous-composant counter du composant kernel est reconfigurable
utilisant le mécanisme de comptage de référence, on écrirait :
kernel/counter : reconfigurable(type=thread-counting,
semaphore-reconfig=sem_reconfig.semaphore,
mutex-reconfig=sem_mutex.semaphore,
semaphore-factory=sf.factory)
62
Chapitre 5. Compilation des systèmes reconfigurables
5.3. Mise-en-oeuvre avec Think ADL
La propriété reconfigurable accepte un premier paramètre qui détermine le type de mécanisme
d’état stable à inclure au composant. Les paramètres supplémentaires (semaphore-reconfig, mutex-reconfig, semaphore-factory) sont spécifiques au type de transformation et dans ce cas
permettent de résoudre les dépendences des implémentations des interfaces de contrôle vers les composants fonctionnels du système.
5.3.1.2
Mise-en-oeuvre
Nous avons dévelopé un support pour le langage FlexProp dans le compilateur Think ADL. Ce
support intègre un parseur du langage capable de trouver les noeuds représentant les composants à
sélectionner et leur attacher un noeud AST de propriétés.
Ce support, implémenté sous forme d’un composant, est intégré dans la phase de load, dans le module
de chargement.
5.3.2
Transformations architecturales
La transformation architecturale d’un système a pour but d’ajouter à ce dernier une interface de
reconfiguration spécifiée avec le langage FlexProp. Plusieurs types de modification d’architecture sont
nécéssaires pour pouvoir ajouter une interface de reconfiguration telle que décrite dans le chapitre précédent :
– ajout des interfaces de contrôle et de leurs impléméntations,
– ajout des intercepteurs et des usines d’intercepteurs,
– modification des liaisons de composants, et
– ajout éventuel des composants fonctionnels à l’architecture.
Ces transformations d’architecture ne sont pas locales au composant reconfigurable ou au composant
qui l’englobe, mais selon le mécanisme de reconfiguration la transformation impacte potentiellement
tout le système (tel est le cas par exemple pour les intercepteurs dynamiques où une usine d’intercepteurs
de différents types doit être générée et partagée dans tous les composants reconfigurables). Il est alors
nécéssaire de manipuler l’architecture dans son ensemble.
Vérifications Avant la transformation de l’architecture, le compilateur peut vérifier sa cohérence par
rapport aux requis des différents mécanismes de reconfiguration :
– Les composants reconfigurables avec état doivent fournir une implémentation de l’interface StateTransferController. C’est au programmeur du composant de la fournir et son existance
de cette interface est vérifiée pendant la transformation.
– Le compilateur peut vérifier la conformité des interfaces de contrôle fournies dans l’architecture,
conformité par rapport aux requis définies dans le chapitre 4. Ces requis peuvent différer suivant
les mécanismes de reconfiguration spécifiés.
– Les implémentations de l’interface de reconfigurations peuvent avoir des dépendances vers des
composants fonctionnels. Il faut s’assurer de l’existance de ces composants.
– ...
5.3.2.1
Mise-en-oeuvre
Deux choix d’implémentation sont possibles pour les transformations d’architecture :
– Générer une nouvelle description d’architecture reconfigurable Cette approche consiste à générer
une description d’architecture reconfigurable à partir d’une description d’architecture initiale,
écrite par l’utilisateur. Cette génération serait faite avant la compilation du système (par un frontend ad-hoc).
63
5.3. Mise-en-oeuvre avec Think ADL
Chapitre 5. Compilation des systèmes reconfigurables
– Modifier l’architecture pendant la compilation L’approche consiste à modifier la représentation
interne de l’architecture pendant la compilation du système, l’AST dans notre cas.
Nous avons opté pour la modification pendant la compilation, car cette solution présente à longtermes des perspectives d’intégration intéréssantes, comme la combinaison des différents aspects nonfonctionnels ou la combinaison de la reconfiguration et des optimisations architecturales. Nous proposons une première implémentation des transformations architecturales ne visant pas à lever les problèmes
de combinaisons des différentes transformations qui ne font pas l’objet de ces travaux. Néanmoins, dans
la partie évaluation nous décrivons un prototype d’un système à composants sécurisé, dont les politiques
de sécurité peuvent être reconfigurées dynamiquement. Ce système a été compilé en appliquant deux
transformations architecturales - la reconfigurabilité et la sécurité.
Les transformations d’architectures sont réalisées après la construction de l’AST du système à construire (i.e. à la fin de la chaı̂ne de composants dans le module de chargement). A la chaı̂ne des composants
constituant la chaı̂ne de chargement, nous avons ajouté un composant supplémentaire – un chargeur de
plugins, qui permet de charger et exécuter des plugins de transformation d’AST. De cette façon plusieurs
plugins (i.e. transformations) peuvent être chargés et exécutés. Le plugin de transformation est exécuté
une fois qu’une représentation complète de l’architecture est construite, mais avant que celle-ci soit
vérifiée. Ainsi, toute transformation est soumise aux vérifications standards faites par le compilateur.
Le plugin à charger est lui-même un composant, écrit en Java, implémentant une interface bien
définie. L’AST complet est passé au plugin de transformation qui peut le modifier à sa guise, en particulier, appliquer de façon programmatique une transformation aux composants – noeuds AST – ayant
des propriétés particulières (e.g. la reconfigurabilité).
5.3.3
Intercepteurs et usines d’intercepteurs
Les intercepteurs sont des composants Think dont le but est de faire un pré-traitement, suivi d’un
éventuel appel à l’interface interceptée, et un post-traitement. Un intercepteur a un type - le type de l’interface qu’il intercèpte, et une fonctionalité spécifique (par exemple un intercepteur de contrôle d’accès,
cf. chapitre 7 ou un intercepteur de comptage de références pour la reconfiguration dynamique).
Le concept d’intercepteur n’est pas exclusif à la reconfiguration et de façon générale les intercepteurs
permettent de construire un contrôle actif (i.e. pendant l’exécution, à chaque invocation du composant
intercepté) lors d’un accès au composant. Comme expliqué au chapitre précédent, les mécanismes de
reconfigurations sont implémentés en partie avec des intercepteurs.
De plus, pour certains mécanismes (comme les intercepteurs dynamiques décrits au chapitre précédent), il est nécéssaire de disposer à l’exécution d’une usine d’intercepteurs. La fonctionnalité de cette
usine est d’instancier un intercepteur dynamique, de type I, correspondant au type d’interface. Une telle
usine doit pouvoir être générée automatiquement de façon transparente à l’utilisateur. Les usines d’intercepteurs sont des composants composites qui regroupent les usines particulières d’intercepteurs. Ces
usines ne nécéssitent pas de support particulier, elle peuvent être créés pendant la transformation de
l’architecture comme un composant composite regroupant plusieurs composants.
5.3.3.1
Mise-en-oeuvre
Nous avons intégré au compilateur un support générique de génération d’intercepteurs et de leurs
usines. Ce support est réalisé sous forme d’un composant inclus dans la chaı̂ne des composants du module
de chargement, capable de générer une représentation interne (AST) d’un intercepteur spécifique et son
code C. Ce composant est générique et la génération d’un intercepteur est paramétrée avec deux fichiers
templates :
64
Chapitre 5. Compilation des systèmes reconfigurables
5.3. Mise-en-oeuvre avec Think ADL
– Un fichier template sert à instancier la représentation interne d’un intercepteur. Ce fichier est en
réalité une définition ADL paramétrable (en XML). Pour chaque composant intercepteur, cette
définition est instanciée (par la chaı̂ne du load du compilateur) avec les bons arguments. Par
exemple, la figure 5.3.3.1 montre une définition ADL paramétrable pour les intercepteurs de comptage de référence.
– Le deuxième template sert à instancier le code d’une méthode d’un intercepteur. Il s’agit d’un code
C générique qui est personnalisé pour chaque méthode de l’intercepteur. La figure 5.3.3.1 montre
un exemple simple d’un tel template, qui a pour l’unique fonctionnalité de faire suivre les appels
vers l’interface interceptée. Les mots-clés du template (__type__, SRV INTERCEPTOR METHOD et CLT_INTERCEPTOR_METHOD) sont remplacés par le code réel de l’intercepteur3 .
La génération des intercepteurs est donc automatisée, l’utilisateur doit uniquement écrire le template de
définition et le template de code C.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN"
"classpath://org/objectweb/think/adl/parser/xml/think.dtd">
<definition name="fractal.lib.reconfig.StaticStub"
arguments="name,signature,implem">
<component name="${name}">
<interface name="stub" role="server" signature="${signature}" />
<interface name="target" role="client" signature="${signature}" />
<interface name="lifecycle" role="server"
signature="fractal.api.reconfig.StaticStub" />
<interface name="lifecycle-controller" role="server"
signature="fractal.api.LifeCycleController" />
<interface name="mutex" role="client" contingency="optional"
signature="activity.api.Semaphore" />
<interface name="sem" role="client" contingency="optional"
signature="activity.api.Semaphore" />
<interface name="cb" role="client" contingency="optional"
signature="fractal.api.reconfig.Callback" />
<interface name="sf" role="client"
signature="activity.api.SemaphoreFactory" />
<content class="${implem}" language="thinkC" >
<directive language="C">
<include file="fractal.lib.reconfig.static_stubs_helper" />
</directive>
</content>
</component>
</definition>
F IG . 5.4 – Template de construction ADL des intercepteurs de comptage de références.
3
Pour des raisons de syntaxe il existe une déclinaison de ce template pour les fonctions void.
65
5.4. Conclusion
Chapitre 5. Compilation des systèmes reconfigurables
type
SRV INTERCEPTOR METHOD ( )
{
type
val ;
v a l = CLT INTERCEPTOR METHOD ( ) ;
return val ;
}
F IG . 5.5 – Template de construction C des intercpteurs génériques.
5.4
Conclusion
Les extensions que nous avons apportées au compilateur du canevas Think permettent d’assister le
développeur d’un système reconfigurable, en automatisant les tâches liées à la génération d’une interface
de reconfiguration. De plus, ces extensions sont génériques et peuvent être réutilisées pour ajouter un
support d’autres aspects non-fonctionnels dans le compilateur (comme nous le montrons au chapitre 7.
Nous avons décrit dans ce chapitre un prototype de compilateur de systèmes reconfigurable. Techniquement loin d’être parfait, ce prototype a néanmoins permis de démontrer le concept et a permis de
dégager les perspectives de ce travail, abordées ultérieurement.
66
Chapitre 6
Reconfiguration des architectures Think
avec FScript
L’interface de reconfiguration que nous avons conçue est riche, mais reste de très bas niveau pour
un programmeur de reconfiguration, raisonnant idéalement au niveau architectural. Alors qu’un langage
de reconfiguration d’architectures Fractal (un langage dédié, domain specific language ou DSL) appelé
FScript existe, l’utilisation d’un tel langage dans les architectures systèmes pose un certain nombre de
problèmes que nous abordons dans ce chapitre, notamment la conception d’un support d’exécution efficace.
Nous avons dévelopé un support de compilation et d’exécution des programmes FScript pour les
architectures systèmes à base de composants Think. Ce support – un compilateur FScript, générant des
composants de reconfiguration en C – est le dernier maillon de notre proposition pour la construction
de systèmes reconfigurables et la programmation des reconfigurations, articulée autour de l’architecture.
L’utilisation de ce support pour reconfigurer un système est facultative – un système qui fourni une interface de programmation de reconfigurations est autonomne par rapport à la reconfiguration dynamique
et peut être reconfiguré sans l’utilisation de FScript.
Ce chapitre donne un aperçu du langage FScript. Ensuite, nous discutons les différentes possibilités
d’implémentation d’un support pour un tel langage, en particulier la distribution de ce support. Finallement nous décrivons la solution choisie pour réaliser ce support – un compilateur FScript générant un
code de reconfiguration, ainsi qu’un support minimal nécéssaire pour exécuter le code de reconfiguration
compilé.
6.1
Le langage FScript
FScript est un langage dédié à la reconfiguration des architectures Fractal, conçu par Pierre-Charles
David (David, 2005; David & Ledoux, 2006). L’interface de programmation des reconfigurations, décrite
au chapitre 4, réalisée avec les contrôleurs Fractal est puissante et de bas niveau, néanmoins programmer les reconfigurations à ce niveau d’abstraction, i.e. en C dans le cas de Think, est verbeux, difficile
à comprendre et difficile à analyser. Pour s’en convaincre, il suffit d’analyser l’exemple du code de
reconfiguration du chapitre 4, section 4.3. Et encore, ce code ne fait aucune vérification lors de la reconfiguration, comme par exemple la vérification de la compatibilité des types des interfaces. FScript lève
ces limitations et permet de programmer les reconfigurations au niveau d’abstraction de l’architecture,
tout en préservant la puissance de l’interface de programmation offerte par les interfaces de contrôle de
Fractal.
67
6.1. Le langage FScript
6.1.1
Chapitre 6. Reconfiguration avec FScript
Eléments du langage
FScript est un langage impératif, avec comme particularité i) un sous-langage spécifique pour des
expressions, appelé FPath, permettant de naviguer dans une architecture Fractal et en séléctionner des
éléments, et ii) des actions permettant d’effectuer des modifications d’une architecture Fractal.
Expressions FPath
FScript utilise une grammaire particulière pour les expressions, FPath (inspirée de XPath pour les
documents XML). FPath supporte d’une part les expressions classiques (les littéreaux – chaı̂ne de caractères et nombre flottans, arithmétique, logique, comparaison, référencement de variables (déclarées
dans FScript) et fonctions) et d’autre part une syntaxe particulière qui permet de naviguer dans une
architecture Fractal et en séléctionner des élements.
Une architecture Fractal est vue comme un graphe où les noeuds représentent les éléments de l’architecture. Les noeuds sont connéctés par des arcs étiquetés, représentant une relation entre les éléments. Par
exemple, un composant avec plusieurs interfaces sera représenté comme un noeud composant, connecté
à tous ces noeuds interfaces par les arcs annotés interface. Les éléments d’une architecture, i.e. les
noeuds du graphe, sont séléctionnés avec une expression FPath qui représente leur(s) chemin(s). Chaque
pas dans un chemin commence à un ensemble initial de noeuds et séléctionne un nouveau pas en suivant une des relations. L’ensemble des noeuds finaux peut être filtré suivant un nom ou par un prédicat
(expression), incluant d’autres expressions de chemins. Par exemple l’expression suivante permet de
séléctionner toutes les interfaces alloc des sous-composants du composants kernel, lui-même sous
composant de l’ensemble racine (la variable $root$ étant bien-connue) :
$root/child::kernel/child::*/interface::alloc
Actions et fonctions
Un programme FScript est constitué d’un ensemble de définitions de procédures - fonctions et actions. Les fonctions sont sans effets de bord sur l’architecture, alors qu’une action modifie une architecture Fractal. Le corps d’une définition de procédure est constitué d’une séquence d’instructions. FScript
n’autorise pas la définition de procédures récursives.
Structures de contrôle
FScript offre un ensemble classique de structures de contrôle :
– blocs d’instructions - un groupement d’instructions délimité par { et },
– alternative - if/then/else,
– itération - foreach i in path do { body }, et
– retour explicite - return.
L’utilisation d’un ensemble restreint de structures de contrôles et l’interdiction de définitions récursives, permet à l’implémentation de l’interprète FScript de guarantir la terminaison des reconfigurations
(David, 2005).
Variables et affectations
FScript supporte trois types de variables avec des portées différentes - variables globales, locales et
paramètres passés lors d’une invocation de procédure. Par exemple l’instruction suivante, à l’intérieur
d’une définition d’action, défini une variable locale :
foo := <expression>;
68
Chapitre 6. Reconfiguration avec FScript
6.1.2
6.1. Le langage FScript
Bibiolothèque d’actions et de fonctions
FScript fourni une librairie extensible de fonctions primitives et d’actions qui donne à l’utilisateur
l’accès à l’API Fractal. Ces primitives peuvent être combinées de façon à créer des scripts de reconfiguration complexes.
A la bibliothèque standard, nous avons ajouté les actions suspend(parent, sub-component)
et resume(parent, sub-component) qui correspondent à l’invocation de l’interface ReconfigurationController définie dans le chapitre 4. Le tableau 6.1 récapitule les actions standard de
FScript et leur correspondance avec l’API Fractal, i.e. les interfaces de contrôle.
Paramétrage des composants – AttributeController
set-value(attribute, value)
Renommage d’un composant – NameController
set-name(component, name)
Ajout et suppression de sous-composants – ContentController
add(composite, sub-component)
remove(composite, sub-component)
Manipulation des liaisons – BindingController
bind(client-itf, server-itf)
unbind(client-itf)
Detéction d’un état quiescent – ReconfigurationController
suspend(parent, sub-component)
resume(parent, id)
Cycle de vie – LifeCycleController
start(component)
stop(component)
Instantiation de composants
create(component-definition)
TAB . 6.1 – La bibliothèque des actions FScript.
6.1.3
Exemples
Voici un exemple d’un programme FScript simple :
1
2
3
4
5
6
7
8
9
10
11
12
action rebind(parent, itfname, srvitf) = {
// Select all sub-components of $parent
subcomponents := $parent/child::*;
foreach comp in $subcomponents do {
// Select the interface $itfname of $comp
cltitf = $comp/interface::$itfname[bound(.)]
[required(.)]
// Modify the binding
bind($cltitf, $srvitf);
}
69
6.2. Supports d’exécution pour FScript
13
Chapitre 6. Reconfiguration avec FScript
}
Cet exemple défini une nouvelle action de reconfiguration, appelée rebind. Cette action est utilisée
lors d’un remplacement d’un composant pour rediriger les références clientes vers le nouveau composant.
La première expression FPath (ligne 3) peut être lue ainsi : en commençant au composant $parent,
séléctionner dans l’architecture tous ses sous-composants (child::*). Ensuite, pour tous ces composants (foreach, ligne 5), retrouver l’interface cliente dont le nom est $itfname (ligne 7). Nous voulons modifier uniquement les liaisons existantes, donc affecter uniquement les interfaces liées (prédicat
bound(.)). De plus, le programme suppose que le composant ne peut avoir plusieurs interfaces du
même nom. Une fois l’interface cliente retrouvée, le programme modifie sa valeur pour référencer l’interface $srvitf (ligne 11).
L’exemple de reconfiguration du chapitre 4 (section 4.3), sans le transfert d’état, pourrait1 être programmé en FScript de la façon suivante (en utilisant l’action rebind(), ligne 7) :
1
2
3
4
5
6
7
8
9
10
6.2
k = $root/child::kernel;
n := new(’new_alloc’);
o := $k/child::alloc;
add($k, $n);
suspend($k, $o);
stop($o);
rebind($k, alloc, $n/interface::alloc);
start($n);
resume($k);
remove($k, $o);
Supports d’exécution pour FScript
La définition du langage FScript est étroitement liée au modèle Fractal. De la même façon que le
modèle Fractal est implémenté par le canevas Think, il est nécéssaire de concevoir un support d’exécution
pour le langage FScript, pour pouvoir l’utiliser avec les systèmes à base de composants Think. Cette
relation est montrée sur le schéma de la figure 6.1.
Langage
FScript
définition
(programmation)
reconfigurations
réalisation
(implémentation)
?
support
FScript
Modèle
à composant
Fractal
implémentation
exécution
reconfiguration
Think
composants
"natifs" en C
F IG . 6.1 – Quel support pour FScript ?
Il existe plusieurs solutions pour concevoir un support d’exécution pour FScript, suivant la répartition
de ce support entre la système cible de la reconfiguration et d’autres plate-formes de support. Chaque
1
Nous faisons l’hypothèse que le compilateur (ou interprète) FScript est capable de générer l’interface Callback et gérer
la suspension du programme de reconfiguration en attente de la détection d’un état stable
70
Chapitre 6. Reconfiguration avec FScript
6.2. Supports d’exécution pour FScript
implémentation aura des propriétés différentes – complexité, l’utilisation des ressources, garanties offertes (terminaison, atomicité etc.), ...
6.2.1
Répartition du support FScript
La figure 6.2 montre les deux répartitions possibles du support pour FScript. La première consiste à
fournir un support d’exécution sur la plate-forme cible, en d’autres termes un interprète FScript réalisé
en C. La deuxième solution consiste à répartir le support de FScript sur plusieurs plate-formes, afin
d’alléger le support nécéssaire sur la plate-forme cible. Typiquement, cette solution est intéréssante pour
les architectures embarquées contraintes en ressources matérielles, comme les noeuds de capteurs.
FScript
Fractal
support
FScript
Think
FScript
Fractal
support
FScript
Think
compilateur, ou
interprète distribué
interprète natif
a) support FScript centralisé, natif
b) support FScript distribué
plate-forme matérielle
distincte
F IG . 6.2 – Distribution du support pour FScript.
Le choix de répartition du support FScript conduit à trois différents types d’implémentation, que nous
décrivons ici :
– un interprète FScript,
– un compilateur FScript, et
– un système ”proxy”.
6.2.1.1
Interprète FScript
FScript
Reconfiguration
Program + new
components
Device +
Reconfigurable
Device-OS +
FScript interpreter
communication
link
reconfiguration
Un interprète FScript en natif (càd en C) est un programme embarqué sur le terminal, capable
d’exécuter la reconfiguration dynamique à partir du code de reconfiguration écrit en FScript. La figure
6.3 illustre le déploiement d’un interprète en natif.
F IG . 6.3 – Interprète FScript.
Un interprète natif analyse syntaxiquement le programme FScript (parsing), le vérifie éventuellement
et exécute les actions spécifiées. La complexité des vérifications et les garanties offertes ont un impact
sur la complexité de l’implémentation de l’interprète et aussi sur l’utilisation des ressources matérielles
sous-jacentes. Par exemple, l’interprète de FScript pour Julia (l’interprète original, en Java, pour les
71
6.2. Supports d’exécution pour FScript
Chapitre 6. Reconfiguration avec FScript
composants en Java) offre des garanties d’atomicité, d’isolement et de terminaison des reconfigurations.
Ceci en implémentant un système transactionnel. De plus, un interprète FScript pour instancier de nouveaux composants (dont les usines ne font pas forcément partie du système à l’exécution) l’interprète
requière que le système fourni un chargeur dynamique pour charger le code et les données des nouveaux
composants.
6.2.1.2
Compilateur FScript
La deuxième approche pour implémenter un support pour FScript consiste à réaliser un compilateur
FScript sur une machine différente de la plate-forme cible. Le compilateur analyse le programme FScript
et génère le code de reconfiguration sous une forme binaire, directement téléchargeable et exécutable par
le système cible. Toute la compléxité liée au support de FScript est sur la machine de compilation et le
système cible ne fournit qu’un support minimal pour charger et exécuter le code binaire de reconfiguration et des nouveaux composants.
La compilation des programmes FScript est basée sur une représentation de l’architecture du système
à l’exécution. Plusieurs variantes d’implémentation sont possibles pour garantir que la représentation de
l’architecture reflète l’architecture actuelle à l’exécution. Les figures 6.4 et 6.5 illustrent deux exemples
d’implémentation.
Dans le premier cas, figure 6.4, un protocol de synchronisation de représentation architecturale est
mis en place afin de retrouver l’architecture actuelle juste avant la compilation d’une reconfiguration.
Dans ce cas il est nécéssaire d’interdire toute modification du système entre le moment de synchronisation et la reconfiguration (hypothèse de non-évolution de l’architecture).
FScript
Reconfiguration
Compilation Host
FScript
Reconfiguration
Program
device
configuration
ADL/AST
reconfiguration
component
communication
link
Device +
Reconfigurable
Device-OS
reconfiguration
F IG . 6.4 – Un compilateur FScript – synchronisation des vues architecturales avant la compilation.
Le deuxième cas, figure 6.5, est une simplification du cas précédent où l’implémentation fait l’hypothèse que l’architecture du système est identique à sa description initiale (en ADL) – l’architecture du
système n’évolue que par des reconfigurations externes (ou les parties pouvant évoluer sont identifiées,
par exemple des usines à composants). Dans ce cas aucune synchronisation n’est nécéssaire avant la compilation d’une reconfiguration et à chaque reconfiguration, la machine de compilation maintient un ADL
qui reflète l’architecture actuelle de la plate-forme cible. (Cette solution nécéssite quand même un protocol qui confirmerait le succès d’une reconfiguration, afin de mettre effectivement à jour la représentation
de l’architecture vue par le compilateur).
L’enjeu dans une approche compilée est la maı̂trise du code généré en terme de complexité et d’efficacité. Dans la section suivante nous allons décrire notre implémentation d’un compilateur FScript, les
propriétés garanties et le compromis de l’utilisation des ressources.
72
Chapitre 6. Reconfiguration avec FScript
6.3. Un compilateur FScript
external device
configuration
(meta-data: ADL +
binary image)
FScript
Reconfiguration
Compilation Host
reconfiguration
component
FScript
Reconfiguration
Program
Device +
Reconfigurable
Device-OS
reconfiguration
communication
link
F IG . 6.5 – Un compilateur FScript – la plate-forme cible évolue uniquement via les reconfigurations
FScript (aucune synchronisation des vues architecturales nécéssaire).
6.2.1.3
Utilisation d’un système ”proxy”
Il existe une troisième alternative d’implémentation d’un support de FScript où la machine de compilation exécute la reconfiguration sur un système à composant local, dont l’architecture est identique à
l’architecture de la plate-forme cible, figure 6.6. Le système à composant local joue le rôle d’un proxy et
toute opération de modification de l’architecture locale (donc tout appel à une interface de contrôle) est
répercutée sur la plate-forme cible – les interfaces de contrôle sont implémentées sous forme de proxy.
Cette approche fait également une hypothèse forte sur les capacités de l’évolution de la configuration du
système distant.
FScript
Reconfiguration
Compilation Host
(Re)Configuration
API
proxy
Device +
Reconfigurable
Device-OS
FScript
Reconfiguration
Program
communication
link
F IG . 6.6 – Utilisation d’un système de proxy pour exécuter un programme de reconfiguration FScript.
6.3
Un compilateur FScript
Nous avons conçu un prototype de compilateur FScript pour un usage dans le contexte des réseaux
de capteurs. Dans la suite de ce chapitre nous décrivons l’implémentation de ce compilateur, le chapitre
suivant 7 évaluera cette approche dans le domaine ciblé.
Le compilateur répartit le support de FScript entre la plate-forme cible et une plate-forme appelée
hôte de compilation. Cette dernière compile un composant binaire à partir d’un programme FScript,
contentant à la fois un composant de reconfiguration et éventuellement les nouveaux composants à instantier. Nous supposons l’existance d’un lien de communication entre la plate-forme cible et l’hôte de
compilation.
73
6.3. Un compilateur FScript
6.3.1
Chapitre 6. Reconfiguration avec FScript
Défis de l’implémentation
Plusieurs défis sont liées à une implémentation d’un compilateur FScript pour les architectures Think.
– Comment assurer la cohérence des vues de l’architecture ? L’hôte de compilation qui va compiler un programme FScript doit se baser sur une représentation de l’architecture du système
cible. Il faut alors s’assurer que cette représentation reflète réellement l’architecture du système
à l’exécution. Typiquement, la description en ADL d’un système reflète son état lors de son
déploiement. Néanmoins, si on fait l’hypothèse que le système évolue uniquement par des reconfigurations depuis l’hôte de compilation, ce dernier peut maintenir sa propre représentation du
système cible.
– Comment retrouver les composants sur le système cible ? Lors de la compilation, les entités manipulées dans les programmes FScript (composants, liaisons, interfaces ...) doivent être translatées
vers des références réelles du système à l’exécution. En principe les capacités d’introspection
d’une architecture Fractal permettent de retrouver les éléments d’une architecture à partir de leur
description textuelle telle qu’écrite dans un programme FScript.
– Quelles sont les propriétés garanties par le compilateur ? Par exemple, l’implémentation originale
de FScript (un interprète en Java) garantie les propriétés telle que l’atomicité des reconfigurations
ou leur isolation.
– Quel compromis entre les propriétés garanties et les différentes ressources utilisées ? La complexité de la compilation (l’implémentation des garanties) est en principe contrainte uniquement
par les capacités de l’hôte de compilation, néanmoins, pour garantir certaines propriétés (par
exemple, un degré de gestion d’erreur), il peut être nécéssaire de générer un code de reconfiguration plus ou moins complexe. Par conséquent, l’implémentation des garanties peut avoir un
impact sur l’utilisation des ressources de la plate-forme cible (mémoire, temps de calcul, bande
passante etc.). Pour un usage sur des plate-forme matérielles contraintes en ressources, comme les
réseaux de capteurs, il est nécéssaire de trouver un compromis entre les propriétés qui peuvent être
garanties et les l’utilisation des ressources sur la plate-forme cible.
6.3.2
Caractéristiques du prototype
Le principe du compilateur FScript, que nous avons conçu, repose sur la simulation d’une reconfiguration sur une architecture système locale, équivalente à l’architecture du système cible. Pour cela, nous
réutilisons l’interprète FScript original. Le résultat de la simulation est un ensemble de modifications
d’architecture en terme d’opérations sur les interfaces de contrôle Fractal – le log. Ce log est traduit
en code C constituant le code du composant de reconfiguration qui, avec les nouveaux composants, est
compilé sous forme binaire pour être envoyé au système cible. Le système cible implémente un support
minimal pour charger ce code de reconfiguration et l’exécuter.
Pour assurer la cohérence des vues architecturales entre le système cible et le système de compilation,
nous faisons l’hypothèse que l’architecture du système cible évolue exclusivement via des reconfigurations explicites, faites par la machine de compilation et uniquement par cell-ci. Ainsi, la machine de
compilation peut maintenir une représentation cohérente de l’architecture cible qui est mis à jour après
chaque reconfiguration (nécéssité d’un protocole de confirmation du succès de la reconfiguration). La
représentation initiale du système est identique à la description ADL initiale du système.
Dans le code de reconfiguration généré (détaillé dans la section 6.3.4, les noms des éléments de
l’architectures sont sous représentés sous leur forme textuelle, i.e. chaı̂ne de caractère. La résolution de
ce nom vers une référence réelle a lieu à l’exécution, en utilisant un composant spécialement dédié à
l’introspection de l’architecture Think. Nous allons décrire ce support dans la section 6.3.5.
Le prototype du compilateur n’effectue pas une analyse sémantique, néanmoins vérifie et garantie
les propriétés suivantes :
74
Chapitre 6. Reconfiguration avec FScript
6.3. Un compilateur FScript
– L’existance des implémentations des différents mécanismes pour la reconfiguration dynamique,
i.e. l’existance des différentes interfaces de contrôle. Cette vérification est faite en vérifiant la
spécification des composants reconfigurables, telle que spécifiée lors de la construction du système
(voir chapitre 5).
– L’équivalence des types des interfaces lors d’une reconfiguration, en particulier lorsque de nouvelles liaisons sont établies (lors d’un remplacement de composant ou simplement lors d’une modification de liaison).
– La résolution des dépendences des nouveaux composants à instancier.
Dans l’état du prototype, le compilateur actuel optimise le code généré pour une utilisation dans un
contexte de réseau de capteurs. Ainsi le compilateur privilégie la compacticité du code par rapport aux
garanties susceptibles d’avoir un impact sur le code.
En perspectives, le compilateur pourrait générer une implémentation de l’interface Callback et
pourrait générer automatiquement le code responsable de la suspension du programme de reconfiguration
(avec des sémaphores) pour attendre que les composants à reconfigurer soient dans un état stable. Le
compilateur pourrait également réorganiser le code de reconfiguration afin de minimiser le temps de
suspension de service etc. Une alternative consisterait à proposer une construction au niveau du langage
FScript qui rendrait explicite l’attente du programme de reconfiguration sur les état stables.
6.3.3
Mise-en-oeuvre avec Think ADL
Le compilateur FScript que nous avons conçu reprend l’architecture du compilateur Think ADL
et l’organise à sa guise pour pouvoir compiler un programme de reconfiguration. Nous avons réutilisé
sans changement la chaı̂ne de chargement d’un AST pour pouvoir à la fois de charger la description
architecturale du système à reconfigurer, mais également la description architecturale des éventuels nouveaux composants. Nous avons également réutilisé, sans changements, la chaı̂ne terminale du compilateur Think ADL, à savoir le module de chargement avec la génération de code. En réalité, nous avons
insérer l’interprète FScript qui dirige le flot d’exécution (contrairement au compilateur ADL, où le flot
est linéaire, cf. figure 5.2 au chapitre 5).
La figure 6.7 montre le flot d’exécution du compilateur FScript. Les étapes suivantes sont exécutées :
– L’ADL du système à reconfigurer est chargé par le module de chargement du compilateur. L’AST
ainsi obtenue est également annoté avec les propriétés de reconfigurations, telles que spécifiées
dans le fichier FlexProp, puis transformé. On obtient ainsi un AST du système reconfigurable à
l’exécution.
– Cet AST permet d’instancier un système à composants en Java, équivalent à l’architecture du
système à l’exécution. Ces composants Java implémentent uniquement les différentes interfaces
de contrôle et serviront à obtenir le log de reconfiguration.
– A ce stage, l’interprète FScript peut être exécuté sur le système Fractal en Java, avec en entrée le
programme de reconfiguration. Un log de reconfiguration est obtenu lors de cette phase.
– Ce log est passé au module génère le code de reconfiguration, encapsulé dans un composant
(représentation AST), appelé driver. Ce module charge également les AST des composants à instancier par le programme de reconfiguration. Finalement, ce module construit (AST) un composant, appelé composant de reconfiguration, qui contient à la fois le driver et les nouveaux composants.
– L’AST ainsi obtenu est passé à la chaı̂ne de génération de code standard, i. e. au module de traitement d’AST.
– A la sortie de ce traitement, on obtient une image binaire du composant de reconfiguration.
– Le module de compilation de reconfiguration génère également la nouvelle représentation du
système sous forme d’une description ADL.
75
6.3. Un compilateur FScript
.fractalA
.fractalA
FlexProp
DL
DL
.fractalA
.fractalA
IDL
DL
DL
.fractal
Implém
.fractal
.c,
cpp,
ADL
ADL
.java
...
Analyseurs
syntaxiques
ADL
extension
Reconfiguration
AST
DSL
L
ID
.fractal
ADL
.fractal
ADL
ADL
Chapitre 6. Reconfiguration avec FScript
Transformations
d'architecture
AST
Analyseurs
sémantiques
AST
LOG
list of new
components
if ack on
reconfig
new
ADL
Java Fractal
Components
Factory
reconfiguration
AST - new components
FScript
Interpreter
FScript
AST
kernel
Module de chargement
Reconfiguration
Component
Compiler
ADL
Module de
traitement
d'AST
AST
Graphe
de
tâches
Génération
de code
Ex
e
cu
Vérification
n
Execution
t
cu
e
Ex
Tâche
1
Ordonnanceur
tio
Moteur
d'exécution
Liste de
tâches
Résolution de
dépendences
ion
Graphe de tâches
Tâche
2
Tâche
3
Tâche
4
Déploiement
F IG . 6.7 – Compilateur FScript - flot de données et d’exécution.
6.3.4
Le composant de reconfiguration généré
Le compilateur génère un code de reconfiguration encapsulé dans une structure à composant. Nous
détaillons d’abord le code de reconfiguration généré à partir d’un programme FScript, ensuite son encapsulation en composants et finalement le format binaire du composant de reconfiguration.
Le code C généré
Le code de reconfiguration en C est généré à partir du log de simulation de la reconfiguration par le
compilateur. Ce code a les charactéristiques suivantes :
– Code séquentiel, sans instructions de contrôle – le log de simulation est une suite d’opérations
sur les interfaces de contrôle de l’architecture, en particulier les instructions conditionnelles sont
évaluées (if/then ou boucles while etc.). Par conséquent le code C à générer ne contient pas
d’instructions de contrôle et le générateur génère uniquement les différentes variables C et les
appels aux interfaces de contrôle Fractal du système à l’exécution.
– Références textuelles et résolution – Les références du programme FScript sont préservées sous
leur forme textuelle et leur résolution est faite à l’exécution en appelant un composant d’introspection fourni par le support d’exécution de FScript embarqué sur la plate-forme. Ce composant
est accédé par l’interface client introspection du composant de reconfiguration.
76
Chapitre 6. Reconfiguration avec FScript
6.3. Un compilateur FScript
– Déploiement de nouveaux composants – Si lors de la reconfiguration de nouveaux composants
doivent être déployés, leur code est également générée par le compilateur et peut être accédée par
le code de reconfiguration via l’interface container.
– Gestion d’erreurs – Un code de gestion d’erreur minimal est également généré. Ce code vérifie
uniquement l’initialisation des différentes variables.
En exemple, voici un extrait de code généré pour l’exemple de programme FScript de la section
précédente (repris dans les commentaires du code C) :
typedef Rfractal_api_ComponentIdentity CI_t;
void reconfiguration__run (void* _this)
{
...
/* 1 k = $root/child::kernel; */
CI_t *kernelCI = CALL(REQUIRED.introspection, get, "kernel");
/* 2 n := new(’new_alloc’); */
CI_t *comp_0 = fscript_new(_this, "counter_reconfig");
/* 4 add($k, $n); */
fscript_add(_this, kernelCI, comp_0);
...
}
Cet exemple illustre l’utilisation de l’interface introspection pour retrouver les références
réelles à partir des références textuelles. Les fonctions utilitaires fscript_new() et fscript_add()
sont génériques et sont implémentés dans le support embarqué sur la plate-forme cible. Les deux fonctions encapsulent les appels vers les interfaces de contrôle Fractal et seront détaillées dans la section
suivante.
L’architecture interne du composant généré
Le compilateur FScript génère un composant, dit de reconfiguration, qui contient à la fois le code C
de reconfiguration et éventuellement les nouveaux composants à déployer lors de la reconfiguration. Ces
nouvelles instances sont déduites à partir de la fonction fscript_new(). Le code C de reconfiguration
est encapsulé dans un sous-composant appelé driver. La figure 6.8 montre cette architecture.
Le composant driver fourni l’interface reconfiguration qui sera appelée sur la plate-forme
cible pour exécuter le programme de reconfiguration. Ce composant requière deux interfaces – une
interface introspection et une interface container. La première est utilisée pour traduire les
références textuelles du programme FScript vers des références réelles. La deuxième sert à retrouver les
nouvelles instances.
Format binaire du composant de reconfiguration - ELF
Le composant de reconfiguration compilé est en format binaire ELF (ELF, n.d.), relogeable (relocatable). Dans le format ELF relogeable, un objet binaire est embarqué avec des informations permettant
de le charger à n’importe quelle adresse. De plus, le fichier contient également une liste de symbols nonrésolus qui doivent l’être lors de l’édition de liens sur la plate-forme cible – dans ce cas concret, ce sont
uniquement les fonctions utilitaires (fscript_add(), fscript_new(), etc.)
77
Reconfiguration Component
driver
container
(FScript code in C)
new
new
new
components
components
components
implements
reconfiguration
interface
introspection interfaface (required)
Chapitre 6. Reconfiguration avec FScript
reconfiguration interface
6.4. Conclusion
F IG . 6.8 – Le composant de reconfiguration généré par le compilateur FScript.
6.3.5
Support du système à l’exécution
Pour pouvoir charger et exécuter un composant binaire tel que décrit dans la section précédente,
il est nécéssaire que la plate-forme cible fournisse un support minimal à l’exécution. Ce support est
propre à l’implémentation du compilateur FScript, en particulier il est indépendant des mécanismes de
reconfiguration tel que décrits dans le chapitre 4.
Concrétement, la plate-forme cible doit fournir les composants suivants :
– Chargeur et éditeur de liens La plate-forme cible doit implémenter un chargeur et éditeur de
lien dynamiques pour le format ELF, capable charger le composant de reconfiguration binaire et
d’éditer les liens (symbols).
– Fonctions utilitaires Pour minimiser le code de reconfiguration transmis à la plate-forme, quelques
fonctions utilitaires doivent être embarquées dans le système reconfigurable. Il s’agit de fonctions
génériques qui encapsulent les actions des programmes FScript. Ainsi par exemple l’action add()
d’un programme FScript aura une fonction utilitaire associée, appelée fscript add().
– Composant d’introspection Afin de résoudre les références textuelles d’un programme FScript
vers les références réelles, la plate-forme cible doit fournir un composant permettant de retrouver
à l’aide des interfaces d’introspection Fractal le composant réel.
6.4
Conclusion
Le support pour un langage de programmation de reconfigurations, tel que FScript, est la dernière
pièce de notre proposition pour un modèle de construction de systèmes reconfigurables.
Le prototype du compilateur est bien évidemment sujet aux améliorations, néanmoins comme tout
compilateur, il permet une analyse de l’architecture à reconfigurer et du programme de reconfiguration et
permet de valider le programme de reconfiguration, ainsi que d’envisager des optimisations de ce dernier
(réorganisation du code utilisateur) etc.
Cette solution nécessite une synchronisation de la représentation de l’architecture vue par l’hôte de
compilation avec l’architecture actuelle s’exécutant sur la plate-forme cible. Par ailleurs le chargement
d’objets relogeables au format ELF implique un surcoût d’utilisation mémoire qui est prohibitoire dans
certains cas, comme dans les noeuds de réseaux de capteurs. Néanmoins, au chapitre suivant (Evaluation)
nous montrons une solution où sous certaines hypothèses la relocation des composants peut avoir lieu
sur la plate-forme de compilation, optimisant ainsi l’utilisation mémoire du système cible.
78
Troisième partie
Evaluation
79
Chapitre 7
Evaluations
Ce chapitre est dévoué à l’évaluation de notre approche, quantitative et qualitative. Pour cela, nous
avons réalisé trois prototypes de systèmes reconfigurables à travers lesquels nous allons montrer les
différents éléments de l’évaluation.
7.1
7.1.1
Méthode d’évaluation
Sujet d’évaluation
Nous nous intéressons à évaluer notre modèle de construction de systèmes reconfigurables et leurs
reconfigurations dans le contexte d’utilisation des systèmes embarqués. Nous avons découpé l’évaluation
de notre proposition en trois parties, chacune correspondante à une partie du modèle, avec des critères
d’évaluation différents.
7.1.1.1
Interface de reconfiguration et les implémentations des mécanismes de reconfiguration
L’interface de reconfiguration que fournit Think/Fractal est l’élément clé de notre proposition. Deux
aspects en sont déterminants dans le contexte des systèmes embarqués :
– Flexibilité de l’interface de reconfiguration. La conception de l’interface de reconfiguration détermine sa flexibilité ou la possibilité d’implémenter différents mécanismes, à des grains d’architecture différents, dans des systèmes aux contraintes d’utilisation différentes (comme les réseaux de
capteurs ayant des ressources matérielles limitées).
– Performances de l’implémentation. L’implémentation d’une interface de reconfiguration a un impact sur les performances du systèmes - utilisation de la mémoire, temps de calcul... Or les performances d’un système embarqué, ou le respect des différentes contraintes du système, sont un
élément déterminant dans ce contexte.
7.1.1.2
Compilation des systèmes reconfigurables
Si la conception et l’implémentation d’une interface de reconfiguration est l’élément central de notre
approche, le compilateur des systèmes reconfigurables englobe toute l’intelligence et la complexité de la
mise-en-place d’une telle interface dans un système réel.
Le compilateur étant un prototype logiciel, qu’il est toujours possible d’améliorer, nous avons cherché
à évaluer les aspects liés à sa conception et à l’approche que nous proposons (en particulier la qualité
”logicielle” n’a que peu d’intérêt) :
81
7.1. Méthode d’évaluation
Chapitre 7. Evaluations
– Expressivité et simplicité. Les entrées du compilateur constituant une interface avec l’utilisatuer,
la spécification des parties reconfigurables, son pouvoir d’expression et la simplicité constituent
des éléments clés de l’adoption de notre approche.
– Automatisation des transformations architecturales. Le compilateur construit un système reconfigurable à partir des spécifications utilisateur en transformant son architecture. Cette transformation
nécéssite divers paramètres spécifiés par l’utilisateur (sous forme des paramètres des propriétés,
comme expliqué au chapitre 5). Le compilateur réalise un compromis entre la simplicité de la
spécification et la capacité à automatiser la transformation de l’architecture.
– Analyse et validation. Dans la forme actuelle du modèle que nous proposons, quel est le degré
d’analyse et de validation que le compilateur peut faire lors de la construction d’un système reconfigurable ? Par exemple si deux spécifications de composants reconfigurables sont compatibles au
sein du même système.
Cette évaluation du compilateur de systèmes reconfigurables est à mettre en lien avec les optimisations architecturales séléctives, décrites en annexe D, qui sont réalisées grâce à un support avancé du
compilateur.
7.1.1.3
Programmation et compilation des reconfigurations FScript
L’utilisation de FScript pour la programmation des reconfigurations est optionnelle, néanmoins son
utilisation simplifie l’écriture des reconfigurations et leur validation. Le compilateur FScript étant un
prototype logiciel, qu’il est toujours possible d’améliorer, nous avons cherché à évaluer les aspects liés
à sa conception et à l’approche que nous proposons (en particulier la qualité ”logicielle” n’a que peu
d’intérêt) :
– Langage FScript - simplicité, expressivité Le langage FScript constitue une entrée utilisateur et
pour son adoption, il est essentiel que le langage permette d’écrire de manière simple des programmes de reconfiguration équivalents au langage C.
– Analyse et validation Quel est le type et le degré des vérifications que le compilateur peut entreprendre, avec les éléments du modèle de programmation que nous proposons ? Par exemple,
dans notre proposition il est toujours nécéssaire de vérifier si le composant à reconfigurer a effectivement été construit comme un composant reconfigurable, càd si le composant à reconfigure
implémente les mécanismes de reconfiguration.
– Adaptation aux différents contextes opérationnels. Contrairement au compilateur de systèmes reconfigurables (qui prépare une image exécutable), le compilateur FScript intéragit avec le système
à l’exécution et pour cela requière un support minimal de ce dernier. Comme énoncé, nous avons
l’ambition de construire des systèmes reconfigurables pour des plate-formes variées, allant jusqu’aux réseaux de capteurs disposant de peu de ressources matérielles. Il est alors nécéssaire
d’évaluer si l’utilisation de FScript s’adapte correctement à des contextes variés.
7.1.2
Critères d’évaluation
La nature de l’évaluation diffère selon l’aspect à évaluer, néanmoins, nous avons divisé l’évaluation
en deux parties :
– évaluation qualitative, comprend l’appréciation des différents aspects liés à la compilation d’un
système reconfigurable et à la programmation des reconfigurations avec FScript.
– évaluation quantitative, comprend l’évaluation des différents surcoûts lié à l’implémentation d’un
système reconfigurable. En particulier, nous avons séparé la mesure de performances en deux
parties :
82
Chapitre 7. Evaluations
7.2. Evaluation qualitative
– micro-benchmarks – mesure de performances localisée, portant sur l’évaluation de performances
des intercepteurs pour la reconfiguration dynamique.
– benchmarks applicatifs – évaluation de performances et comparaison d’un système reconfigurable à un système équivalent non-reconfigurable.
7.1.3
Prototypes d’évaluation
Pour évaluer les différents éléments cités précédement, nous avons construit plusieurs prototypes de
systèmes, permetant de montrer les différents aspects de l’évaluation.
Construction d’un système sécurisé reconfigurable Nous avons contruit un prototype d’un système
à composants reconfigurables et sécurisés (contrôle d’accès). Ce prototype illustre l’aspect utilisateur de
notre proposition (évaluation qualitative) et l’articulation entre les phases de construction d’un système
reconfigurable et sa reconfiguration.
Décodeur H.264 reconfigurable Dans le but de procéder à une analyse des perfomances d’un système
reconfigurable, nous avons construit un décodeur vidéo H.264 reconfigurable. En particulier, ce système
nous a permis de confronter et analyser deux implémentations de détection d’un état quiescent de composants – comptage de références et les intercepteurs dynamiques.
Systèmes reconfigurables pour noeuds de capteurs Notre approche a pour ambition de cibler également les plate-formes limitées en ressources matérielles, comme les noeuds de réseaux de capteurs.
Comme preuve de concept, nous avons construit un système reconfigurable minimal pour un noeud
de capteur. Ce prototype nous a également permis d’évaluer l’impact sur les performances du système
de deux implémentations du support FScript, présentants différents compromis entre l’efficacité et la
flexibilité.
7.2
Evaluation qualitative
Dans cette partie nous montrons à travers le prototype d’un système sécurisé reconfigurable une
évaluation qualitative de notre contribution. Concrétement nous décrivons l’articulation entre les éléments
qui permettent la construction du système et sa reconfiguration.
7.2.1
Description du système
Dans les systèmes mobiles, au-delà de la 3G, l’architecture de sécurité1 doit pouvoir prendre en
compte les conditions d’opération très dynamiques. Il s’agit en particulier de terminaux nomades, pouvant évoluer dans des réseaux d’accès hétérogènes (GSM, WLAN, ...), ayant des requis différents sur
la sécurité. Dans ce contexte, les capacités de reconfiguration dynamique permettent de construire un
système où les différents aspects de sécurité sont flexibles et peuvent évoluer au cours de l’exécution, de
façon non-anticipée à la conception du système.
Dans le cadre d’une initiative plus large (Saxena et al., 2007) visant à construire des terminaux reconfigurables de bout-en-bout (projet E2R (E2R, n.d.)), nous avons co-dévelopé un prototype du framework
de contrôle d’accès reconfigurable appelé CRACKER (Jarboui et al., 2006b) (Component-Based Reconfigurable Access Control for Kernels). Ce prototype a été construit en utilisant le compilateur Think ADL
étendu, tel que décrit dans le chapitre 5. En particulier un plugin de transformation architecturale pour
1
security en anglais – sûreté et sécurité
83
7.2. Evaluation qualitative
Chapitre 7. Evaluations
la sécurité (autorisation d’accès) a été rajouté. Dans cette partie de l’évaluation, nous nous intéressons à
l’aspect utilisateur de notre modèle – sa simplicité et son efficacité.
7.2.1.1
L’architecture CRACKER pour le contrôle d’accès
CRACKER est une architecture de contrôle d’accès basée sur une architecture à composants, indépendante de la politique d’autorisation utilisée. Dans CRACKER, toute ressource, ou objet, est sous la
forme de composant. L’accès à un objet par un sujet – entité active du système, typiquement un thread
– est soumise à autorisation par un contrôleur spécifique de l’objet. Cette autorisation est fonction d’un
contexte et des identifiant de l’objet et du sujet en question.
La mise-en-place de l’architecture CRACKER pour un objet (composant) est montrée sur la figure
7.1. Elle consiste de deux éléments – un reference monitor (RM) et un policy manager (PM).
ChangeAuthorizationPolicy
Policy Manager (PM)
Reference Monitor (RM)
Check
Check
Decision (DC)
I
I
J
Admin
Resource
to protect
Administration
(AC)
J
Compute
Compute
Permissions
(CPC)
F IG . 7.1 – Architecture CRACKER pour le contrôle d’accès aux composants.
Reference Monitor Un moniteur de référence est attaché à tout composant qui nécéssite un contrôle
d’accès. Dans Think, ce moniteur est implémenté dans la membrane du composant de façon incountournable grâce à des mécanismes matériels basé sur une utilisation de la MMU (?). Le RM intercepte les
appels entrant et apelle le policy manager du système pour autoriser ou refuser l’accès au composant
contrôlé.
Policy Manager Un gestionnaire de politique d’accès est une implémentation de la matrice de contrôle
d’accès (sujets/objets). Concrétement il s’agit d’un composant Think qui fourni une interface utilisée par
des RM lors de l’autorisation d’un accès et des interfaces permettant l’administration du système. Le PM
a trois sous-composants ayant des rôles distincts :
– Administration Component (AC) Ce composant maintient un contexte de sécurité et la matrice de
contrôle d’accès - associant des droits à la combinaison sujet/objet. Une interface d’administration
est également implémentée permettant de modifier ou réinitialiser cette matrice.
– Decision Component (DC) Le composant de décision forme les requêtes d’autorisation destinées
au composant d’administration, en retrouvant l’identifiant de l’objet accédé et du sujet (à l’aide du
composant scheduler du système).
– Compute Permissions Component (CPC) Ce composant défini la politique d’autorisation d’accès.
Il implémente une fonction qui permet de calculer la matrice d’autorisation maintenue par le composant d’administration. (Saxena et al., 2007) détaille la manière de spécifier la fonction d’autorisation dans Prolog. A l’encontre des composants d’administration et de décision, ce composant
dépend de la politique d’accès, changer la politique d’accès revient alors à reconfigurer ce composant et réinitialiser le composant d’administration.
84
Chapitre 7. Evaluations
7.2.1.2
7.2. Evaluation qualitative
Reconfiguration des politiques d’accès de CRACKER
Reconfigurer la politique de contrôle d’accès revient à remplacer le composant CPC du gestionnaire de politique CP et réinitialiser la matrice maintenue par le composant administration. Suite aux
précédents travaux, deux composants CPC sont disponibles, implémentant deux politiques de contrôle
d’accès - Domain and Type Enforcement (DTE) (Badger et al., 1995) et Multi-Level Security (MLS).
Le protoype que nous avons construit, simule un terminal mobile qui change de contexte de sécurité,
nécéssitant une mise-à-jour de la politique de contrôle d’accès. Cette politique, non-anticipée lors de la
conception du système, est téléchargée avant la reconfiguration.
7.2.1.3
Architecture du système
L’architecture du système, telle qu’elle est vue par l’utilisateur, comprend quatre éléments :
– le système fonctionnel, ici un ensemble de threads accédant à un écran pour afficher des informations,
– l’implémentation d’un protocol de communucation (TPC/IP sur ethernet, ymodem sur une ligne
série, ...),
– un (ou plusieurs) gestionnaire(s) de politiques de contrôle d’accès, par défaut implémentant la
politique DTE,
– le support pour FScript (chargeur dynamique, introspection et sémaphores).
Pour plus de clarté, le système est construit en trois étapes. Le premier système, screenOS, contient
uniquement la partie fonctionnelle du système.
composite screenOS {
provides activity.api.Main as main
contains main = main
contains
contains
contains
contains
contains
contains
contains
binds
binds
binds
binds
binds
binds
binds
binds
thread1 = activity.lib.job
thread2 = activity.lib.job
scheduler : activity.lib.scheduler
allocator : memory.lib.allocator
screen : video.lib.screenType
drawer = video.lib.tdrawer
link : net.lib.comm_link //CHECK
main.drawer to drawer.drawer
main.console to screen.console
main.framebuffer to screen.framebuffer
main.thread1 to thread1.job
main.thread2 to thread2.job
main.allocator to allocator.allocator
main.scheduler to scheduler.scheduler
main.link to link.link
binds drawer.framebuffer to screen.framebuffer
binds drawer.character to screen.character
binds
binds
binds
binds
thread1.scheduler
thread2.scheduler
thread1.allocator
thread2.allocator
to
to
to
to
scheduler.scheduler
scheduler.scheduler
allocator.allocator
allocator.allocator
85
7.2. Evaluation qualitative
Chapitre 7. Evaluations
binds thread1.runner to main.runner
binds thread2.runner to main.runner
binds this.main to main.main
}
Le composant screenOS est étendu avec le support d’un gestionnaire de politiques de contrôle
d’accès. Le nouveau composant s’appelle alors screenAcOS :
composite screenAcOS extends screenOS {
contains irqsafe : irq.lib.irqsafeType
contains policy = security.lib.dtepolicy
binds policy.scheduler to scheduler.scheduler
binds policy.allocator to allocator.allocator
binds policy.irqsafe to irqsafe.irqsafe
}
Finallement, le système est étendu en y ajoutant un support pour FScript :
composite screenReconfAcOS extends screenAcOS {
contains loader
= loader.lib.loader
contains registry = loader.lib.registry
contains lowloader : loader.lib.lowloader
contains introspection = introspection
binds
binds
binds
binds
binds
introspection.allocator to allocator.allocator
loader.registry to registry.registry
loader.lowloader to lowloader.lowloader
loader.allocator to allocator.allocator
loader.cache to cache.cache
binds main.introspection to introspection.introspection
binds main.loader to loader.loader
binds main.registry to registry.registry
}
7.2.2
Compilation du système
Ce système a été compilé avec le compilateur Think ADL étendu, en particulier nous avons utilisées deux extensions de transformation d’architecture. La première pour ajouter le contrôle d’accès au
composant écran avec l’infrastructure de gestion de politiques de sécurité, la deuxième pour ajouter une
interface de reconfiguration au système, plus précisément au composant PM.
7.2.2.1
Spécification des propriétés
Contrôle d’accès Pour spécifier le contrôle d’accès, l’utilisateur utilise le langage FlexProp introduit
au chapitre 5. La spécification suivante définit l’architecture CRACKER pour le système décrit dans le
paragraphe précédent.
kernel/drawer_sec : security(type=accesscontrol,
RM=RM, PM=kernel/policy)
86
Chapitre 7. Evaluations
7.2. Evaluation qualitative
kernel/thread1 : security(type=accesscontrol,
RM=RMthread, PM=kernel/policy)
kernel/thread2 : security(type=accesscontrol,
RM=RMthread, PM=kernel/policy)
Cette spécification définit le composant drawer_sec comme un composant dont l’accès est soumis
à un contrôle par le gestionnaire de politique, implémenté dans le composant kernel/policy inclus
dans l’architecture conçue par l’utilisateur2 . L’argument RM spécifie le type de moniteur de référence standard pour les objets ou RMthread pour les sujets. Le moniteur pour les sujets, ici thread1 et
thread2, enregistre les derniers auprès du policy manager lors du démarrage du système.
Interface de reconfiguration La spécification suivante définit une interface de reconfiguration pour
pouvoir remplacer à l’exécution le composant cpc. Une implémentation de type comptage de référence
est spécifiée (avec les différents paramètres spécifiant les sémaphores à utiliser).
kernel/policy/cpc : reconfigurable(type=thread-counting,
semaphore-reconfig=sem_reconfig.semaphore,
mutex-reconfig=sem_mutex.semaphore,
semaphore-factory=sf.factory)
Remarques En observant la spécification des différentes parties du systèmes, nous pouvons avancer
deux critiques :
– La spécification est relativement verbeuse, le mini-langage ne dispose pas de blocs syntaxiques
(délimité par { et }) qui permetterait par exemple d’exprimer que les trois entités sont toutes
liées au même gestionnaire – kernel/policy. Par conséquent il est nécéssaire de répéter cette
information individuellement dans chaque spécification.
– La combinaison des différentes transformations architecturales n’a pas posé de problème dans cet
exemple, car l’interface de reconfiguration est appliquée à un composant existant dans l’architecture conçue par l’utilisateur. Néanmoins, l’utilisateur ne peut pas appliquer une transformation à un
composant résultat d’une transformation précédente, car celui-ci n’existe pas dans le système lors
du traitement de spécifications FlexProp. Concrétement, si la transformation de contrôle d’accès
ajoutait également un gestionnaire de politique d’accès par défaut, il serait impossible de spécifier
une interface de reconfiguration pour ce dernier.
7.2.2.2
Transformations architecturales
Lors de la compilation de ce système, deux plugins sont chargés par le compilateur pour effectuer
deux transformations architecturales successives (les mêmes que sur les figures 4.4 et 7.1) Le premier
est le plugin de contrôle d’accès et le second le plugin pour la reconfiguration dynamique. L’ordre des
plugins n’est pas important dans ce cas, néanmoins il est spécifié dans la configuration de compilation
du système3 .
7.2.3
Programmation et compilation d’une reconfiguration
Pour remplacer la politique de contrôle d’accès du système conçu, nous utilisons un programme
FScript qui vérifie quelle politique est actuellement utilisée et suivant le cas, reconfigure le gestionnaire
de politiques :
2
3
Il peut bien y avoir plusieurs gestionnaires différents dans un systèmes
fichier build.properties
87
7.3. Micro-benchmarks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Chapitre 7. Evaluations
k = $root/child::kernel/::child/policy;
l = get-name($k/child::seccompute)
if ($l != "mls") {
n := new(’cpc_mls’);
o := $k/child::cpc;
add($k, $n);
suspend($k, $o);
stop($o);
rebind($k, seccompute, $n/interface::seccompute);
bind($o/interface::allocator, $k/interface::alloc)
bind($o/interface::secadmin,
$k/child::admin/interface::secadmin)
start($n);
resume($k);
remove($k, $o);
}
Le code généré pour ce programme, à partir de la simulation de reconfiguration sur le système conçu,
comporte deux blocs de code linéaire, en particulier la vérification de la ligne 4 a été supprimée4 (cette
expérimentation a été effectué avec une sémantique bloquante de la méthode suspend()) :
– une déclaration et initialisation des variables pour les lignes 1, 2, 5 et 6,
– un appel aux fonctions utilitaires (fscript_add(), fscript_suspend(), ..) pour les lignes
8-17.
Finallement, le compilateur FScript génère un composant de reconfiguration, qui contient le composant driver et le nouveau composant mls (contenu dans le composant container), comme le
montre la figure 6.8 au chapitre 6. Ce composant de reconfiguration est envoyé sous sa forme binaire
(ELF) au système s’exécutant sur le terminal qui va exécuter la reconfiguration.
7.3
Micro-benchmarks
Les micro-benchmarks ont pour but d’évaluer le coût des différents intercepteurs pour la reconfiguration dynamique qui servent à implémenter la détection d’un état stable. L’implémentation de ces
interepteurs diffère suivant le modèle d’exécution. Par conséquent, pour pouvoir comparer les intercepteurs du modèle à threads, nous avons réalisé un prototype d’un modèle d’exécution événementielle
(prototype à sémantique pauvre) comme une alternative au modèle multi-thread pour la reconfiguration
dynamique.
Nous évaluons d’abord les intercepteurs pour le modèle d’exécution à threads (intercepteurs dynamiques et intercepteurs de comptage de références, décrits au chapitre 4). Dans un deuxième temps nous
décrivons le modèle d’exécution événementiel et son impact sur les performances d’un système.
7.3.1
Intercepteurs dans un modèle à threads
Le tableau 7.3.1 compare les différents surcoûts liés à l’utilisation du canevas Think et à l’utilisation
des différents intercepteurs de reconfiguration. Le surcoût lié à un appel de composant est comparé à un
4
Le compilateur n’effectue pas une analyse sémantique, voir chapitre 6, et par conséquent générera toujours un code de
reconfiguration pour ce programme, même si la condition à la ligne 4 est évaluée négative (i.e. la politique de contrôle d’accès
est déjà mls). Dans ce cas, le compilateur génère un code de reconfiguration, comportant uniquement du code C pour les deux
premières lignes.
88
Chapitre 7. Evaluations
7.3. Micro-benchmarks
appel de fonction en C. Ces mesures ont été obtenues sur un processeur ARM XScale (Intel PXA255 sur
iPAQ h2200), à une fréquence de 400MHz et un bus mémoire de 100MHz.
type d’appel
appel de fonction C
appel de méthode T HINK
appel de méthode T HINK avec
intercepteurs de comptage de références
appel de méthode T HINK avec
intercepteurs dynamiques
temps (µs)
0, 03
0, 06
0, 6 (0, 27)
0, 4 (0, 27)
TAB . 7.1 – Les performances des différentes implémentations d’intercepteurs.
Un appel de composant Think implique plusieurs déréférencement de pointeurs (cf. figure 3.5 au
chapitre 3). Chaque implémentation d’une méthode a au moins un argument (le pointeur this), donc
au total quatre déréferencements sont nécéssaires.
Les intercepteurs de comptage de références utilisent un composant sémaphore pour accéder le compteur d’accès en exclusion mutuelle. Au total, six appels de composants sont effectués lors d’un appel
intercepté (deux appels au composant sémaphore qui à son tour appelle le composant qui bloque les
interruptions du système). Le retour d’un appel est implémenté de la même manière, d’où le facteur 10
par rapport à un appel classique de composant Think. Nous avons optimisé l’implémentation des intercepteurs, en implémentant l’exclusion mutuelle directement en bloquant les interruptions – les mesures
entre parenthèse. Néanmoins cette implémentation dépend de l’architecture matérielle ciblée.
L’algorithme qu’implémentent les intercepteurs dynamiques est plus complexe et nécéssite de tracer
l’identité des différents appelants (avec les composants Kortex ceci nécéssite un appel au composant
scheduler). Contrairement au comptage de références, les intercepteurs dynamiques ne font aucun
traitement pour le retour d’appel du composant.
Le tableau 7.2 indique la taille mémoire occupée par les différents intercepteurs :
– Un intercepteur (que ce soit comptage de référence ou dynamique) est un composant Think qui
implémente une interface fonctionnelle et deux interfaces de contrôle (LifeCycleController
et InterceptorStateController). Les méta-données associées à un intercepteur représentent cette information. Les méta-données contiennent également les noms des différentes interfaces, étant la différence de taille des noms des interfaces fonctionnelles.
– Pour chaque méthode de l’interface interceptée le même traitement est effectué. Pour minimiser la
taille de la méthode d’interception, nous avons factorisé ce traitement en plusieurs fonctions et la
méthode se résume alors à l’appel d’une ou plusieurs fonctions.
– L’implémentation des interfaces de contrôle des intercepteurs, ainsi que le code de traitement sont
partagés par tous les intercepteurs du système.
composant intercepteur
chaı̂nes de caractères
stub de méthode
comptage de références
implémentation
intercepteurs dynamiques
implémentation
taille code
144 + 5
100b
1280b
taille données
200b
-
4200b
160b
TAB . 7.2 – L’occupation mémoire des différentes implémentation des intercepteurs.
89
7.3. Micro-benchmarks
Chapitre 7. Evaluations
Par exemple pour l’interface video.api.Console qui a six méthodes, le composant d’interception occupe 100.6 + 144 = 744b de code et 200b de données. Pour un système reconfigurable, avec
l’algorithme de comptage de références, ayant i interfaces interceptées et m méthodes interceptées, la
mémoire occupée par l’implémentation de l’algorithme de comptage de référence serait la suivante :
200.i + 144.i + + 100.m + 1280
7.3.2
(7.1)
Un modèle d’exécution événementielle
Dans un modèle à threads, la détection d’un état quiescent du composant engendre un coût et une
infrastructure non-négligeable. Nous avons conçu un modèle événementiel dans lequel, par construction
les composants sont dans un état stable entre chaque traitement d’événement. Ainsi, il n’y a pas de coût
associé à détecter cet état.
Cependant, un modèle événementiel présente deux inconvéniants. D’abord, en terme de modèle de
programmation, car ce modèle est moins intuitif et plus difficile à comprendre dans son ensemble que
le modèle classique. Ensuite, en terme de performances, dans la mesure, où toute intéraction entre les
composants du système est implémentée comme un événement et donc implique un surcoût par rapport
à un simple appel de composant.
Le modèle que nous présentons ici est simple et son objectif est uniquement une analyse de performances pour la reconfiguration dynamique.
7.3.2.1
Modèle de base
Le modèle événementiel mis en place est simple :
– Tout appel d’une méthode d’interface est un événement. Par extension (ou abus de langage), on
désigne également par événement l’interface ou son implémentantion, donc le composant.
– Chaque événement s’exécute jusqu’à sa terminaison.
– Les événements sont gérés par un ordonnanceur d’événements, simple dans notre modèle – une
FIFO.
– Le modèle d’architecture est un modèle plat – il n’y a pas de composition hiérarchique, tous les
composants événementiels sont sous-composants du même composant parent. L’architecture peut
néanmoins contenir des composants composite, mais leur exécution ne sera pas événementielle.
– Les interruptions matérielles sont transformées en événements logiciels, associés à une interface.
7.3.2.2
Construction d’un système événementiel
L’implémentation du modèle présenté est simple, toute liaison entre composant est interceptée par
un intercepteur relié à un ordonnanceur. C’est l’ordonnanceur qui expédie les événements, en appelant
le composant (plus précisément la méthode de l’interface). A chaque appel d’une méthode cliente, l’intercepteur met l’événement correspondant dans la file de l’ordonnanceur et l’exécution se poursuit dans
le composant appelant. Lorsque le composant a terminé son traitement, l’exécution retourne à l’ordonnanceur qui élit l’événement suivant.
Un système événementiel est construit en utilisant les mêmes mécanismes de compilation qui ont
été utilisés pour contruire des systèmes reconfigurables ou sécurisés – spécifications et transformations
d’architecture. L’utilisateur construit une architecture à composants Think et spécifie une transformation
”événementielle”. L’architecture du système doit néanmoins respecter les contraintes imposées par le
modèle – modèle d’architecture plat.
90
Chapitre 7. Evaluations
7.3.2.3
7.3. Micro-benchmarks
Implémentation de la reconfiguration
Une reconfiguration dynamique est implémentée comme un événement. Lorsque celui-ci s’exécute,
tous les autres composants sont dans un état stable.
Par conséquent, l’implémentation de l’interface de reconfiguration dynamique pour un modèle d’exécution événementiel va diverger uniquement dans l’implémentation de l’état stable, donc l’implémentation de l’interface ReconfigurationController – l’implémentation de l’introspection, des modifications architecturales et les autres aspects du contrôle d’état reste inchangés. Par conséquent, les
méthodes de l’interface ReconfigurationController sont simplement vides, car non-nécéssaires, mais présentes dans le programme FScript, qui lui n’a aucune information sur le modèle d’exécution
sous-jacent6 .
7.3.2.4
Evaluation de performances
Evénement Le tableau 7.3 montre la comparaison des temps d’exécution des différents types d’appel
sur la plate-forme Cognichip – fonction C, appel synchrone de méthode d’un composant (appel classique de composant) ou appel asynchrone (intéraction par événement, cet appel est intercepté et géré par
l’ordonnanceur).
Le coût d’un appel asynchrone comprend à la fois le temps d’appel de l’intercepteur, qui à son tour
appelle l’ordonnanceur pour insérer l’événement dans une file, également le temps que met l’ordonnanceur à exécuter l’événement. Par ailleurs, nous retrouvons le facteur 2 d’un appel de composant classique
par rapport à un appel d’une fonction C.
type d’appel
appel fonction C
appel méthode T HINK
événement
temps (µs)
7, 7(12, 6)
16, 8
215, 5
TAB . 7.3 – Les performances d’un appel événementiel.
Evenementiel vs. Multi-thread Le tableau 7.4 compare le coût d’un évnémenent au coût du contextswitch dans un modèle multi-thread. Lors d’un context-switch, il est nécéssaire de sauvegarder et restaurer un ensemble de registres (32x8bits sur AVR), le coût de l’événement comprend l’appel du composant
intercepteur, l’appel du composant scheduler et également la gestion de la file (naı̈ve dans cette
implémentation).
changement de contexte de threads
événement (queue, dispatch)
temps (µs)
262, 7
215, 5
TAB . 7.4 – Performances comparatives entre un modèle événementiel et un modèle multi-thread.
Un modèle d’exécution événementiel présente un avantage en termes de performances pour implémenter un état stable dans un système reconfigurable, néanmoins cette évaluation ne donne aucun renseignement sur la comparaison des deux modèles pour une application ou un système concrèt.
6
Ces instructions pourraient être supprimées par le compilateur FScript, comme une optimisation.
91
7.4. Evaluation de performances de systèmes reconfigurables
7.4
Chapitre 7. Evaluations
Evaluation de performances de systèmes reconfigurables
L’évaluation de performances applicatives s’appuie sur deux prototypes d’application. Tout d’abord
nous étudions les performances d’un système reconfigurable en utilisant le prototype du décodeur H.264.
Ensuite, nous évaluatons le support d’exécution de programmes FScript sur le prototype d’un système
pour noeuds de capteurs.
7.4.1
Décodeur vidéo H.264 reconfigurable
Dans un système reconfigurable ayant un modèle d’exécution multi-thread, l’implémentation du
contrôle actif – détection d’un état quiescent – a un impact considérable sur les performances du systèmes.
Afin d’évaluer cet impact, nous avons contruit un décodeur vidéo H.264 reconfigurable. Au cours des
travaux précédents, le décodeur H.264 de référence (JN/TML, n.d.) a été rearchitecturé sous forme de
composants Think (Layaida et al., 2005). Ce système est conçu comme un système d’exploitation applicatif (application et système dans le même espace d’adressage) et permet de modifier le modèle de
concurrence et son degré.
Nous avons mis à l’épreuve notre conception de l’interface de reconfiguration et son implémentation
en rendant reconfigurables les services systèmes, en particulier le composant d’affichage (framebuffer et
screen) – le composant le plus critique en terme de performances de ce système. Nous avons construit et
comparé deux versions de ce système, une première avec des threads ”classiques”, donc utilisable avec
l’algorithme de comptage de référence ; et une deuxième avec des threads ”à la K42”, où les intercepteurs dynamiques peuvent être utilisés pour détecter un état quiescent, mais également l’algorithme de
comptage de référence.
7.4.1.1
Caractéristiques du système
La figure 7.2 montre l’architecture du système de base qui a servi à construire le décodeur complet.
Cette figure montre l’architecture utilisateur, en particulier les intercepteurs liés à l’implémentation de
l’interface de reconfiguration sont omis.
FileSystem
Allocator
Scheduler
FrameBuffer
Console
E2FS
Idle Thread
e2fs
Console
PriorityScheduler
PriorityBased
Scheduler
FrameBuffer
Driver
DiskDriver
Trap
Manager
Timer
Handler
Screen
FlatAllocator
Flat Memory
Manager
dlmalloc
SpecificOSKernel_H264
F IG . 7.2 – Système applicatif du décodeur H.264.
L’architecture du décodeur, construite au-dessus du système décrit précédemment, est composée de
quatre composants complexes qui ont un traitement indépendant :
– Input Reader (IR) - Composant responsable de lire le flux à décoder (réseaux, disque etc.) et le
présenter au composant coeur du décodage.
92
Chapitre 7. Evaluations
7.4. Evaluation de performances de systèmes reconfigurables
– Core Decoder (CD) - Le composant coeur du décodage vidéo H.264.
– Video Displayer (VD) - Ce composant encapsule la logique d’affichage du flux décodé sur un
support donnée, dans notre cas l’écran.
– Subtitle Displayer (SD) - Gestion des sous-titres, décodage et affichage. Accès concurrent au service/composant d’affichage du système.
L’exécution de chacun des quatre composants est indépendante, chaque composant est associé à un
fil d’exécution – thread – et les composants s’échangent des messages et des données dans des tampons
prévus à cet effet. Le flot de données, et par conséquent l’algorithme de décodage, est le suivant : i)
lecture par IR, ii) décodage par CD et iii) en parallèle affichage par VD et SD.
Dans cette architecture le modèle de concurrence est implémenté par le composant scheduler
et les composants threads qui sont associés aux quatre composants de traitement. Les figures 7.3 et
7.4 montrent les architectures concrètes du décodeur H.264 avec les deux modèles de concurrence. En
particulier, la deuxième architecture utilise des threads dynamiques et par conséquent contient des usines
de composants threads.
Subtitled Video Decoder
Thread 1
Input Reader
Thread 2
Core Decoder
Subtitle
Reader
Thread 3
Video
Displayer
Subtitle
Displayer
Thread 4
Console
Frame Buffer
Memory Allocator
File System
Scheduler
SpecificOSKernel_H264
F IG . 7.3 – Architecture du système H.264 utilisant un modèle de concurrence classique.
7.4.1.2
Benchmarks applicatifs
Le benchmark applicatif a pour but de déterminer l’impact des mécanismes pour la reconfiguration
dynamique sur une application réelle. Pour cela, nous avons réalisé un décodage de 200 frames vidéo
avec le décodeur H.264 décrit précédemment.
Le tableau 7.5 présente les temps de décodage pour les deux modèles de concurrence. Dans chaque
cas nous avons comparé le temps de décodage d’une architecture non-reconfigurable à une architecture
reconfigurable, avec aucune ou une seule reconfiguration (le frame-buffer).
Performances initiales La comparaison des performances initiales – système non-reconfigurable et
système reconfigurable (sans reconfiguration), dépend du choix du mécanisme de détection de l’état
quiescent et par conséquent du choix de modèle de concurrence.
Comme prévu, l’utilisation des intercepteurs dynamiques pour détecter un état stable n’altère pas les
performances du système reconfigurable (sans reconfiguration) par rapport à un système non-reconfigurable.
93
7.4. Evaluation de performances de systèmes reconfigurables
Chapitre 7. Evaluations
Subtitled Video Decoder
Execution
Controller
Thread 0
Thread
Factory
Thread
n+1
Input Reader
Thread
n+2
Core Decoder
Subtitle
Reader
Thread
n+3
Video
Displayer
Subtitle
Displayer
Thread
n+4
Console
Frame Buffer
Memory Allocator
File System
Scheduler
SpecificOSKernel_H264
F IG . 7.4 – Architecture du système H.264 utilisant un modèle de concurrence avec des threads de durée
déterminée et non-bloquants.
L’utilisation du mécanisme de comptage de référence implique un surcoût lié à l’utilisation massive
des intercepteurs. Ce surcoût est fonction de la combinaison suivante :
i) la complexité de l’implémentation des intercepteurs, étroitement liée à la complexité de l’algorithme de détection d’un état quiescent,
ii) le pattern d’accès au composant reconfigurable et sa complexité, donc le pattern d’exécution de
l’intercepteur, ceci étant une donnée de l’application.
Dans notre système, le composant frame-buffer est accédé de façon massive et donc le système paie le
surcoût de l’intercepteur à chaque appel.
Impact d’une reconfiguration sur les performances Une reconfiguration impacte les performances
de deux façons. La première est le surcoût lié à la détection d’un état quiescent. La seconde est le
surcoût lié à la reconfiguration elle-même sous forme de code non-fonctionnel qui s’exécute une fois
l’état quiescent atteint. Le surcoût total varie en fonction de la complexité de la reconfiguration et de la
complexité des mécanismes de détection d’état quiescent.
L’impact sur les performances de la détection d’un état stable est déterminé par i) la complexité de
l’intercepteur utilisé et ii) le pattern d’accès au composant reconfigurable, donc la fréquence d’exécution
de l’intercepteur. Ce dernier varie selon l’application.
Durée de détection d’un état quiescent Pendant le détection d’un état quiescent, les performances
du systèmes sont dégradées, car dans le cas des deux mécanismes, les appels aux composants reconfigurables sont temporairement bloqués. La durée de détection d’un état stable est alors un paramètre à
minimiser, néanmoins elle dépend fortement de l’application. La durée varie également selon le nombre
de composants en état quiescent :
– Avec les intercepteurs dynamiques la durée de détection dépend de la durée de vie d’une génération
de threads, donc du pattern de création/destruction de threads et de la complexité des composants
que le thread exécute.
94
Chapitre 7. Evaluations
7.4. Evaluation de performances de systèmes reconfigurables
modèle à threads classique
système non reconfigurable
système reconfigurable
avec comptage de références
short-lived
non-blocking threads
système non reconfigurable
système reconfigurable
avec intercepteurs dynamiques
système reconfigurable
avec comptage de références
pas de
reconfiguration
4, 74s
une
reconfiguration
-
4, 95s (4, 4%)
4.99s (5, 2%)
pas de
reconfiguration
7, 14s
une
reconfiguration
-
7, 14s
7, 42 (3, 9%)
7, 24s (1, 4%)
7.32s (2, 5%)
TAB . 7.5 – Durée de décodage de 200 frame vidéo pour les différents systèmes reconfigurables (utilisant
différentes implémentations de la détection d’un état quiescent).
La détection d’un état quiescent de plusieurs composants a lieu en principe en même temps, à la
fin de la même génération de threads.
– Avec le comptage de référence, la durée de détection dépend de la complexité du composant reconfigurable (et eventuellement des composants qu’il appelle).
Contrairement aux intercepteurs dynamiques, la détection d’un état quiescent de plusieurs composants est complétement indépendente.
Comptage de référence vs. Intercepteurs dynamiques Au vu des résultats il n’existe pas de mécanisme de détection d’état stable optimal. Certes, les intercepteurs dynamiques ne présentent pas de
surcoût pendant l’exécution, néanmoins, le modèle d’exécution n’est pas universel et nous avons du
modifié l’algorithme de décodage pour paramétrer la création et destruction de threads et cette version
modifiée présente un surcoût initiale plus important que la simple version utilisant des threads ”classiques”.
Le choix d’un mécanisme de détection d’état stable va dépendre de l’application, du modèle de
concurrence souhaité, des performances initiales souhaitées, de la flexibilité du mécanisme (typiquement, par défaut tout composant est reconfigurable avec les intercepteurs dynamiques, alors qu’avec le
comptage de référence, il faut anticiper lors de la conception du système et spécifier les composants
comme reconfigurables), la durée de reconfiguration etc.
Surcoût mémoire
vidéo H.264.
Le tableau 7.6 compare l’occupation mémoire des différentes versions du décodeur
type de système reconfigurable
système non reconfigurable
système reconfigurable
avec comptage de références
système reconfigurable
avec intercepteurs dynamiques
occupation mémoire
907.3kB
913.2kB
990.3kB
TAB . 7.6 – Occupation mémoire des systèmes reconfigurables.
Le surcoût des intercepteurs dynamiques est lié à notre implémentation des usines d’intercepteurs –
pour chaque type d’interface du système, le compilateur ADL génère un composant usine. Nous n’utili-
95
7.4. Evaluation de performances de systèmes reconfigurables
Chapitre 7. Evaluations
sons pas d’intercepteurs génériques. Pour le comptage de référence, les intercepteurs occupent moins de
mémoire et l’implémentation partagée est également plus compacte.
7.4.2
Reconfiguration dynamique des noeuds de capteurs
Les sytèmes pour des noeuds de réseaux de capteurs présentent des défis liés à leur construction et
efficacité (de par leur limitation de resources, les systèmes sont construits ”à la carte”) et à leur mise-àjour (du fait du nombre de noeuds déployés et leur potentielle inacessibilité physique).
Dans le chapitre 6, nous avons décrit le support nécessaire pour charger et exécuter un programme
FScript compilé. Ce support est générique et flexible – la résolution des adresses des interfaces est faite
à l’exécution par introspection et le format binaire du composant permet de le charger dynamiquement à
n’importe quelle adresse mémoire. Ainsi, à part l’ADL du système, le compilateur FScript ne nécéssite
aucune information supplémentaire pour compiler un programme de reconfiguration. Alors que ce fonctionnement peut convenir à des plate-formes avec suffisamment de resources, pour une utilisation dans
les réseaux de capteurs, il est nécéssaire d’optimiser l’utilisation de la mémoire et de la bande passante.
En effet, la transmission radio étant la resource critique qui consomme le plus d’énergie. De ce point de
vue, notre approche de la reconfiguration est à l’opposé d’une approche comme la machine virtuelle Maté
(Levis & Culler, 2002) où tout programme est constitué de byte-code compact et efficace à transmettre.
Dans un premier temps, nous présentons une version générique et flexible du support pour FScript,
ensuite nous présenterons les optimisations apportées pour une utilisation efficace dans les réseaux de
capteurs. Le compilateur FScript, génère un code de reconfiguration en accord avec le support présent (ou
en accord avec la spécification utilisateur). Le compilateur de systèmes reconfigurables, pourrait inclure
de façon automatique un support FScript approprié au système construit.
7.4.2.1
Description du système
Nous avons construit un prototype de noeud de capteur pour la radio cognivite opportuniste (Mitola,
2000), destiné à un usage domotique. Cette plate-forme est appelée Cognichip.
Le Cognichip est basé sur une architecture AVR, architecture Harvard avec les bus mémoire séparés
pour le code et les donées, concrètement le micro-processeur ATmega2561 (Atmel, n.d.), un RISC 8-bit à
16MHz, avec 8kb de RAM (données) et 256kb de mémoire flash (code). La plate-forme est équipée d’un
circuit éméteur/recepteur radio (le cc1000, (Chipcon, n.d.)) opérant sur les fréquence radio allouées
aux chaı̂nes télévisées.
Le Cognichip peut accueillir des capteurs et des actionneurs domotiques (capteurs de température,
détecteurs de fumée, ...). Les Cognichips sont reliés à une station de base (lien radio), servant de passerelle. Cette dernière est connectée à une infrastructure réseaux, permettant de gérer le réseau de capteurs
déployé.
Au vu des resources matérielles de la plate-forme, la reconfiguration logicielle est une capacité
intéréssante, voire nécéssaire. Pour effectuer des mis-à-jour du système, sans le redémarrer (et perdre
son état qui est associé au traitement de l’information), pour installer de nouveaux drivers permettant de
piloter de nouveaux actionneurs ou capteurs etc.
Avec le canevas Think, nous avons construit un prototype d’un système reconfigurable sur le Cognichip. Pour des raisons de capacité matérielle et d’efficacité à l’exécution, le modèle d’exécution
classique, multi-thread, est prohibitif pour construire un tel système. En effet, la détection d’un état
quiescent du composant implique un surcoût non négligeable sur une plate-forme comme le Cognichip.
Par conséquent, nous avons construit un système événementiel, avec une sémantique particulière d’état
stable, permettant de reconfigurer le système à moindre coût. De plus, les optimisations architecturales
décrites dans l’annexe D sont spécialement conçues pour s’appliquer à ce système.
96
Chapitre 7. Evaluations
7.4.2.2
7.4. Evaluation de performances de systèmes reconfigurables
Support flexible pour FScript
A partir d’un ADL et d’un programme de reconfiguration, le compilateur FScript génère un code de
reconfiguration (ainsi que les composants associés). La flexibilité de l’approche est dûe à l’utilisation de
l’introspection dans le code généré, les références textuelles étant suffisantes, et à l’utilisation du format
ELF qui permet de charger le composant à n’importe quelle adresse en mémoire.
Le tableau 7.4.2.2 compare les tailles des différentes parties du fichier ELF du composant de reconfiguration généré :
– L’en-tête ELF contient la table de symboles (donc chaı̂nes des caractères) et deux tables de relocation (pour les sections .text et .data).
– La quantité de symboles dans la table de symboles est proportionnelle au nombre de composants.
Pour chaque composant, le compilateur Think génère un nombre de variables globales (donc symboles), en particulier, l’implémentation du composant est transformée et les variables globales
”utilisateurs” sont encapsulées dans une seule structure globale.
– La taille des tables de relocation est liée également à la nature du code C généré. Le compilateur
génère des variables globales ”cross-référencées”, chaque référence nécéssitant une entrée dans la
table de relocation. La complexité de l’implémentation du composant, en terme de découpage en
fonctions, joue également un rôle - chaque appel d’une fonction nécéssite une entrée dans la table
de relocation.
Taille programme FScript
Code de reconfiguration
Nouveau composant (mls)
Méta-données (structures T HINK)
Total contenu
En-tête ELF
dont chaı̂nes de caractères
Total fichier ELF
400b
1.5kb
4.7kb
0.2kb
6.4kb
2kb
∼ 1kb
8.4kb
TAB . 7.7 – Composant de reconfiguration – occupation mémoire.
La table 7.8 montre la taille des différents éléments du support d’exécution des composants de reconfiguration. Nous avons séparé la taille du code (section .text) de la taille des données (section .data).
Dans les architectures AVR, utilisées dans des réseaux de capteurs par exemple, le code est écrit dans la
mémoire flash (de l’ordre de 128kB à 256kB) et les données dans la RAM (de l’ordre de 4kB à 16kB).
Les données commprennent les variables globales, en particulier, cette information ne donne aucun renseignement sur l’utilisation de la pile ou du tas par une implémentation donnée. L’éditeur de liens a des
fonctionnalités minimales pour charger le composant de reconfiguration.
Le support de FScript que nous avons conçu est indépendant de la méthode de communication entre
l’hôte de compilation et le terminal, nous faisons l’hypothèse que le système à reconfigurer est un système
”connecté”, communiquant à l’aide d’une pile protocolaire quelconque qui accepte des requêtes de reconfiguration.
7.4.2.3
Support optimisé pour FScript
L’utilisation de la mémoire et et de la bande passante de la solution précédente est liée au format de
fichier ELF – le chargement d’un tel fichier nécéssite son écriture et sa modification en mémoire, le code
de reconfiguration étant relogeable, son en-tête ELF contient les informations de relocations, augmentant
par conséquent la quantité de données à télécharger.
97
7.5. Conclusion
Chapitre 7. Evaluations
Introspection
Chargeur et éditeur de liens
FScript fonctions utilitaires
Total support à l’exécution
taille code
2.7kb
4.9kb
1.3kb
8.9kb
taille données
100b
300b
0b
400b
total
2.8kb
5.2kb
1.3kb
9.3kb
TAB . 7.8 – Support FScript, occupation mémoire.
Afin d’optimiser l’efficacité d’utilisation de la mémoire et de la bande passante, nous avons implémenté un support pour FScript utilisant un format de fichier binaire où l’édition de liens est faite sur la
plate-forme de compilation FScript. L’avantage est de réduire considérablement la quantité de données
transmises et l’utilisation d’un chargeur dynamique n’est plus nécéssaire - le code est écrit directement dans la mémoire flash, les données en mémoire. Les addresses mémoires (donc l’image binaire
du système à l’exécution) doivent être connues lors de la compilation de programmes FScript. Il est
nécéssaire de les sauvegarder en tant que méta-données architecturales lors de la compilation du système.
Le tableau 7.4.2.3 détaille les tailles des différentes parties du composant de reconfiguration transmises lors d’une reconfiguration. La partie code des composants à télécharger peut être directement
écrite dans la flash (sans relocation nécéssaire) donc sans nécéssité d’allocation temporaire d’autant de
mémoire RAM pour la relocation.
taille code
1112
334
1446
Code de reconfiguration
Nouveau composant (xyz)
Total transféré
taille données
135
57
192
TAB . 7.9 – Composant de reconfiguration, occupation mémoire.
7.5
Conclusion
A travers les trois prototypes de systèmes reconfigurables, nous avons évalué les trois points clefs
de notre approche i) l’interface utilisateur, ii) l’efficacité de son implémentation, et iii) l’efficacité du
support pour le langage FScript compilé.
7.5.1
Evaluation qualitative
L’évaluation qualitative doit montrer que notre approche satisfait aux objectifs de flexibilité, expressivité et simplicité (l’objectif d’efficacité étant traité dans la section suivante). Les raisons suivantes
permettent d’affirmer cela :
– La variété des implémentations de mécanismes de reconfiguration pouvant être abritées par l’interface de reconfiguration conçue, démontrant la simplicité et la flexibilité.
– La variété des impléméntations de l’interface de reconfiguration pouvant être générés par le compilateur de manière uniforme, par transformations architecturales, s’adaptant à différents modèles
d’exécution. Simplicité.
– La généralisation des transformations architecturales, appliquées à la construction des systèmes
sécurisés et des systèmes événementiels, permet de confirmer le généricité de cette approche,
proposant à l’utilisateur un mécanisme polyvalent et simple pour ajouter des extensions à son
système. Flexibilité.
98
Chapitre 7. Evaluations
7.5. Conclusion
– L’implémentation des mécanismes de reconfiguration sur des plate-formes hétérogènes, en particulier sur des plate-formes contraintes en ressources matérielles comme les noeuds de réseaux de
capteurs, montrant la flexibilité.
– L’implémentation du support FScript sur des plate-formes hétérogènes, s’adaptant aux différents
contextes opérationnels, en particulier sur des plate-formes contraintes en ressources matérielles
comme les noeuds de réseaux de capteurs, montrant la flexibilité. Ici, l’évaluation montre le potentiel des méta-données architecturalles pour la reconfiguration dynamique.
7.5.2
Evaluation quantitative
L’évaluation quantitative de notre approche met en évidence le surcoût de notre approche pour la
reconfiguration dynamique, d’une part de l’implémentation d’une interface de reconfiguration, d’autre
part de l’implémentation d’un support pour les programmes FScript compilés.
– L’implémentation de la détection d’un état quiescent est coûteuse. Elle peut être optimisée suivant le modèle d’exécution utilisé par le système (événementiel, threads ”à la K42”), néanmoins,
comme le montre la comparaison sur le décodeur H.264, il n’existe pas de mécanisme optimal – à
chaque système un mécanisme adapté.
– Il n’existe pas de modèle de concurrence optimal, le modèle événementiel implémente de façon efficace la détection d’un état stable, néanmoins engeandre un surcoût dû au traitement d’événements.
– Les mécanismes de détection d’état quiescent n’offrent pas le même degré de flexibilité (avec
comptage de référence, le composant doit être conçu pour être reconfigurable avec ce mécanisme)
– Notre approche permet d’implémenter un support FScript qui réduit au maximum la quantité de
données transmises et nécéssite pas de mémoire supplémentaire pour exécuter le code de reconfiguration (pas de chargeur). Pour réduire la quantité de données transmises au-delà de nos résultats,
il faudrait utiliser une approche de machine virtuelle, comme Maté (Levis & Culler, 2002).
99
7.5. Conclusion
Chapitre 7. Evaluations
100
Chapitre 8
Conclusion et perspectives
8.1
Bilan
Dans cette thèse nous avons décrit un modèle de construction de systèmes embarqués qui offre une
flexibilité pour construire à la carte des systèmes embarqués reconfigurables et autorise la programmation
de leurs reconfigurations. Le modèle de construction que nous avons proposé est fondé sur la notion de
l’architecture du système et comprend les éléments suivants :
– Une interface de programmation des reconfigurations de bas-niveau permettant l’implémentation à
grain fin des différents mécanismes de reconfiguration dynamique – chaque composant implémente
les mécanismes appropriés. Les reconfigurations sont programmées en termes de cette interface de
programmation. L’interface telle que nous l’avons définie est indépendante de la partie fonctionnelle d’un composant et du modèle d’exécution du système et par conséquent offre une flexibilité
de construction de systèmes reconfigurables.
Dans ce même esprit, l’interface pour la reconfiguration offre que des méthodes d’accès de basniveau à l’état d’un composant, permettant la construction de mécanismes de transfert d’état complexes.
– Un environment de construction de systèmes reconfigurables, supporté par des outils aidant le
concepteur du système à créer et valider une architecture reconfigurable, i.e. avec une implémentation concrète d’une interface de reconfiguration. Le concepteur du système spécifie les parties
reconfigurables du système de façon orthogonale à l’architecture elle-même du système.
– Un environment de programmation de reconfigurations, basé sur l’utilisation d’un langage dédié à
la reconfiguration, ciblant jusqu’à des architectures matérielles contraintes en ressources matérielles.
Pour valider notre approche, nous avons réalisé plusieurs prototypes de systèmes reconfigurables qui
ont eu pour but de démontrer la flexibilité de l’approche ainsi que l’efficacité de son implémentation. En
particulier nous avons réalisé un prototype d’un système applicatif reconfigurable pour noeuds de réseau
de capteurs, fortement contraints en ressources matérielles. Son évaluation quantitative montre l’impact
du choix du modèle d’exécution sur les performances d’un système reconfigurable.
8.2
Limitations
La conception du modèle proposé présente plusieurs limitations.
Généricité de l’interface de reconfiguration Tout d’abord, nous avons implémenté plusieurs mécanismes de reconfiguration (concrétement la détection d’un état stable) avec plusieurs modèles d’exécution.
101
8.2. Limitations
Chapitre 8. Conclusion et perspectives
Néanmoins, nous ne disposons d’aucune preuve que l’interface telle que nous l’avons conçue est suffisamment générique pour satisfaire toutes les utilisations possibles.
Inter-blocages Le programmeur de reconfiguration peut ammener le système dans un état d’interblocage dans le cas précis où dans un modèle à thread l’état quiescent de plusieurs composants doit
être détécté à l’aide du mécanisme de comptage de références. En effet notre implémentation se base sur
l’utilisation de sémaphores et losrqu’un état quiescent pour un composant est détecté, les threads entrants
sont mis en attente sur un sémaphore. L’inter-blocage intervient lorsque le programmeur de reconfiguration demande la détection d’un état quiescent de deux composants – client et serveur et lorsque l’état
stable du serveur est détecté en premier lieu. Dans ce cas, les threads venant du client sont mis en attente
à l’entrée du composant serveur et le composant client n’atteindre jamais un état quiescent (car les appels
au serveur ne progressent pas).
Cette limitation est dûe à la volonté de concevoir une interface où les différents éléments sont
indépendants et aucune implémentation n’a une vue globale de l’état des reconfigurations. Une solution consiste à réordonnancer le programme de reconfiguration pendant la phase de compilation en faisant une analyse architecturale de façon à exclure toute possibilité de deadlock et insérer des points de
synchronisation dans le programme de reconfiguration.
Limites des transformations transparentes à l’utilisateur L’approche qui consiste à transformer
l’architecture du système de façon transparente à l’utilisateur présente deux inconvéniants. D’abord,
l’implémentation de la membrane d’un composant Think peut dépendre des composants fonctionnels qui
doivent se trouver dans l’architecture utilisateur (dépendance cachée). Nous avons résolu ce problème en
introduisant les paramètres dans les propriétés attachées à des noeuds reconfigurables lors de la compilation. Ces propriétés permettent de remplir les dépendances de la membrane vers la partie fonctionnelle.
De plus, lorsque plusieurs transformations de l’architecture utilisateur sont nécessaires, comme le
montre le prototype du système sécurisé reconfigurable (cf. 7), un décallage d’architecture est créé à
chaque transformation, alors que celles-ci sont spécifiées par rapport à l’architecture initiale (la transformation n + 1 ne voit pas le résultat de la transformation n). Une solution consiste à introduire une
représentation intermédiaire entre les transformations (l’ADL en est une) et spécifier les transformations
de façon itérative par rapport à description précédente (et non initiale).
Synchronisation des vues architecturales pour la compilation FScript La compilation FScript quant
à elle, présente une difficulté liée à la synchronisation des vues architecturales - celle du système de compilation avec l’architecture réelle du système cible. Dans le chapitre 6 nous avons étudié plusieurs possibilités de synchronisation, faisant différentes hypothèse sur la dynamique du système et offrant différents
compromis entre la flexibilité et l’efficacité du support pour la reconfiguration.
En ce qui concerne l’efficacité d’un programme de reconfiguration compilé, nous avons rencontré
deux problèmes liés à son utilisation efficace dans les noeuds de réseaux de capteurs :
– Dans les réseaux de capteurs, une des ressources critiques est l’utilisation de l’énergie, la transmission radio étant une des opération des plus coûteuse. De ce point de vue, notre solution transmettant
des composants binaires (i.e. en langage objet cible) est moins efficace en termes d’informations
à transmettre qu’une solution telle que la machine virtuelle Maté où le code à transmettre est sous
forme d’un ensemble restreint d’instructions de la machine virtuelle.
– Pour offrir un maximum de flexibilité à un système reconfigurable, le composant de reconfiguration binaire est sous la forme d’un fichier ELF où le code et les données sont relogeables. Ceci est
au détriment de la taille du fichier à transmettre, car l’en-tête ELF contient une quantité d’informations de relocation.
102
Chapitre 8. Conclusion et perspectives
8.3. Perspectives
A ce problème, nous avons décrit au chapitre 7 une solution partielle qui consiste à faire l’édition
de liens sur la machine de compilation à une adresse fixe, prédéterminée pendant la construction
de la plate-forme cible. Après cette édition de liens, le volume des données à transmettre à la
plate-forme cible est réduit au code et aux données du composant de reconfiguration (éliminant
l’en-tête ELF). Cependant, la flexibilité de cette solution est réduite, car l’éditeur de liens doit
connaı̂tre l’adresse d’édition (par un protocole quelconque entre la plate-forme cible et l’hôte de
compilation).
8.3
Perspectives
Ce travail ouvre de nouvelles perspectives sur la reconfiguration dynamique des systèmes embarqués.
Le compilateur Think ADL
Dans l’annexe D nous décrivons une évolution du compilateur Think ADL pour supporter des optimisations architecturales séléctives. En perspectives, il est nécéssaire d’explorer l’articulation des optimisations et des mécanismes pour la reconfiguration dynamique. En effet, les deux approches sont contradictoires – la reconfiguration dynamique repose sur des liaisons dynamiques et sur l’implémentation du
contrôle, alors que les optimisations les éliminent. Il serait intéréssant de concevoir une solution d’optimisations réversibles en s’inspirant des techniques d’implémentation des spécialisations dans l’évaluation
partielle (Consel et al., 1998; Consel et al., 1996; Volanschi, 1998).
Boucle autonomique
La reconfiguration dynamique constitue un élément de base de la boucle autonomique. Ces systèmes
évoluent en fonction des conditions de leur environment, de leur contexte (Appavoo et al., 2003), (Horn,
2001), (Horn, 2001). Dans ce cas, le système détecte la nécéssité de reconfiguration suivant des critères
et déclenche sa reconfiguration lui-même. Il serait alors intéressant d’investiguer la conception d’une
gestion de contexte efficace dans le cadre des systèmes embarqués restreints en ressources matérielles,
comme le Cognichip.
Transfert d’état
L’interface que nous avons conçue offre un accès bas-niveau à l’état du composant – set() et
get(). Cette interface ne précise volontairement pas la sémantique de l’implémentation attendue. De
cette façon, il est possible de bâtir différents mécanismes ou stratégies pour transférer l’état d’un composant. Cependant, c’est au programmeur du composant reconfigurable de spécifier la sémantique de
l’implémentation de cette interface et de l’implémenter.
Par exemple, un composant peut accepter d’exhiber ses données directement via un pointeur. Lors
d’une reconfiguration le nouveau composant peut accepter un tel pointeur. Cela suppose à la fois que
les formats de données du nouveau composant et de l’ancien soient compatibles, et que le programmeur
ait cette information de compatibilité. Dans un autre cas, par exemple où les formats des données sont
incompatibles, le programmeur de reconfiguration peut écrire une fonction de transformation de données
(ou celle-ci peut être générée par des outils tiers), appelée pendant la phase de transfert d’état.
Modèle d’exécution événementiel
Dans la partie évaluation de notre proposition, nous avons montré un modèle d’exécution événementiel simplifié. L’avantage d’un modèle événementiel par rapport à un modèle multi-thread est controversé,
103
8.3. Perspectives
Chapitre 8. Conclusion et perspectives
néanmoins, ce modèle d’exécution présente des avantages en terme de vérification du comportement des
systèmes (analyse temporelle) ou de la distribution du système entre plusieurs coeurs d’exécution (sur
un chip ou sur plusieurs machines). Pour la reconfiguration dynamique, le modèle événementiel présente
l’avantage de pouvoir implémenter de façon très efficace les différents mécanismes, en particulier l’état
stable d’un composant est donné par construction du système.
La difficulté dans un modèle événementiel est dans la programmation et compréhension du système
(le flot d’exécution ne suit pas le code). Dans notre proposition, la sémantique que nous avons donnée
est suffisamment simple et nous avons pu automatiser la construction du système événementiel uniquement en analysant l’architecture du système (ADL). Cependant, les liaisons architecturales ne sont pas
suffisantes pour spécifier les dépendances des événéments dans un système, comme c’est déjà le cas avec
le langage ThinkJoin (Ozcan, 2007). Le défi consiste à allier la reconfiguration dynamique à une telle
description et en réaliser une implémentation effiface sur le plan des performances.
La suite logique dans la définition d’un modèle d’exécution à sémantique plus riche, serait de pouvoir
extraire un comportement du système afin de le vérifier. Un certain nombre de travaux existent déjà autour
du couplage de Think et de BIP (Basu et al., 2006; Basu et al., 2007) afin de permettre la vérification des
systèmes à sémantique opérationnelle particulière. Ces modèles ne prennent pas en compte une évolution
quelconque du système. Il serait alors intéréssant d’explorer quelles sont les propriétés et garanties qui
peuvent être vérifiées si le système évolue via la reconfiguration dynamique.
Le compilation FScript
Nous avons implémenté un prototype d’un compilateur FScript. Pour des raisons d’efficacité sur
plate-formes contraintes en ressources matérielles, il serait intéréssant de pouvoir optimiser le code de reconfiguration généré. Par exemple, on pourrait envisager d’analyser la séquence des requêtes de détection
d’un état stable et de modifier leur ordre afin de minimiser le temps de suspension de service. Une telle
analyse pourrait également prévenir le cas d’inter-blocage décrit plus haut.
Rollback
Le prototype du compilateur FScript ne génère pas un code de reconfiguration avec une gestion
consistante d’erreurs. Dans le code généré, il faut pouvoir gérer les erreurs liés au programme de reconfiguration. Ces erreurs sont manifestées par les erreurs bas-niveau, i.e. au niveau du langage C (pointeurs
nulls etc.)
Se basant sur une gestion consistante d’erreurs, il serait intéressant dans le cadre des systèmes embarqués restraints en ressources matérielles de pouvoir effectuer un rollback de la reconfiguration en
cours en cas d’erreur.
Persistance des reconfigurations
Les reconfigurations dynamiques telles que nous les avons décrites se basent toujours sur un système
qui a un état initial connu, qui correspond à sa configuration de construction, C0 . Or lorsqu’une ou
plusieurs reconfigurations sont appliquées à ce système et si pour une raison quelconque le système
redémarre, il est souhaitable de redémarrer directement dans la configuration Ci .
Il faut alors s’assurer de la persistance des reconfigurations qui ont menés à la dernière configuration. Egalement, il faut être capable de regénerer l’architecture du sysètme qui correspond à la dernière
configuration.
104
Chapitre 8. Conclusion et perspectives
8.3. Perspectives
Console d’administration
La représentation de l’architecture du système en ADL et les programmes en FScript fournissent une
abstraction pour pouvoir construire une console d’administration de systèmes reconfigurables capable
de gérer un parc de systèmes, potentiellement hétérogènes. Typiquement, un opérateur mobile gère non
loin de milles types de plate-formes différentes (un type est la configuration logicielle sur une plateforme matérielle), mais avec quasiment les mêmes services. Une console d’administration pourrait offrir
une gestion transparente des différentes versions de configuration logicielle, résolvant les problèmes de
versionnement de systèmes et en déployant les composants adaptés à chaque plate-forme.
105
8.3. Perspectives
Chapitre 8. Conclusion et perspectives
106
Annexe A
Caractéristiques variées des systèmes
embarqués
Les caractéristiques de ces systèmes embarqués sont très variées (Lee, 2000; Sztipanovits & Sastry,
n.d.). Pour la plupart, il s’agit de systèmes connectés, spécifiques à un domaine d’application, s’exécutant sur des plate-formes matérielles hétérogènes, ayant différents requis ”temps réel” et d’autres qualités
non-fonctionnelles (sécurité, maintenabilité, ...). La durée de vie de ces systèmes peut être de l’ordre de
quelques (dizaines d’) années et alors il peut s’avérer nécéssaire de mettre à jour soit la partie logicielle
ou/et matérielle du système déployé.
Spécificité à un domaine d’application Contrairement aux ordinateurs personnels qui sont des systèmes de calcul généraux, les systèmes embarqués tel que nous les décrivons sont des systèmes hautement spécialisés à un domaine applicatif. Par exemple, dans un téléphone portable nous trouvons un
système spécialisé dans le traitement du signal audio et vidéo. Les systèmes embarqués dans les avions
ou dans les voitures sont spécialisés dans le contrôle, les noeuds de réseaux de capteurs dans la remontée
d’informations etc.
Hétérogénité des plate-formes et variété des environments Chaque domaine d’application nécéssite
différentes ressources matérielles et par conséquent un système d’exploitation adapté. Par exemple, les
noeuds des réseaux de capteurs peuvent être réalisés avec des architectures AVR à basse consommation,
mais à faible fréquence de calcul. Les téléphones portables, plus gourmands en calcul, peuvent être
constitués d’un coeur ARM maı̂tre et des DSP spécialisés, dédiés au traitement du signal.
De plus, ces systèmes embarqués évoluent dans des environments physiques et logiques très variés
– un noeud de réseaux de capteurs déployé dans la nature pour des expérimentations biologiques n’aura
pas le même environement qu’un routeur télécom (le premier par exemple est physiquement difficilement
accessible, alors que le second évolue dans un système complexe de routage).
Durée de vie Une fois déployé, un systèmes embarqué peut avoir une durée de vie importante, voire
correspondante à la durée de vie du produit dans lequel il est intégré – voiture, équipements multi-média
etc. Une mise-à-jour du logiciel est possible pour une classes de systèmes où tout simplement cette fonctionalité aurait été prévue pendant la conception du système (par exemple le cas de l’électronique grand
public). Cette mis-à-jour peut être effectuée de façon manuelle (par un service spécialisé ou l’utilisateur)
ou de façon automatique, à distance (par exemple téléphones portables ou les routeurs domotiques tel la
LiveBox).
107
Chapitre A. Caractéristiques variées des systèmes embarqués
Cycle de vie complexe Aujourd’hui, le cycle de vie d’un système embarqué est complexe et souvent plusieurs acteurs interviennent dans le processus. En général, la partie matérielle est conçue par
un fabricant, indépendamment du système d’exploitation et indépendamment de la partie applicative.
Souvent le commenditaire d’un système embarqué va jouer le rôle de l’intégrateur pour l’intégrer dans
l’environement cible (ex. industrie télécom et des services proposés par un opérateur). Les spécifications
des différentes parties (matérielles, système d’exploitation etc.) qui servent à la coopération entre les
différents acteurs sont souvent standardisées (par exemple OSEK (OSEK/VDX, n.d.)).
Par exemple, un opérateur mobile achète des téléphones à des fournisseurs qui fournissent donc le
matériel et une partie du logiciel. Ceux-ci achètent souvent le logiciel (au moins le système d’exploitation) à des tiers. Une fois le téléphone déployé (i.e. intégré à l’infrastructure de l’opérateur), l’opérateur
va vouloir déployer ses propres services (ou l’ouvrir à des services tiers) ou événetuellement mettre à
jour la partie logicielle du système.
De plus, une fois le système embarqué déployé, il n’est pas forcément dans la possession du concepteur, ni sous le contrôle de ce dernier. Par exemple un réseau de capteurs géologiques déployé par l’état
peut être dans la possession de l’état et sous son contrôle. Par contre un téléphone portable peut être dans
la possession de l’utilisateur qui en prend contrôle (il a la liberté de l’allumer, l’éteindre et téléphoner à
sa guise, par contre l’opérateur peut toujours détenir un certain contrôle sur le logiciel du téléphone).
Ouverture Dans certains domaines, comme sur les téléphones portables, les systèmes embarqués sont
de plus en plus ouverts, c’est à dire accessibles à des acteurs tiers non-présents lors du dévelopment
ou déploiement du système (par exemple possibilité d’installer des applications Java sur des téléphones
portables). Cette ouverture modifie les exigences sur le système et complexifie la conception du système,
notamment en matière de sûreté et sécurité.
La standardisation des différentes interfaces (matérielles, logicielles, réseau ...) joue un rôle important. Parmi les standards système nous trouvons POSIX (POSIX, n.d.), standard généraliste pour l’interface entre le système et les applications, OSEK (OSEK/VDX, n.d.) également pour l’interface avec le
système (fortement utilisé dans les automobiles), CAN (Bosch, 1991) standard de bus de terrain (ex. automobile), .
Connectivité Pour la plupart, les systèmes embarqués d’aujourd’hui sont des systèmes inter-connectés
que ce soit de manière classique par un réseau filaire (ex. Ethernet, bus de terrain CAN (Bosch, 1991),
etc.), par radio (ex. réseaux de capteurs (Hill et al., 2000)) ou par bus d’interconnexion sur silicium dans
les cas de plusieurs noeuds sur une puce matérielle.
Nous distinguons deux degrés de connectivité. Tout d’abord les systèmes isolés réalisés à partir
de plusieurs noeuds communiquant entre-eux. C’est le cas des systèmes critiques comme les centrales
nucléaires, avions ou voitures. Dans la deuxième catégorie nous plaçons les systèmes connectés à plus
grande échelle, comme les téléphones portables ou des réseaux de capteurs et passerelles domotiques,
tous connectés sur Internet.
Exigences temps-réel et prédictabilité Dans tous les systèmes l’aspect temps est important.
Suivant l’importance accordée, les exigences en termes de prédictabilité et satisfaction des échéances
(deadlines) peuvent déterminer toute la conception du système embarqué. Les besoins en temps réel
peuvent déterminer le paradigme de programmation du système, en adoptant par exemple une approche
synchrone avec les langages Lustre (Halbwachs et al., 1991) ou Esterel (Berry, 2000). Par conséquent, les
exigences temps-réel constituent une contrainte forte pour le choix d’un paradigme de programmation
(car toutes les technologies ne permettent pas de maı̂triser l’aspect temps du système conçu).
108
Chapitre A. Caractéristiques variées des systèmes embarqués
Dans les systèmes où les contraintes liées au temps ne sont pas primordiales (comme par exemple
sur les téléphones portables où un retard dans le décodage n’est probablement même pas perceptible par
l’utilisateur), celles-ci sont satisfaites dans la conception globale du système qui n’est en particulier pas
subordonnée à cette unique contrainte, typiquement en dimensionnant correctement le matériel ou en
implémentant une politique de qualité de service.
Aspects non-fonctionnels Notre définition de systèmes embarqués embrasse une large gamme de
systèmes ayant des nécéssités très variées. Suivant le contexte, une panoplie de qualités non-fonctionnelles doit être considérée lors de la conception du système, ces qualités constituent souvent une valeur
ajoutée importante d’un système. Parmi les différentes qualités non-fonctionnelles, nous ne citons que
quelques exemples :
– efficacité par rapport au matériel utilisé (temps calcul, mémoire ou consommation d’énergie, bande
passante, ...),
– sécurité,
– fiabilité, disponibilité, sûreté (Avizienis et al., ?),
– maintenabilité,
– ”certifiabilité” (ou la qualité d’un système à pouvoir être certifié, plus ou moins facilement),
– documentation,
– adaptabilité et extensibilité,
– qualité de service (QoS) (Tournier, 2005a),
– peristance,
– ...
Compléxité Les systèmes embarqués peuvent varier d’un simple noeud d’un réseau de capteur qui
implémente l’acquisition des données du capteur et un protocole permettant de remonter cette information, jusqu’aux systèmes de contrôle complexes comme dans les voitures ou dans les avions (Sztipanovits
& Sastry, n.d.). De plus, cette complexité a tendance à augmenter avec le temps (Damm, 2006a; Damm,
2006b).
109
Chapitre A. Caractéristiques variées des systèmes embarqués
110
Annexe B
Modèles d’exécution
Deux modèles d’exécution sont répandus dans les systèmes d’exploitation – le modèle à threads et
le modèle evénementiel. Leurs avantages et inconvéniants font partie de guerres religieuses – Lauer et
Needham (Lauer & Needham, 1979) en relèvent la dualité, Ousterhout (Ousterhout, 1996), Dabek et
al. (Dabek et al., 2002) ou Lee (Lee, 2006) identifient le modèle à threads comme source de problèmes
et réservent son utilisation uniquement aux parties à performances critiques. Plus tard Behren et al. argumentent le contraire (von Behren et al., 2003a; von Behren et al., 2003b)...
B.1
Threads
Un thread présente deux aspects à la fois. D’un côté un thread est une abstraction de l’état de
l’exécution du système d’exploitation et des ressources de la machine sous-jacente (registres par exemple).
D’un autre coté, un thread est un outil de programmation et de structuration de code – un fils d’exécution
– et défini un modèle de calcul concurrentiel et constitue une solution simple pour la multi-programmation
d’un processeur (exécution simultanée de plusieurs threads/applications).
Historiquement, le concept de thread est issu d’un besoin de maximiser l’utilisation du processeur,
même lorsque le programme actif est en attente d’une opération d’entrée/sortie. Lors d’une opération
d’entrée/sortie, le thread actif est mis en attente et le système – l’ordonnanceur (scheduler) – continue
l’exécution avec un autre thread – changement de contexte (context-switch). Aujourd’hui le thread est
devenu un outil pour la programmation parallèle.
L’avantage d’un modèle d’exécution à base de threads est la simplicité d’écriture de programmes
et leur compréhension - l’exécution d’un programme donne l’impression d’être séquentielle, il suffit
de suivre les appels de fonctions. L’algorithme d’ordonnancement n’altère pas l’ordre d’exécution à
l’intérieur d’un thread. Néanmoins, le modèle à threads présente plusieurs inconvéniants :
– La mémoire peut être partagée entre plusieurs threads, par conséquent il est nécéssaire de protéger
son accès en synchronisant les threads. La programmation de cette synchronisation est la source
d’erreurs de synchronisation difficilement détéctables et fatales, comme les inter-bloquages (deadlock ou le livelock).
– Pour chaque thread le système doit maintenir le contexte de son exécution, le contexte étant l’état
de la machine (registres) et du système à un moment donné. La conséquence est double : le
système doit allouer de la mémoire pour gérer le contexte (en particulier le système alloue une
pile d’exécution pour chaque thread) et lorsque le système choisit un autre thread pour s’exécuter,
le contexte courant doit être sauvegardé pour restaurer le contexte du thread qui va s’exécuter
(entraı̂nant en particulier des effets sur le cache et la TLB).
– Finalement, l’exécution concurrente de plusieurs threads est non-déterministe.
111
B.2. Modèle d’exécution événementiel
Chapitre B. Modèles d’exécution
Etat stable – Détection d’un état quiescent Dans un système à base de threads, un état quiescent
permet de trivialiser l’état de contrôle lié à une partie du système. L’état quiescent est défini comme un
état qui garanti la quiescence, donc l’absence d’activité. L’état de contrôle (la pile (stack) dans ce cas)
est alors vide (ou non-relevant pour cette partie du système). Dans ce cas, l’état de la partie du système
se résume uniquement à son état interne. Cette partie (code et donnée) peut alors être manipulée avant
de reprendre l’exécution. Un état quiescent est un état stable comme défini auparavant. Dans un modèle
à threads, une partie du système peut être accédée de manière concurrente et son état quiescent doit être
détecté à l’aide d’un algorithme. Au chapitre 4 nous décrivons deux algorithmes de détection d’un état
quiescent.
B.2
Modèle d’exécution événementiel
Les systèmes dits événementiels sont organisés autour de traitement d’événements. Un événement
correspond à une intéraction entre les différentes entités qui composent le système, mais également
à une interruption du processeur convertie en événement (et par conséquent à toute intéraction avec
l’environement physique du système). Un système événementiel défini la sémantique d’exécution d’un
événement, e.g. non-réentrant (peut être interrompu par un autre événement) ou plus fort, non-préemtible
(appelé run to completion dans TinyOS (Hill et al., 2000)). Par exemple, un système événementiel simple
est constitué d’un ensemble de traitants d’événements atomiques1 et un ordonnanceur qui exécute les
événements selon une politique d’ordonnancement prédéfinie (FIFO par exemple).
Comparé au modèle d’exécution multi-thread, l’approche événementielle ne nécéssite pas de sauvegarde de contexte. Les implémentations utilisent souvent des continuations (Adya et al., 2002; Draves
et al., 1991). De plus, sur mono-processeur, la synchronisation de l’accès concurrent à une ressource est
simplifié par la sémantique d’exécution de l’événement – dans le cas des événements atomiques, aucune
synchronisation n’est nécéssaire, tout événement s’exécute en exclusion mutuelle. Comparé aux threads,
l’exécution d’un système événementiel est déterministe et un modèle événementiel permet une analyse
de la prédictabilité et une implémentation pour les systèmes temps réel.
Le modèle événementiel présente plusieurs inconvéniants :
– la non-réentrance ou la non-préemtion (l’atomicité) des événements a une influence sur la réactivité
du système et le programmeur doit en tenir compte dans la conception du système (au lieu d’assigner une priorité plus élevée à un thread),
– par rapport aux threads, le concepteur du système doit avoir une démarche plus structurante pour
éclater le système en évéments de granularité arbitraire,
– le déroulement d’une exécution n’est pas aussi intuitif que dans un système à threads,
– les systèmes événementiels manquent d’outils répandus généralement comme les compilateurs et
les ”debuggers”.
Il existe plusieurs systèmes d’exploitation que nous qualifions d’événementiels, parmi lesquels TinyOS (Hill et al., 2000) (conception événementiel) ou SEDA (Welsh et al., 2001). Le système extensible
SPIN est également un système événementiel.
Etat stable dans un système événementiel Dans un système événementiel sur uni-processeur (événements atomiques, non-préemtifs), par construction un composant est dans un état stable entre chaque
réaction à un événement (donc lorsque l’ordonnanceur s’exécute). Contrairement aux systèmes multithreadés, où la détection d’un état quiescent implique un surcoût (voir à ce sujet les chapitres 4 et 7),
l’obtention d’un état stable dans un système événementiel n’implique pas de surcoût à l’exécution.
1
L’atomicité dans ce cas suppose la non-préemption et donc la non-réentrance
112
Annexe C
Historique du compilateur Think ADL
L’historique du compilateur Think ADL est étroitement lié à l’évolution du modèle sous-jacent au
canevas Think.
Canevas Think à l’origine A l’origine, le canevas Think avait son propre modèle à composants et un
ADL en XML (différent de l’ADL existant, typiquement la notion de liaison explicite était absente). Par
conséquent le premier compilateur avait pour but d’interpréter cette ADL et de générer du code ”glue”
en C adapté aux composants écrits également en C. Le modèle et le compilateur (la chaı̂ne de génération)
sont décrits dans (Fassino, 2001).
Adoption du modèle Fractal Avec l’adoption du modèle à composant Fractal, le canevas Think a été
doté d’un nouveau ADL et par conséquent d’un nouveau compilateur. Cette version est designé comme
la deuxième version du canevas. L’ADL est celui présenté dans ce travail, le compilateur ayant pour but
d’interpréter cet ADL et générer du ”glue” code en C.
Un compilateur à composants La dernière évolution n’a touché que le compilateur Think qui a luimême été construit avec des composants Fractal (en Java), décrit dans (Ozcan, 2007). En réalité il s’agit
d’une convergence du compilateur FractalADL pour les composants écrit en Java et du compilateur Think
précédent, dans la mesure où le compilateur FractalADl existant a été adapté pour produire un code
identique au compilateur précédent. Le modèle de programmation de composants primitifs et l’ADL
sont resté inchangés. Cette version est communément designée comme la troisième version du canevas
ou think-v3.
113
Chapitre C. Historique du compilateur Think ADL
114
Annexe D
Optimisations architecturales sélectives
En tant qu’implémentation du modèle à composants F RACTAL, le framework T HINK actuel1 fixe un
certain nombre de choix d’implémentation des concepts du modèle F RACTAL. En particulier, l’implémentation spécifie un format binaire standard d’un composant qui fixe les structures des méta-données
associées à un composant. Ce format offre une flexibilité pour la réutilisation des composants (Fassino,
2001). Cependant ces choix d’implémentation flexible ne sont pas obligatoirement pertinents pour tous
les systèmes pouvant être construits avec le framework T HINK.
Nous avons identifié les lacunes de l’implémentation actuelle et nous avons réalisé une implémentation flexible (Lobry & Polakovic, 2008), autorisant des optimisations architecturales sélectives :
– Sous optimisations nous comprenons une implémentation alternative des méta-données d’un système à composant F RACTAL, offrant un compromis différent entre la flexibilité et des critères de
performance du système (comme l’occupation de l’espace mémoire ou le surcoût à l’exécution
etc.).
– Ces optimisations concernent l’implémentation de l’architecture du système, donc liaisons, métadonnées, attributs . . .(contrairement à une optimisation du code fonctionnel).
– Les optimisations sont séléctives, spécifiées par l’utilisateur, et s’appliquent localement à un composant ou liaison (contrairement à tout système, même si cette possibilité existe).
D.1
Motivation
D.1.1
Historique
L’origine de la réflexion sur les optimisations est double.
Surcoût lié aux intercepteurs pour la reconfiguration dynamique L’implémentation d’un algorithme de détection d’un état quiescent pour la reconfiguration utilise des composants intercepteur (voir
chapitre 4) qui ont un impact non-négligeable sur les performances du système. Dans une architecture reconfigurable, ce composant intercepteur est étroitement lié au composant dont l’interface est interceptée.
Par conséquent, il est intéressant d’investiguer quel degré de flexibilité est nécessaire et si il est possible
de supprimer tout surcoût lié à ce composant intercepteur (par exemple en court-circuitant ces liaisons,
en supprimant ces interfaces de contrôle, etc.).
L’implémentation efficace des composants sur AVR Pour être réutilisable dans différentes architectures matérielle, le composant uart dans la bibliothèque Kortex – pilote de port série – exporte des attri1
début 2007
115
D.1. Motivation
Chapitre D. Optimisations architecturales sélectives
buts qui permettent de le configurer pour une architecture donnée. Ces attributs sont par exemple les mappings mémoire des registres de contrôle du port série. Les attributs dans T HINK sont implémentés dans
les méta-données dont l’implémentation est fixée et pour accéder la valeur de cet attribut le code du composant doit passer par une indirection. Or sur l’architecture AVR, l’exécution d’une telle implémentation
prend trop de temps et la communication sur le port série déborde (overflow). Cependant, pour une architecture donnée, la valeur de ces attributs est constante, donc l’attribut pourrait être implémenté comme
une variable constante ou une macro.
D.1.2
Objectif
L’objectif du travail consiste à pouvoir construire des architectures à composants avec différents
compromis entre la flexibilité et l’efficacité (suivant des critères de performances établis). Ce compromis
peut varier d’un système flexible (l’existant) à l’élimintation de tout surcoût lié à l’implémentation du
modèle à composant, dans quel cas, le composant serait une entité de conception, mais disparaı̂trait à
l’exécution.
L’intérêt de pouvoir varier le compromis entre flexibilité et l’efficacité d’implémentation est de pouvoir construire des systèmes embarqués à composants sur des plate-formes matérielles contraintes en
ressources (comme les systèmes sur architecture AVR, par exemple le Cognichip (Jarboui et al., 2006a)).
Les types d’optimisations du framework actuel que nous avons identifiés sont au nombre de cinq :
– Attributs constants
– Liaisons statiques
– Implémentation optionnelle du contrôle
– Implémentations alternatives des méta-données
– ”Inlining” des composants
D.1.2.1
Attributs constants
Un attribut d’un composant qui ne change pas au cours de l’exécution du système est dit constant.
L’implémentation actuelle génère systématiquement des méta-données (i.e. une variable) pour chaque
attribut. Cet attribut pourrait bien être implémenté comme une constante (i.e. variable const ou comme
une macro de préprocesseur).
D.1.2.2
Liaisons statiques
Dans la version actuelle de T HINK, une liaison est implémentée avec un pointeur dans les métadonnées du composant client qui référence le descripteur de l’interface serveur. Ce descripteur est un
couple de deux pointeurs qui référencent les données privées du composant serveur et une table virtuelle
de méthode (cf. figure 3.5 au chapitre 3)
Cette implémentation offre la flexbilité à l’exécution – il est possible de modifier la liaison et lié une
interface cliente vers une autre interface serveur d’un autre composant. Dans le cas où cette flexibilité
n’est pas nécessaire (composants fortement couplés ou architecture qui ne va pas évoluer), la liaison, dite
alors statique, peut être supprimée dans le système à l’exécution et pour l’appel d’une méthode serveur
pourrait s’effectuer directement en appelant la fonction C de l’implémentation.
Le code suivant (cf. chapitre 3, section 3.3.2) :
ItfI->meth->f(ItfI->data, arg1, arg2, ...);
deviendrait alors :
f(data, arg1, arg2, ...);
116
Chapitre D. Optimisations architecturales sélectives
D.2. Les problèmes
ou idéalment, l’utilisateur l’écrirait de la façon suivante (l’argument data, qui permet de retrouver
les données d’instance du composant, est invisible à l’utilisateur) :
ItfI_f(arg1, arg2, ...);
D.1.2.3
Implémentation optionnelle du contrôle
Le compilateur actuel génère pour tout composant un ensemble d’interfaces de contrôle par défaut.
Les interfaces de contrôle permettent d’introspecter l’architecture du système ou la modifier. Dans le cas
où telles fonctionalités ne sont pas souhaitées dans une architecture concrète (introspection ou modification), le compilateur pourrait omettre la génération de ces interfaces de contrôle.
D.1.2.4
Implementations alternatives des méta-données
Les méta-données générées pour un composant sont fixes. Il s’agit d’un certain nombre de structures C prédéfinies. Par exemple les identifiants d’interfaces clientes sont implémentés comme pointeurs
stockés dans un tableau. Sur une architecture 32-bit, ce pointeur pourrait potentiellement identifier une
interface parmi 232 − 1. Pour optimiser l’occupation mémoire, un identifiant d’interface pourrait être
implémenté comme un index dans un tableau d’identifiants. Pour un système sur AVR, ce tableau ne
dépasserait guère 256 interfaces (i.e. entrées) et l’identifiant pourrait être codé sur 8 bits.
L’objectif est alors de proposer des implémentations alternatives des méta-données d’un composant
ou du système entier.
D.1.2.5
Inline des composants
Dans Kortex, pour une meilleure réutilisation de composants pilotes de périphériques, le code bas
niveau dépendant d’une architecture matérielle concrète est implémenté dans des composants séparés.
Ainsi par exemple, les pilotes utilisent tous un composant irqsafe implémentant le masquage d’interruption sur une architecture donnée, composant appelé fréquemment. En général il s’agit d’un quelques
instructions en assembleur. Cependant, le système paie un surcoût lié au composant – surcoût d’exécution
lié à la liaison et surcoût mémoire lié aux méta-données.
L’objectif est alors de pouvoir ”inliner” (analogie avec les fonctions inline de C) le code des composants (ou interfaces) serveurs dans les composants clients.
D.2
Les problèmes
D.2.1
Problèmes identifiés de l’implémentation actuelle
Pour implémenter les optimisations telles que décrites, nous avons identifiés plusieurs problèmes
dans l’implémentation actuelle de T HINK.
Le langage d’implémentation Le langage d’implémentation de composants (ou le dialect C) est
dépendant d’une structure de méta-données – le dialect impose une structure. Par exemple un attribut
est accédé avec la construction ATT.myAttribute. Le point, ’.’, dans cette syntaxe impose que les
méta-données d’attributs sont une structure avec des champs qui représentent les attributs.
Le compilateur Le compilateur actuel est peu flexible et génère uniquement une structure unique
de méta-données de composants (et par conséquent une seule représentation binaire du composant).
Cependant, la flexibilité du compilateur est dans le support de la génération des interfaces de contrôle –
différentes implémentations d’interfaces de contrôle peuvent être générées.
117
D.3. Vers une implémentation
D.2.2
Chapitre D. Optimisations architecturales sélectives
Problèmes liés à l’implémentation des optimisations
Mise à part les problèmes de l’implémentation actuelle, les optimisations architecturales présentent
plusieurs difficultés pour construire des systèmes à composants de manière flexible. Ces problèmes sont
discutés plus en détail dans (Lobry & Polakovic, 2008).
Spécification des optimisations Pour un système donné, l’utilisateur doit pouvoir spécifier les différentes informations d’optimisation de l’architecture. De plus, cette spécification doit se faire de manière
indépendante de la spécification des composants de façon à pouvoir réutiliser les composants dans une
autre architecture, optimisée différemment. Ce support pour la spécification doit pouvoir être suffisamment expressif pour permettre les différentes combinaisons possibles.
Analyse de l’architecture Comme évoqué au chapitre 5 nous abordons le compilateur avec un soucis
de pouvoir intégrer des aspects non-fonctionnels à l’architecture, comme nous considérons l’interface de
reconfiguration. Le compilateur doit garantir une cohérence des différentes spécifications d’un système
– son architecture, les optimisations et les différents aspects non-fonctionnels appliqués. Par exemple,
dans une architecture reconfigurable, toutes les liaisons ne peuvent pas être statiques.
Représentations internes du compilateur Le compilateur T HINK génère du code C, glue, à partir d’une représentation interne de l’architecture du système à construire. Pour chaque élément de la
représentation de l’architecture, une partie du code est générée, de manière prédéfinie, de façon à maintenir la cohérence de l’ensemble du code C glue généré. Le flot de génération de code est déterminé
de manière fixe par un pattern visiteur. Pour pouvoir implémenter les optimisations il est nécessaire de
disposer d’une représentation interne du code C à générer de façon à pouvoir le modifier à plusieurs
moment du flot de génération de code. En effet, pour implémenter les optimisations, il est nécessaire de
coordonner la structure du code glue généré par les différents modules.
D.3
Vers une implémentation
Nous avons implémentés un premier prototype de compilateur pouvant générés des structures optimisées à composants. Nous avons appelé ce compilateur N UPTSE2 Ce prototype se base sur trois modifications du framework T HINK. Ces modifications ne sont décrites que brièvement, car récemment
N UPTSE a vu une réingéniérie importante qui a modifié la spécification des différents éléments, néanmoins sans altérer leur rôle dans l’implémentation des optimisations.
D.3.1
Un nouveau langage d’implémentation de composants
Nous avons défini un nouveau langage d’implémentation de composants, appelé N UP C. Ce langage
est une extension du langage C qui définit des mots-clés représentant les différents concepts présents
dans la description ADL d’un composant. Ainsi, le code d’implémentation de composants ne fait aucune
supposition sur la struture des méta-données, uniquement sur leur existance. Par exemple un attribut
myAttr peut être accédé dans le code source par le mot-clé ATTR myAttr.
Dans la dernière version du framework, la langage N UPT C est du C pur (ne définissant pas de nouveaux mot-clés) avec des annotations dans les commentaires. Ces annotations permettent au parseur
C du compilateur N UPTSE d’associer les différents éléments du code (appel de méthode, définition de
fonctions ou accès aux variables) à la génération de méta-données et de code glue.
2
Du nom du sommet himalayan Nuptse (7861m).
118
Chapitre D. Optimisations architecturales sélectives
D.3.2
D.3. Reconfiguration dynamique
Spécification des optimisations
La spécification des optimisations architecturales est dissociée de la description architecturale d’un
composant, de façon à pouvoir réutiliser un composant dans des contextes d’optimisations différents.
Nous avons réutilisé le mécanisme de propriétés pouvant être associées à un composant, décrites au
chapitre 5. A l’aide du langage FlexProp, il est possible d’associer des optimisations à tout élément de
l’architecture.
Dans la dernière version du framework, le langage FlexProp a été remplacé par des extensions ADL.
A la compilation, une extension ADL permet d’étendre l’architecture du système à compiler et ajouter
des éléments à cette architecture (comme par exemple des interface de contrôles ou des propriétés).
D.3.3
Support de compilation
Le compilateur N UPTSE se base sur le compilateur décrit au chapitre 5. De plus, il définit un format
interne représentant le code C glue à générer – C ODE G EN. La structure du compilateur N UPTSE fait
objet de l’article (Lobry & Polakovic, 2008).
D.4
Optimisations architecturales et reconfiguration dynamique
Les différentes implémentation de la reconfiguration dynamique peuvent avoir un impact sur les
performances du système, par exemple causé par l’utilisation des intercepteurs. Pour minimiser l’impact
des différentes implémentations, il serait intéréssant d’appliquer les optimisations architecturales à un
système reconfigurable. Cependant une analyse du système à construire est nécessaire pour déterminer
le compromis entre l’efficacité et la flexibilité, par exemple, les liaisons d’un composant reconfigurable
doivent être flexibles de façon à pouvoir être modifiées pendant la reconfiguration.
D.5
En conclusion
Nous avons implémenté un prototype de compilateur pouvant générer différentes structures de métadonnées pour un système composant. L’intérêt d’une telle approche étant de pouvoir construire des
systèmes à composants très flexibles, ou des systèmes n’ayant pas de surcoût lié à l’utilisation de composants (le système est équivalent à un système écrit en C pur), ou de pouvoir satisfaire un compromis
entre efficacité et flexibilité entre les deux extrêmes.
Les optimisations architecturales, telles que présentées, sont un mécanisme de bas niveau du compilateur N UPTSE. Afin de satisfaire les différents besoin en construction de systèmes à composants, une
phase d’analyse des spécifications (architecturales, aspects non-fonctionnels et optimisations) et de leur
cohérence doit précéder la génération de code.
119
D.5. En conclusion
Chapitre D. Optimisations architecturales sélectives
120
References
A DYA , ATUL , H OWELL , J ON , T HEIMER , M ARVIN , B OLOSKY, W ILLIAM J., & D OUCEUR , J OHN R.
2002. Cooperative task management without manual stack management. Pages 289–302 of : Proceedings of the general track : 2002 usenix annual technical conference. Berkeley, CA, USA :
USENIX Association.
A JMANI , S. 2004. Automatic software upgrades for distributed systems. Ph.D., MIT.
A PPAVOO , J., AUSLANDER , M., S ILVA , D. DA , E DELSOHN , D., K RIEGER , O., O STROWSKI , M.,
ROSENBURG , B., W ISNIEWSKI , R.W., & X ENIDIS , J. 2002. K42 overview.
A PPAVOO , J., H UI , K., S OULES , C. A. N., W ISNIEWSKI , R. W., S ILVA , D. M. DA , K RIEGER , O.,
AUSLANDER , M. A., E DELSOHN , D. J., G AMSA , B., G ANGER , G. R., M C K ENNEY, P., O S TROWSKI , M., ROSENBURG , B., S TUMM , M., & X ENIDIS , J. 2003. Enabling autonomic behavior
in systems software with hot swapping. Ibm syst. j., 42(1), 60–76.
A RMSTRONG , J OE , V IRDING , ROBERT, W IKSTR ÖM , C LAES , & W ILLIAMS , M IKE. 1996. Concurrent
programming in erlang. Second edn. Prentice-Hall.
A RTIST 2. http ://www.artist-embedded.org – network of excellence on embedded systems design.
ATMEL. Atmel avr 8-bit risc microcontrollers. http ://www.atmel.com.
AVIZIENIS , A LGIRDAS , L APRIE , J EAN -C LAUDE , & R ANDELL , B RIAN. ?. Dependability and its
threats : A taxonomy.
BADGER , L., S TERNE , D. F., S HERMAN , D. L., WALKER , K. M., & H AGHIGHAT, S. A. 1995. Practical domain and type enforcement for unix. Page 66 of : Sp ’95 : Proceedings of the 1995 ieee
symposium on security and privacy. Washington, DC, USA : IEEE Computer Society.
BALTER , R., B ELLISSARD , L., B OYER , F., R IVEILL , M., & V ION -D URY, J. 1998. Architecturing and
configuring distributed applications with olan.
BARHAM , PAUL , D RAGOVIC , B ORIS , F RASER , K EIR , H AND , S TEVEN , H ARRIS , T IM , H O , A LEX ,
N EUGEBAUER , ROLF, P RATT, I AN , & WARFIELD , A NDREW. 2003. Xen and the art of virtualization. Pages 164–177 of : Sosp ’03 : Proceedings of the nineteenth acm symposium on operating
systems principles. New York, NY, USA : ACM.
BASS , L EN , C LEMENTS , PAUL , & K AZMAN , R ICK. 1998. Software architecture in practice. Boston,
MA, USA : Addison-Wesley Longman Publishing Co., Inc.
BASU , A NANDA , B OZGA , M ARIUS , & S IFAKIS , J OSEPH. 2006. Modeling heterogeneous real-time
components in bip. Pages 3–12 of : Sefm ’06 : Proceedings of the fourth ieee international conference on software engineering and formal methods. Washington, DC, USA : IEEE Computer Society.
BASU , A NANDA , M OUNIER , L AURENT, P OULHI ÈS , M ARC , P ULOU , JACQUES , & S IFAKIS , J OSEPH.
2007. Using bip for modeling and verification of networked systems – a case study on tinyos-based
networks. Pages 257–260 of : Nca.
121
REFERENCES
REFERENCES
BAUMANN , A., H EISER , G., A PPAVOO , J., DA S ILVA , D., K RIEGER , O., W ISNIEWSKI , R.W., &
K ERR , J. 2005. Providing dynamic update in an operating system. In : Proceedings of the 2005
USENIX annual technical conference.
B ELL , D ONALD. 2003 (june). UML basics : An introduction to the Unified Modeling Language.
B ERRY, G ÉRARD. 2000. The foundations of esterel. Proof, language, and interaction : essays in honour
of robin milner, 425–454.
B ERSHAD , B.N., S AVAGE , S., PARDYAK , P., S IRER , E.G., F IUCZYNSKI , M. E., B ECKER , D., C HAM BERS , C., & E GGERS , S. 1995. Extensibility safety and performance in the SPIN operating system.
Pages 267–283 of : Proceedings of the 15th acm symposium on operating systems principles. ACM
Press.
B ERSHAD , B RIAN , C HAMBERS , C., E GGERS , S., M AEDA , C., M C NAMEE , D., PARDYAK , P., S A VAGE , S., & S IRER , E. G. 1994. SPIN - An Extensible Microkernel for Application-specific Operating System Services, Technical Report TR-94-03-03. Tech. rept. University of Washington.
B HATTI , S., C ARLSON , J., DAI , H., D ENG , J., ROSE , J., S HETH , A., S HUCKER , B., G RUENWALD ,
C., T ORGERSON , A., & H AN , R. 2005. MANTIS OS : An Embedded Multithreaded Operating
System for Wireless Micro Sensor Platforms. Monet, 10(4), 563–579.
B LAIR , G ORDEN S., & S TEFANI , J EAN -B ERNARD. 1998. Open distributed processing and multimedia.
Boston, MA, USA : Addison-Wesley Longman Publishing Co., Inc.
B LOOM , T. 1983. Dynamic module replacement in a distributed programming system. Ph.D., MIT. Also
as MIT LCS Tech. Report 303.
B LOOM , T., & DAY, M. 1993. Reconfiguration and module replacement in Argus : Theory and Practice.
Iee software engineering journal, 8(2).
B OSCH. 1991. Can specification, version 2.0. http ://www.semiconductors.bosch.de/pdf/can2spec.pdf.
B RUNETON , E., C OUPAYE , T., & S TEFANI , J.-B. 2004. The Fractal Component Model. http ://fractal.objectweb.org.
B RUNETON , E., C OUPAYE , T HIERRY, L ECLERCQ , M., Q U ÉMA , V., & S TEFANI , J.-B. 2006. The
Fractal Component Model and its Support in Java. Software - practice and experience, special issue
on experiences with auto-adaptive and reconfigurable systems, 36(11–12), pp. 1257–1284.
C AMPBELL , R. H., & TAN , S EE -M ONG. 1995. /spl mu/choices : an object-oriented multimedia operating system. Page 90 of : Hotos ’95 : Proceedings of the fifth workshop on hot topics in operating
systems (hotos-v). Washington, DC, USA : IEEE Computer Society.
C AMPBELL , ROY H., & I SLAM , NAYEEM. 1993. Choices : a parallel object-oriented operating system.
Research directions in concurrent object-oriented programming, 393–451.
C HARRA , O. 2004. Conception de noyaux de systèmes embarqués reconfigurables. Ph.D., Université
Joseph Fourier – Grenoble 1.
C HEUNG , W. H., & L OONG , A NTHONY H. S. 1995. Exploring issues of operating systems structuring :
from microkernel to extensible systems. Sigops oper. syst. rev., 29(4), 4–16.
C HIPCON. Cc1000 – single chip very low power rf transceiver, focus.ti.com/lit/ds/symlink/cc1000.pdf.
http ://www.chipcon.com.
C LARKE , M., & C OULSON , G. 1998. An architecture for dynamically extensible operating systems.
Page 145 of : Cds ’98 : Proceedings of the international conference on configurable distributed
systems. Washington, DC, USA : IEEE Computer Society.
122
REFERENCES
REFERENCES
C LARKE , M ICHAEL , B LAIR , G ORDON S., C OULSON , G EOFF , & PARLAVANTZAS , N IKOS. 2001. An
efficient component model for the construction of adaptive middleware. Pages 160–178 of : Middleware ’01 : Proceedings of the ifip/acm international conference on distributed systems platforms
heidelberg. London, UK : Springer-Verlag.
C ONSEL , C., H ORNOF, L., M ARLET, R., M ULLER , G., T HIBAULT, S., VOLANSCHI , E.-N., L AWALL ,
J., & N OY É , J. 1998. Tempo : specializing systems applications and beyond. Acm comput. surv.,
30(3es), 19.
C ONSEL , C HARLES , H ORNOF, L UKE , N O ËL , F RANÇOIS , N OY É , JACQUES , & VOLANSCHE , N ICO LAE . 1996. A uniform approach for compile-time and run-time specialization. Pages 54–72 of :
Selected papers from the internaltional seminar on partial evaluation. London, UK : SpringerVerlag.
C OOK , R. P. 1980. *mod a language for distributed programming. Ieee trans. softw. eng., 6(6), 563–571.
C OULSON , G EOFF , B LAIR , G ORDON S., C LARKE , M ICHAEL , & PARLAVANTZAS , N IKOS. 2002. The
design of a configurable and reconfigurable middleware platform. Distrib. comput., 15(2), 109–126.
DABEK , F RANK , Z ELDOVICH , N ICKOLAI , K AASHOEK , F RANKS , M AZI ÈRES , DAVID , , & M ORRIS ,
ROBERT. 2002. Event-driven programming for robust software. In : Proceedings of the 2002 sigops
european workshop.
DAMM , W ERNER. 2006a. Embedded system development for automotive applications : trends and
challenges. Pages 1–1 of : Emsoft ’06 : Proceedings of the 6th acm & ieee international conference
on embedded software. New York, NY, USA : ACM.
DAMM , W ERNER. 2006b. Embedded system development for automotive applications : trends and
challenges. http ://www.artist-embedded.org/docs/PositionPapers/Damm EmSoft06.pdf.
DASHOFY, E RIC M., DER H OEK , A NDR É ; VAN , & TAYLOR , R ICHARD N. 2001. A highly-extensible,
xml-based architecture description language. Page 103 of : Wicsa ’01 : Proceedings of the working
ieee/ifip conference on sof tware architecture (wicsa’01). Washington, DC, USA : IEEE Computer
Society.
DAVID , P.-C., & L EDOUX , T. 2005. Une approche par aspects pour le développement de composants
fractal adaptatifs. Pages 91–108 of : 2ème journée francophone sur le développement de logiciels
par aspects (JFDLPA 2005). Lille, France : Hermès.
DAVID , P IERRE -C HARLES. 2005 (July). Développement de composants fractal adaptatifs : un langage
dédié à l’aspect d’adaptation. Phd thesis, Université de Nantes / École des Mines de Nantes.
DAVID , P IERRE -C HARLES , & L EDOUX , T HOMAS. 2006 (July). Safe dynamic reconfigurations of fractal architectures with fscript. In : Proceedings of the 5th fractal workshop at ecoop 2006.
D E M ICHIEL , L INDA , & K EITH , M ICHAEL. 2006. Jsr 220 : Enterprise javabeans, version 3.0. Tech.
rept. Sun Microsystems.
D ENYS , G., P IESSENS , F., & M ATTHIJS , F. 2002. A survey of customizability in operating systems
research. Acm comput. surv., 34(4), 450–468.
D IJKSTRA , E DSGER W. 1968. The structure of the ”the”-multiprogramming system. Commun. acm,
11(5), 341–346.
D OUENCE , R ÉMI , A LLEN , ROBERT, & G ARLAN , DAVID. 1997. Specifying dynamism in software architectures. Pages 11–22 of : L EAVENS , G ARY T., & S ITARAMAN , M URALI (eds), Proceedings of
the first workshop on the foundations of compone nt-based systems, zurich, switzerland, september
26 1997.
123
REFERENCES
REFERENCES
D RAVES , R ICHARD P., B ERSHAD , B RIAN N., R ASHID , R ICHARD F., & D EAN , R ANDALL W. 1991.
Using continuations to implement thread management and communication in operating systems.
Pages 122–136 of : Proceedings of the13th ACM symposium on operating systems principle. Association for Computing Machinery SIGOPS.
D UNKELS , A., G RONVALL , B., & VOIGT, T. 2004. Contiki - A Lightweight and Flexible Operating
System for Tiny Networked Sensors. Pages 455–462 of : Lcn ’04 : Proceedings of the 29th annual
ieee international conference on local computer networks (lcn’04).
D UNKELS , A., F INNE , N., E RIKSSON , J., & VOIGT, T. 2006. Run-time dynamic linking for reprogramming wireless sensor networks. In : Proceedings of the 4th acm conference on embedded
networked sensor systems (sensys 2006).
E2R. End-to-End Reconfigurability. http ://e2r2.motlabs.com.
E C OS .
http ://sources.redhat.com/ecos.
ELF. System v application binary interface specification, tool interface standard, executable and linking
format. http ://www.caldera.com/developers/devspecs/gabi41.pdf.
E NGLER , D.R., K AASHOEK , M.F., & O’T OOLE , J R ., J. 1995. Exokernel : an operating system architecture for application-level resource management. Pages 251–266 of : Proceedings of the 15th
acm symposium on operating systems principles. ACM Press.
FASSINO , J.-F. 2001. Think : vers une architecture de systèmes flexibles. Ph.D. thesis, École Nationale
Supérieure des Télécommunications.
FASSINO , J.-P., S TEFANI , J.-B., L AWALL , J., & M ULLER , G. 2002. Think : a software framework
for component-based operating system kernels. Pages 73–86 of : Proceedings of the 2002 USENIX
annual technical conference. USENIX, Monterey, CA.
F ORD , B., L EPREAU , J., C LAWSON , S., M AREN , K. VAN , ROBINSON , B., & T URNER , J. 1997.
The Flux OS Toolkit : Reusable Components for OS Implementation. Page 14 of : Hotos ’97 :
Proceedings of the 6th workshop on hot topics in operating systems (hotos-vi). Washington, DC,
USA : IEEE Computer Society.
F ORIN , A., H ELANDER , J., P HAM , P., & R AJENDIRAN , J. 2001. Component based invisible computing.
F RIEDRICH , L. F ERNANDO , S TANKOVIC , J OHN , H UMPHREY, M ARTY, M ARLEY, M ICHAEL , & H AS KINS , J OHN . 2001. A survey of configurable, component-based operating systems for embedded
applications. Ieee micro, 21(3), 54–68.
G ABBER , E., S MALL , C., B RUNO , J., B RUSTOLONI , J., & S ILBERSCHATZ , A. 1999. The Pebble
Component-Based Operating System. Pages 267–282 of : Proceedings of the USENIX annual
technical conference.
G ARLAN , D., M ONROE , R. T., & W ILE , D. 2000. ACME : Architectural Description of ComponentBased System s. Pages 47–68 of : L EAVENS , G ARY T., & S ITARAMAN , M URALI (eds), Foundations of component-based systems. Cambridge University Press.
G ARLAN , DAVID , & S HAW, M ARY. 1994. An introduction to software architecture. Tech. rept. Carnegie
Mellon University, Pittsburgh, PA, USA.
G AY, D., L EVIS , P., VON B EHREN , R., W ELSH , M., B REWER , E., & C ULLER , D. 2003. The nesC
language : A holistic approach to networked embedded systems. Pages 1–11 of : Proceedings of the
acm sigplan 2003 conference on programming language design and implementation (plid’03).
124
REFERENCES
REFERENCES
G HORMLEY, D OUGLAS P., P ETROU , DAVID , RODRIGUES , S TEVEN H., & A NDERSON , T HOMAS E.
1998. Slic : an extensibility system for commodity operating systems. Pages 4–4 of : Atec’98 : Proceedings of the annual technical conference on usenix annual technical conference, 1998. Berkeley,
CA, USA : USENIX Association.
G UPTA , D EEPAK , & JALOTE , PANKAJ. 1993. On line software version change using state transfer
between processes. Softw. pract. exper., 23(9), 949–964.
H AERTIG , H., H OHMUTH , M., L IEDTKE , J., & S CHOENBERG , S. 1997. The performance of
microkernel-based systems. Pages 66–77 of : Proceedings of the sixteenth acm symposium on
operating systems principles. ACM Press.
H ALBWACHS , N., C ASPI , P., R AYMOND , P., & P ILAUD , D. 1991. The synchronous data-flow programming language LUSTRE. Proceedings of the ieee, 79(9), 1305–1320.
H AN , C.-C., K UMAR , R., S HEA , R., KOHLER , E., & S RIVASTAVA , M. 2005. A dynamic operating
system for sensor nodes. Pages 163–176 of : Mobisys ’05 : Proceedings of the 3rd international
conference on mobile systems, applications, and services.
H ELANDER , J., & F ORIN , A. 1998. MMLite : a highly componentized system architecture. Pages 96–
103 of : Ew 8 : Proceedings of the 8th acm sigops european workshop on support for composing
distributed applications. Sintra, Portugal : ACM Press.
H ICKS , M. W. 2001. Dynamic software updating. Ph.D., The University of Pennsylvania.
H ICKS , M ICHAEL W., & N ETTLES , S COTT. 2005. Dynamic software updating. Acm trans. program.
lang. syst., 27(6), 1049–1096.
H ILDEBRAND , DAN. 1992. An architectural overview of qnx. Pages 113–126 of : Proceedings of
the workshop on micro-kernels and other kernel architectures. Berkeley, CA, USA : USENIX
Association.
H ILL , J., S ZEWCZYK , R., W OO , A., H OLLAR , S., C ULLER , D., & P ISTER , K. 2000. System architecture directions for networked sensors. Pages 93–104 of : Proceedings of the ninth international
conference on architectural support for programming languages and operating systems (asplos).
H J ÁLMT ÝSSON , G ÍSLI , & G RAY, ROBERT. 1998. Dynamic c++ classes : a lightweight mechanism to
update code in a running program. Pages 6–6 of : Atec’98 : Proceedings of the annual technical
conference on usenix annual technical conference, 1998. Berkeley, CA, USA : USENIX Association.
H OFMEISTER , C HRISTINE R. 1994. Dynamic reconfiguration of distributed applications. Ph.D., University of Maryland.
H ORIE , M ICHAEL , PANG , JAMES C., M ANNING , E RIC G., & S HOJA , G HOLAMALI C. 1998. Using
meta-interfaces to support secure dynamic system reconfiguration. In : Proceedings of the 4th
international conference on configurable distributed systems (iccds).
H ORN , PAUL. 2001 (Oct). Autonomic Computing — IBM’s Perspective on the State of Information
Technology. IBM Corporation.
H UTCHINSON , N ORMAN C., & P ETERSON , L ARRY L. 1991. The x-kernel : An architecture for implementing network protocols. Ieee trans. softw. eng., 17(1), 64–76.
I TOH , J., YOKOTE , Y., & L EA , R. 1995. Using Meta-Objects to Support Optimisation in the Apertos
Operating System. Pages 147–158 of : Proceedings of the usenix conference on object-oriented
technologies (coots).
JARBOUI , T., FASSINO , J.-P., & L ACOSTE , M. 2004. Applying components to access control design :
Towards a framework for os kernels. In : International conference on dependable systems and
networks (dsn 2004).
125
REFERENCES
REFERENCES
JARBOUI , T., M ARX , F., L AVAL , J.-P., G HOZZI , M., G ERMAIN , F., & L OBRY, O. 2006a. The Cognichip : A flexible, lightweight spectrum monitor. In : COGnitive systems with interactive sensors
(COGIS).
JARBOUI , TAHAR , L ACOSTE , M ARC , & WADIER , P IERRE. 2006b. A component-based policy-neutral
authorization architecture. In : Cfse’06 : Conférence française sur les systèmes d’exploitation.
J EONG , J., K IM , S., & B ROAD , A. 2003. Network reprogramming. TinyOS documentation. 2003.
http ://www.tinyos.net/tinyos-1.x/doc/ NetworkReprogramming.pdf.
JN/TML. JM/TML Software Coordination JVT software page. http ://bs.hhi.de/suehring/tml.
K ETFI , A., B ELKHATIR , N., & C UNIN , P.-Y. 2002. Automatic adaptation of component-based software : Issues and experiences. Pages 1365–1371 of : Proceedings of the international conference
on parallel and distributed processing techniques and applications. CSREA Press.
K ICZALES , G REGOR , L AMPING , J OHN , L OPES , C HRISTINA V IDEIRA , M AEDA , C HRIS , M ENDHE KAR , A NURAG , & M URPHY, G AIL . 1997. Open implementation design guidelines. Pages 481–490
of : Icse ’97 : Proceedings of the 19th international conference on software engineering. New York,
NY, USA : ACM.
KON , FABIO , S INGHAI , A SHISH , C AMPBELL , ROY H., C ARVALHO , D ULCINEIA , M OORE , ROBERT,
& BALLESTEROS , F RANCISCO J. 1998. 2k : A reflective, component-based operating system for
rapidly changing environments. Pages 388–389 of : Ecoop ’98 : Workshop ion on object-oriented
technology. London, UK : Springer-Verlag.
K RAMER , J., & M AGEE , J. 1990. The evolving philosophers problem : Dynamic change management.
Ieee trans. software eng., 16(11).
L AUER , H UGH C., & N EEDHAM , ROGER M. 1979. On the duality of operating system structures.
Operating systems review, 13(2), 3–19.
L AYAIDA , O., Ö ZCAN , A. E., & S TEFANI , J.-B. 2005. A component-based approach for MPSoC SW
design : Experience with OS customization for H.264 decoding. In : 3rd workshop on embedded
systems for real-time multimedia.
L ECLERCQ , M., O ZCAN , A.-E., Q UEMA , V., & S TEFANI , J.-B. 2007. Supporting heterogeneous
architecture descriptions in an extensible toolset. In : Icse ’07 : Proceedings of the 29th international
conference on software engineering.
L EE , E DWARD A. 2000. What’s ahead for embedded software ? Computer, 33(9), 18–26.
L EE , E DWARD A. 2006. The problem with threads. Computer, 39(5), 33–42.
L EE , I NSUP. 1983. Dymos : a dynamic modification system. Ph.D., The University of Wisconsin Madison.
L EVIS , P., & C ULLER , D. 2002. Maté : A tiny virtual machine for sensor networks. In : Proceedings of the 10th international conference on architectural support for programming languages and
operating systems (asplos).
L IEDTKE , J. 1993. Improving IPC by kernel design. Pages 175–188 of : Proceedings of the 14th acm
symposium on operating systems principles. Asheville, NC, USA : ACM Press.
L IEDTKE , J. 1995. On micro-kernel construction. Pages 237–250 of : Proceedings of the 15th acm
symposium on operating systems principles. Copper Mountain, Colorado, USA : ACM Press.
L IEDTKE , J. 1996. Toward real microkernels. Commun. acm, 39(9), 70–77.
L OBRY, O LIVIER , & P OLAKOVIC , J URAJ. 2008. Controlling the performance overhead of componentbased systems. In : Software Composition, 7th International Symposium, SC 2008.
126
REFERENCES
REFERENCES
L UCKHAM , DAVID C., K ENNEY, J OHN L., AUGUSTIN , L ARRY M., S V ERA , JAME , B RYAN , D OUG ,
& M ANN , WALTER. 1995. Specification and analysis of system architecture using rapide. IEEE
transactions on software engineering, 21(4), 336–355.
M AEDA , C HRIS , L EE , A RTHUR , M URPHY, G AIL , & K ICZALES , G REGOR. 1997. Open implementation analysis and design. Pages 44–52 of : Ssr ’97 : Proceedings of the 1997 symposium on software
reusability. New York, NY, USA : ACM.
M AGEE , J., D ULAY, N., E ISENBACH , S., & K RAMER , J. 1995. Specifying Distributed Software Architectures. Pages 137–153 of : S CHAFER , W., & B OTELLA , P. (eds), Proc. 5th european software
engineering conf. (ESEC 95), vol. 989. Sitges, Spain : Springer-Verlag, Berlin.
M ARR ÓN , P. J., G AUGER , M., L ACHENMANN , A., M INDER , D., S AUKH , O., & ROTHERMEL , K.
2006. FlexCup : A Flexible and Efficient Code Update Mechanism for Sensor Networks. Pages
212–227 of : European workshop on wireless sensor networks.
M EDVIDOVIC , N ENAD , DASHOFY, E RIC M., & TAYLOR , R ICHARD N. 2007. Moving architectural
description from under the technology lamppost. Inf. softw. technol., 49(1), 12–31.
M ITCHELL , S COTT, NAGUIB , H ANI , C OULOURIS , G EORGE , & K INDBERG , T IM. 1998. Dynamically
reconfiguring multimedia components : a model-based approach. Pages 40–47 of : Ew 8 : Proceedings of the 8th acm sigops european workshop on support for composing distributed applications.
New York, NY, USA : ACM.
M ITOLA , J OSEPH. 2000. Cognitive radio : An integrated agent architecture for software defined radio.
Ph.D. thesis, Royal Institute of Technology (KTH).
M ORRIS , ROBERT, KOHLER , E DDIE , JANNOTTI , J OHN , & K AASHOEK , M. F RANS. 1999. The click
modular router. Sigops oper. syst. rev., 33(5), 217–231.
N EAMTIU , I ULIAN , H ICKS , M ICHAEL , S TOYLE , G ARETH , & O RIOL , M ANUEL. 2006. Practical dynamic software updating for c. Pages 72–83 of : Pldi ’06 : Proceedings of the 2006 acm sigplan
conference on programming language design and implementation. New York, NY, USA : ACM.
N ECULA , G EORGE C. 1997. Proof-carrying code. Pages 106–119 of : Popl ’97 : Proceedings of the
24th acm sigplan-sigact symposium on principles of programming languages. New York, NY, USA :
ACM.
N ECULA , G EORGE C., & L EE , P ETER. 1996. Safe kernel extensions without run-time checking. Pages
229–243 of : Osdi ’96 : Proceedings of the second usenix symposium on operating systems design
and implementation. New York, NY, USA : ACM.
OMG. 2001. CORBA 3.0 New Components Chapters. Tech. rept. OMG TC Document otc/2001-11-03.
Object Managment Group.
OMG. 2002. Lightweight CORBA component model. Tech. rept. Lightweight CCM 2003 FTF ptc/200406-10. Object Management Group.
OMG. 2004. Unified Modeling Language (UML), version 2.0, Object Management Group.
OSEK/VDX. Offene systeme und deren schnittstellen für die elektronik in kraftfahrzeugen (eng., ”open
systems and their interfaces for the electronics in motor vehicles”). http ://www.osek-vdx.org.
O USTERHOUT, J OHN. 1996 (Jan.). Why threads are a bad idea (for most purposes). In : Usenix winter
technical conference.
O ZCAN , A.-E. 2007. Conception et implantation d’un environnement de développement de logiciels
à base de composants, applications aux systèmes multiprocesseurs sur puce. Ph.D. thesis, Institut
National Polytechnique de Grenoble.
PALM OS. Palmos by palm inc., currently garnet os by access. http ://www.palmos.com.
127
REFERENCES
REFERENCES
P L ÁSIL , F., B ÁLEK , D., & JANECEK , R. 1998. Sofa/dcup : Architecture for component trading and dynamic updating. Page 43 of : Cds ’98 : Proceedings of the international conference on configurable
distributed systems. Washington, DC, USA : IEEE Computer Society.
POSIX.
Portable
operating
system
http ://www.opengroup.org/onlinepubs/009695399.
interface,
ieee
std
1003.1.
P U , C., AUTREY, T., B LACK , A., C ONSEL , C., C OWAN , C., I NOUYE , J., K ETHANA , L., WALPOLE ,
J., & Z HANG , K. 1995a. Optimistic incremental specialization : streamlining a commercial operating system. Sigops oper. syst. rev., 29(5), 314–321.
P U , C ALTON , AUTREY, T ITO , B LACK , A NDREW P., C ONSEL , C HARLES , C OWAN , C RISPIN , I N OUYE , J ON , K ETHANA , L AKSHMI , WALPOLE , J ONATHAN , & Z HANG , K E . 1995b. Optimistic
incremental specialization : Streamlining a commercial operating system. Pages 314–324 of : Proceedings of the 15th acm symposium on operating system principles.
R EID , A., F LATT, M., S TOLLER , L., L EPREAU , J., & E IDE , E. 2000 (Oct.). Knit : Component Composition for Systems Software. Pages 347–360 of : Proceedings of the 4th usenix symposium on
operating systems design and implementation (osdi).
R IPPERT, C HRISTOPHE , & S TEFANI , J EAN -B ERNARD. 2002. Think : a secure distributed systems
architecture. Pages 243–246 of : Ew10 : Proceedings of the 10th workshop on acm sigops european
workshop. New York, NY, USA : ACM.
ROZIER , M., A BROSSIMOV, V., A RMAND , F., B OULE , I., G IEN , M., G UILLEMONT, M., H ERRMANN ,
F., K AISER , C., L ANGLOIS , S., L EONARD , P., & N EUHAUSER , W. 1988. CHORUS distributed
operating system. In computing systems, Vol. 1(4), 305–370.
S AXENA , A NSHUMAN , L ACOSTE , M ARC , JARBOUI , TAHAR , L UCKING , U LF, & S TEINKE , B ERND.
2007. A software framework for autonomic security in pervasive environments. In : Third international conference on information systems security (iciss 2007).
SEA-AADL. Architecture analysis and design language (formerly avionics architecture description
language). http ://www.aadl.info/.
S EGAL , M ARK E., & F RIEDER , O PHIR. 1993. On-the-fly program modification : Systems for dynamic
updating. Ieee softw., 10(2), 53–65.
S ELTZER , M.I., E NDO , Y., S MALL , C., & S MITH , K.A. Oct. 1996. Dealing with disaster : Surviving
misbehaved kernel extensions. Pages 213–227 of : Proceedings of the 2nd usenix symposium on
operating systems design and implementation (osdi).
S ENART, A., C HARRA , O., & S TEFANI , J. 2002. Developing dynamically reconfigurable operating
system kernels with the think component architecture. In : In proceedings of the workshop on
engineering context-aware object-oriented systems and environments.
S HAW, M ARY, & G ARLAN , DAVID. 1996. Software architecture : perspectives on an emerging discipline. Upper Saddle River, NJ, USA : Prentice-Hall, Inc.
S MALL , C. 1997. MiSFIT : A tool for constructing safe extensible C++ systems. In : Proceedings of the
3rd usenix conference on object-oriented technologies (coots). USENIX.
S MALL , C., & S ELTZER , M. 1995. Structuring the kernel as a toolkit of extensible, reusable components. Pages 134–137 of : Proceedings of the 4th international workshop on object-orientation in
operating systems.
S OULES , C.A.N., A PPAVOO , J., H UI , K., W ISNIEWSKI , R.W., S ILVA , D. DA , G ANGER , G.R., K RIE GER , O., S TUMM , M., AUSLANDER , M., O STROWSKI , M., ROSENBURG , B., & X ENIDIS , J.
2003. System support for online reconfiguration. Pages 141–154 of : Proceedings of the 2003
USENIX annual technical conference.
128
REFERENCES
REFERENCES
S ZTIPANOVITS , JANOS , & S ASTRY, S HANKAR.
Embedded software : Opportunities and challenges.
University of California, Berkeley and DARPA/ITO,
http ://www.nitrd.gov/subcommittee/sdp/planning/presentations/UCBerkeley-Sastry.pdf.
S ZYPERSKI , C LEMENS. 2002. Component software : Beyond object-oriented programming. Boston,
MA, USA : Addison-Wesley Longman Publishing Co., Inc.
S ÉNART, A. 2003. Canevas logiciel pour la construction d’infrastructures logicielles dynamiquement
adaptables. Ph.D., Institut National Polytechnique de Grenoble.
T HINK. The THINK Project Homepage.
T OURNIER , J.-C H . 2005a. Qinna : Une architecture à base de composants pour la gestion de la qualité de service dans les systèmes embarqués mobiles. Ph.D. thesis, Institut National des Sciences
Appliquées de Lyon.
T OURNIER , J.-C H . 2005b. A survey of configurable operating systems, tr-cs-2005-43. Tech. rept. University of New Mexico.
V EITCH , A., & H UTCHINSON , N. 1998. Dynamic Service Reconfiguration and Migration in the Kea
Kernel. Page 156 of : Proceedings of the international conference on configurable distributed
systems (iccds). Washington, DC, USA : IEEE Computer Society.
VOLANSCHI , E UGEN N. 1998. Une approche automatique à la spécialisation de composants système.
Ph.D., Université de Rennes 1.
VON
B EHREN , J. ROBERT, C ONDIT, J EREMY, & B REWER , E RIC A. 2003a. Why events are a bad idea
(for high-concurrency servers). Pages 19–24 of : Hotos.
VON
B EHREN , ROB , C ONDIT, J EREMY, Z HOU , F ENG , N ECULA , G EORGE C., & B REWER , E RIC.
2003b. Capriccio : scalable threads for internet services. Pages 268–281 of : Sosp ’03 : Proceedings
of the nineteenth acm symposium on operating systems principles. ACM Press.
WAHBE , R., L UCCO , S., A NDERSON , T.E., & G RAHAM , S.L. 1993. Efficient software-based fault isolation. Pages 203–216 of : Proceedings of the 14th acm symposium on operating systems principles.
Asheville, NC, USA : ACM Press.
W EISER , M ARK. 1991. The computer for the twenty-first century. Scientific american.
W ELSH , M ATT, C ULLER , DAVID E., & B REWER , E RIC A. 2001. SEDA : An architecture for wellconditioned, scalable internet services. Pages 230–243 of : Symposium on operating systems principles.
YOKOTE , Y. 1992. The Apertos reflective operating system : the concept and its implementation. Pages
414–434 of : Proceedings on object-oriented programming systems, languages, and applications
(oopsla). ACM Press.
YOKOTE , YASUHIKO , M ITSUZAWA , ATSUSHI , F UJINAMI , N OBUHISA , & T OKORO , M ARIO. 1991.
Reflective object management in the muse operating system. Pages 16–23 of : Proceedings of the
1991 international workshop on object-orientation in operating systems (IWOOOS). Washington,
DC : IEEE Computer Society.
129
Téléchargement