Skip to content

TP Xenomai

Documentation

  • Un très bon tutoriel complet à lire ici

  • les explications sur ce qu'est Xenomai, quels problèmes il résoud, et comment il le fait sont ici

  • Les API de Xenomai sont documentées ici

Test de l'environnement

Après avoir démarré vos machine avec l'image Debian, placez vous dans le répertoire /usr/lib/xenomai (peut être légèrement différent sur les machines de l'école) et cherchez un exécutable nommé latency. Lancez cet exécutable avec les privilèges administrateur. Si cela fonctionne, vous avez bien démarré le bon noyau, bravo. Vous pouvez également essayer la commande dmesg | grep -i xenomai pour vérifier que vous avez des sorties ressemblant à I-pipe: head domain Xenomai registered.

HelloWorld

  • Vous allez chercher dans la documentation de Xenomai ou dans les répertoires de tests fournis comment écrire un programme très simple, qui lance une tâche à la plus haute priorité temps réel (99) pour afficher le message "Hello Real-time World", en utilisant printf()

    • au debut de votre main, ajoutez la ligne mlockall( MCL_CURRENT | MCL_FUTURE ); afin de désactiver le mécanisme de swap mémoire sur disque pour votre application
    • création d'une tache avec rt_task_create() puis démarrage avec rt_task_start()
    • ou bien les deux en même temps avec rt_task_spawn()
    • rt_task_join() dans le main après le démarrage de la tâche temps réel pour attendre sa terminaison.
  • Pour compiler avec l'utilitaire make, vous allez avoir besoin d'un makefile un peu particulier. Reportez vous à cette page

  • Testez. En cas de soucis, vérifiez que le répertoire /usr/xenomai/lib (!! à l'école ce n'est peut petre pas exactement ce répertoire ! adaptez !) se trouve bien dans les répertoires de recherche des librairies dynamiques (variable LD_LIBRARY_PATH, sous bash, faites un echo $LD_LIBRARY_PATH pour voir sa valeur et un export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:nouveau pour ajouter le répertoire nouveau).

  • Si ca ne marche pas, vérifiez que vous êtes super-utilisateur pour lancer l’application.

  • Si ca ne marche toujours pas, essayez avec le code et le makefile de cette archive

  • Proposez une autre version du programme, en utilisant rt_printf à la place de printf.

Danger

Si ca ne marche pas, c'est que les librairies spécifiques à Xenomai ne sont pas installées, il va falloir le faire vous même, pour cela il faut suivre la documentation. Les étapes à suivre :

  • téléchargez les sources de xenomai 3.1 ici https://xenomai.org/downloads/xenomai/stable/latest/
  • décompressez l'archive et placez vous à la racine du repertoire obtenu puis tapez scripts/bootstrap
  • executez la commande ./configure
  • executez la commande make
  • en tant que root, executez la commande make install

Changement de contexte et passage en mode secondaire

Modifier vos deux programmes pour que l'affichage soit fait dans une boucle infini avec une attente d'1s :

Tant que VRAI
    affichage
    attente 1s 
Vous pouvez réaliser l'attente avec la fonction rt_task_sleep(). Attention, cette fonction prend en parametre un nombre de tics, pas des nano secondes. Cherchez dans les API comment convertir.

  • Pour les deux versions du programme, pendant qu'elles s'exécutent (pas en même temps !), testez dans un autre terminal les commandes suivantes :

    • ps -eTo pid,ppid,ucmd,class,rtprio,nice --sort class
    • cat /proc/xenomai/sched/stat
    • cat /proc/xenomai/sched/threads
  • Expliquez les résultats obtenus.

    • Pour une explication des sorties de cat, vous pouvez vous aider de cette page
    • Regardez notamment les autres fichiers de /proc/xenomai
  • Téléchargez cette archive et prenez le temps de regarder les commentaires dans le code. Compilez et executez d'abord en gardant la ligne printf puis en la remplacant par la ligne rt_printf. Concluez.

Tâche périodique

Pour rendre une tâche périodique, deux choses :

  • Au début de la tâche, appeler rt_task_set_periodic()

    • astuce : une tâche peut obtenir un descripteur de type RT_TASK d'elle-même avec la fonction rt_task_self()
    • pour gérer le temps, le type à utiliser est RTIME et des constantes sont définies comme par exemple TM_NOW
  • Entrer dans une boucle infinie (prévoyez dans la phase de debug de ne rentrer dans la boucle que 3 ou 4 fois...). Un passage dans la boucle correspond alors à une instance ou un job. Au début de la boucle, appeler la méthode bloquante rt_task_wait_period() : c'est elle qui va provoquer la suspension de la tâche jusqu'à sa prochaine activation périodique.

  • Tester en faisant une tache qui affiche toutes les secondes le temps courant et la durée écoulée depuis le dernier affichage (voir fonction rt_timer_read(). Vérifiez empiriquement la précision de l'activation.

  • générez maintenant un coût de 0,8s pour cette tâche grâce à la fonction rt_timer_spin()

  • observez ce qu'il se passe si vous descendez la période à 0,5s en gardant le coût à 0,8

  • utilisez le paramètre de rt_task_wait_period() pour afficher le compteur de dépassement proposé par xenomai. Expliquez comment il fonctionne (si il fonctionne).

Influence de la charge système

  • Ecrivez une tache périodique de période 1 ms qui affiche la durée écoulée entre deux activations périodiques en nanosecondes
  • Exécutez le programme en redirigeant la sortie vers un fichier pendant quelques secondes (a.out > fichier.log par exemple)
  • Télécharger le code de calc-stat.c et compilez-le (avec la librairie mathématique, option -lm de gcc). Ce programme permet de calculer le minimum, la moyenne et l'écart type d'une grandeur se trouvant dans un fichier.
  • utilisez-le pour obtenir des statistiques sur le fichier de résultat obtenu précédemment : cat fichier.log > ./calc-stat
  • refaites l'expérience mais en faisant tourner en parallèle la commande dohell fournie dans les répertoires de xenomai (commande qui génère de la charge parasite)

Mon système de tâche !

Proposez un programme qui lit les fichiers de description de systèmes de taches tels que définis au TP précédant et lance les taches périodiques correspondantes (utilisez rt_timer_spin()) pour simuler les coûts.