TP ARINC 653/POK
Etienne Borde (Télécom Paris/LTCI)
(Le TP conçu par M. Borde a uniquement été adapté pour l'UE SEE/M2LSE, Merci Etienne !)
L'objectif de ce TP est d'expérimenter un OS conforme au standard ARINC653.
Nous allons principalement regarder la configuration d'une application dans cet
environnement.
Le TP a été conçu par Etienne Borde et la première version de la machine virtuelle
utilisée pour ce TP par des étudiants de Licence informatique, que je remercie
pour leur aide.
Pour lancer le TP, il faut :
- Télécharger le fichier pok_ubo.ova qui constitue une machine virtuelle prête à l'emploi.
Pour utiliser cette machine, il faudra l'importer sous Virtualbox
(via le menu Fichier/importer un appareil virtuel).
- Une fois la machine lancée, connectez vous sous le login "pok" (mot de passe "pok" également).
- Dans le home directory, vous trouverez un fichier pok.bash. Dans chaque shell
que vous utilisez, lancer la commande suivante avant tout utilisation de POK :
source pok.bash
Ce qui positionnera toutes les variables shell nécessaires pour ce TP.
Dans cette partie du TP, nous fournissons un exemple simple et sa
description. Cet exemple vous permettra de manipuler les outils utiles
pour ce TP. L'exemple illustre également la partie de l'APEX (l'API
définie par le standard ARINC 653) dont vous aurez besoin pour ce TP.
Description de l'exemple
L'exemple se trouve dans le home directory du compte pok,
dans le répertoire reference_example.
L'exemple que nous étudions est un système constitué
de 4 partitions : part1, part2, part3 et part4.
Chaque partition exécute
une tâche périodique de période égale à 1 seconde. Les partitions sont
ordonnancées cycliquement avec un « Major Frame » de 1 seconde. Chaque partition
se voit allouée successivement une « Partition Window » de 250 millisecondes.
L'ordonnancement des partitions est le suivant:
Les communications entre partitions se font via des port de type « sampling ».
Les partitions part1 et part2 ont chacune un port de sortie,
nommés respectivement
p1 pour part1 et p2 pour part2.
La partition part3 a
deux ports d'entrée p3 et p4,
et la partition part4 a un port d'entrée p5.
Dans une partition contenant un port de sortie, le code de la tâche périodique exécutée
toutes les secondes est simple : il affiche la valeur qu'il s'apprête à envoyer sur
le port, puis l'envoie. Dans une partition avec port(s) d'entrée, le code de la tâche
périodique exécutée toutes les secondes lit puis affiche la
(ou les données) reçue(s) sur le(s) port(s).
Les canaux (ou « channels ») de communication permettent aux données d'être transmises depuis
un port de sortie vers un port d'entrée.
Cela correspond dans AADL aux connexions entre composant.
Dans notre exemple, 1) le port p1 est
connecté au port p3 ; 2) le port p2 est connecté aux ports p4 et
p5. Dans cette application, il y a donc 3 canaux.
Enfin, nous avons borné pour chaque partition un espace mémoire
de 150000 octets (maximum).
Le schéma ci dessous résume l'architecture considérée dans cet exemple :
FIGURE 1 : description de l'exemple
Dans le répertoire reference_example,
qui fournit les différents éléments correspondants à la mise en oeuvre de ce système partitionné,
on trouve :
- Deux sous-répertoires input et output.
- Le répertoire input contient:
- un fichier XML (example-conf.xml)
- un Makefile
- un sous-répertoire pour chaque partition (part1, part2, part3 et part4).
Chacun de ces sous-répertoires contient également un fichier
Makefile et le code de la partition stocké dans le fichier main.c
-
Le répertoire output est vide.
Le fichier XML contient la configuration de l'architecture
décrite dans la section précédente: celle illustrée sur la FIGURE 1.
Le fichier part1/main.c contient le code d'initialisation, ainsi que
le code de la tâche périodique de la partition part1. Le point d'entrée
de la partition est la fonction main, fonction qui sera invoquée à
l'initialisation de la partition. Le code de cette fonction crée la
tâche périodique de la partition avec une période correspondant à 1 seconde.
Le point d'entrée associé à cette tâche (ou « process » selon le vocabulaire
ARINC653) est la fonction process1. Cette fonction sera exécutée à chaque
réveil de la tâche périodique.
Nous allons maintenant produire l'image du système et l'exécuter sur un
émulateur de carte : QEMU.
Dans le terminal après l'utilisation de pok.bash (comme
indiqué tout en haut du sujet de TP), restez dans le répertoire input,
puis exécutez :
make
L'exécution de make a pour effet de
- générer, à partir du fichier XML de configuration, des fichiers de code source C
dans le répertoire output qui était vide jusque là ;
- de compiler le noyau du système d'exploitation partitionné POK, configuré par ces fichiers générés ;
- de compiler le code C des partitions part1, part2, part3, et part4.
Vous pourrez ensuite lancer le système sur l'émulateur QEMU comme suit : depuis le terminal,
déplacez vous dans le répertoire input, puis exécutez :
make run
Pour faciliter la visualisation du résultat, vous pouvez rediriger la sortie
standard des partitions vers un fichier en procédant comme suit :
make run QEMU_MISC="-nographic -serial /dev/stdout > pok_exec.trace"
Le fichier pok_exec.trace
contiendra la sortie standard des partitions. Il
faudra alors terminer le processus QEMU en utilisant la
commande kill ou killall.
Vous devriez obtenir la trace d'exécution suivante :
partition part1 sends value through port p1: 1
partition part2 sends value through port p2: 1
partition part3 received value through port p3: 0
partition part3 received value through port p4: 0
partition part4 received value through port p5: 0
partition part1 sends value through port p1: 2
partition part2 sends value through port p2: 2
partition part3 received value through port p3: 1
partition part3 received value through port p4: 1
partition part4 received value through port p5: 1
partition part1 sends value through port p1: 3
partition part2 sends value through port p2: 3
partition part3 received value through port p3: 2
partition part3 received value through port p4: 2
partition part4 received value through port p5: 2
partition part1 sends value through port p1: 4
partition part2 sends value through port p2: 4
partition part3 received value through port p3: 3
partition part3 received value through port p4: 3
partition part4 received value through port p5: 3
partition part1 sends value through port p1: 5
partition part1 sends value through port p1: 5
partition part3 received value through port p3: 4
partition part3 received value through port p4: 4
partition part4 received value through port p5: 4
Questions :
- Ouvrir Le fichier XML du répertoire input et regarder dans ce fichier comment
sont décrits les
partitions, les canaux et l'ordonnancement des partitions (Major Frame).
- Dans chaque répertoire dédié à une partition (répertoires part1,
part2, part3 et part4), étudier le fichier main.c permettant
de lancer le code de la partition correspondante.
- Identifier dans les fichiers main.c la primitive qui permet :
- De créer un port de type sampling.
- D'écrire un message dans un port de type sampling.
- De lire un message depuis un port de type sampling.
- Pour les 3 primitives ci-dessous, déterminer le rôle de chaque argument.
- Identifier dans le code des partitions les arguments utilisés lors de la création d'un process.
Quels sont ceux que l'on utilise lors d'une analyse de l'ordonnancement ?
- Dans le répertoire output/kernel, ouvrir le fichier deployment.h. Ce fichier est généré
à partir du fichier XML et configure l'OS POK selon les consignes contenues dans le fichier XML.
Quelles sont les constantes de ce fichier qui représente l'ordonnancement des partitions?
Dans l'exercice ci-dessous, vous allez devoir configurer un système ARINC afin que les différentes
partitions puissent être correctement ordonnancées et que les communications puissent s'établir
convenablement entre les partitions.
On suppose que la société pour laquelle vous travaillez aujourd'hui souhaite faire
réaliser 4 applications par des fournisseurs différents et les intégrer
sur un unique calculateur sur lequel est déployé le système partitionné POK/ARINC653.
Ces applications sont appelées:
Navigation,
Radar,
Logging et
Display.
Voici la configuration des tâches de chaque application, telle que
négociée avec vos fournisseurs :
- Navigation : 2 tâches, de période 50 ms et 300 ms. Un temps d'exécution
de
10 ms toutes les 100 ms est nécessaire pour exécuter le code de cette application.
- Radar : une tâche de période 100 ms. Un temps d'exécution
de 25 ms toutes les
100 ms est nécessaire pour exécuter le code de cette application.
- Logging : une tâche de période 300 ms. Un temps d'exécution de 30 ms
toutes
les 100 ms est nécessaire pour exécuter le code de cette application.
- Display : deux tâches, de période 100 ms, 300 ms. Un temps d'exécution
de 35 ms
toutes les 100 ms est nécessaire pour exécuter le code de cette application.
Question 1:
Sur le papier, déterminez la « major frame » du système et la configuration
des partition windows pour l'ensemble de ces applications en respectant les informations
ci-dessus.
Question 2:
Nous supposons que l'application Radar communique avec l'application
Navigation. Navigation communique également avec l'application Display. Cette chaine
de deux communications met à jour l'affichage par Display des données produites par Radar.
Ces communications se feront via des ports de type « sampling » car chaque
application n'a besoin que de la dernière valeur produite pour fonctionner
correctement. Pour simplifier, nous supposons que les applications échangent
des entiers.
- Récupérer
les fichiers fournis ici constituant cette application
afin de simuler
l'exécution du système.
- Compléter le code des fichiers main.c des partitions Navigation, Radar et Display.
Le code à compléter est identifié par la chaine de caractères
TODO.
Il s'agit de positionner la valeur de certains paramètres pour les primitives de communication.
- Modifier le fichier XML fourni afin de
- Déclarer les 2 channels permettant de mettre en oeuvre les communications entre Radar et Navigation
d'une part, puis Navigation et Display d'autre part.
- Configurer l'ordonnancement des partitions que vous avez déterminé lors de la question 1.
- Les parties à compléter sont identifiées par la chaine de caractères
TODO.
- Après compilation du code par la commande make,
tester votre solution en exécutant l'application avec la commande make run.
- Attention : le code doit être recompilé à chaque modification du fichier XML ou d'un fichier main.c
Question 3:
L'étude de la trace d'exécution de l'exemple de référence montre que les
communications entre partitions sont décalées : lorsqu'une partition
émettrice envoie la valeur 3, la partition réceptrice reçoit la valeur 1
qui avait été produite au cycle précédent.
Ceci vient du fait que par défaut les vidanges (ou "flush") de
ports sont fait entre deux itérations correspondant chacune à une
"Major Frame". La figure ci-dessous illustre ce comportement.
FIGURE 2
Il est possible de modifier la configuration du système
d'exploitation pour corriger cela. POK offre deux mécanismes de
configuration classiques dans les systèmes partitionnés:
- la vidange peut se faire à la fin de chaque « partition window ».
La figure ci-dessous illustre ce comportement sur notre exemple de référence:
FIGURE 3
Pour activer cette configuration, il faut modifier le fichier XML
en ajoutant un attribut flush_type="window" à la configuration du module ARINC653.
Exemple:
<ARINC653_Module major_frame="1000" flush_type="window">
...
</ARINC653_Module>
- la vidange peut se faire de façon périodique, avec une période
MIF telle que (i) pour tout entier k, k*MIF correspond à une date de
changement de partition window et (ii) MAF est divisible par MIF.
La figure ci-dessous illustre ce comportement sur notre exemple de référence,
avec une période MIF à 500 ms:
FIGURE 4
Pour activer cette configuration, il faut modifier le fichier XML en
ajoutant (i) un attribut flush_type="minor_frame" et (ii) un attribut
minor_frame="500" à la configuration du module ARINC653.
Exemple:
<ARINC653_Module major_frame="1000" flush_type="minor_frame" minor_frame="500">
...
</ARINC653_Module>
Travail à faire:
- Modifier le fichier XML rédigé lors de la question 2 afin d'expérimenter les
différentes modes de gestion des ports de communication. En particulier, regardez l'impact
de ces modes sur les délais de bout en bout pour le transfert des données.
- Notez que plusieurs ordonnancement de partitions respectant les contraintes
temporelles des process/partitions sont possibles.
Les différentes
configurations (ordonnancement des partitions + mode de gestion des port) permettront
aux processus récepteurs de recevoir plus ou moins tôt les données (c'est-à-dire
d'agir sur les latences de bout en bout des données).