Dans les précédents articles nous avons observé les limites de performance des timers Linux et Linux-rt sur une Pandabaord. Cette fois nous allons comparer ces résultats avec ceux que nous obtenons sous Xenomai.
Aurons-nous une meilleure stabilité des tâches périodiques ?
Environnement d’expérimentation
Nous devons tout d’abord compiler un noyau Linux pour la Pandaboard après lui avoir appliqué le patch Xenomai. Ceci est relativement simple, je l’avais déjà décrit dans un article précédent.
Voici brièvement les étapes à suivre, nous considérons que la partition de boot de la Pandaboard est montée dans notre arborescence dans /media/Boot
et sa partition racine dans /media/Root
.
Télécharger Xenomai [~]$ git clone http://git.xenomai.org/xenomai-2.6.git xenomai Cloning into 'xenomai'... [...] Télécharger et décompresser Linux [~]$ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.38.8.tar.bz2 [...] [~]$ tar xjf ~/Data/Repository/linux-2.6.38.8.tar.bz2 Appliquer le patch Adeos sur Linux [~]$ xenomai/scripts/prepare-kernel.sh --linux=linux-2.6.38.8/ --ipipe=xenomai/ksrc/arch/arm/patches/adeos-ipipe-2.6.38.8-arm-1.18-08.patch --arch=arm patching file arch/arm/Kconfig patching file arch/arm/boot/compressed/head.S [...] Configurer et compiler Linux et ses modules [~]$ cd linux-2.6.38.8 [linux-2.6.38.8]$ wget https://www.blaess.fr/christophe/files/article-2012-07-09/config-linux-2.6.38.8-xenomai [...] [linux-2.6.38.8]$ mv config-linux-2.6.38.8-xenomai .config [linux-2.6.38.8]$ make ARCH=arm oldconfig [...] [linux-2.6.38.8]$ make ARCH=arm CROSS_COMPILE=~/cross-panda/usr/bin/arm-linux- uImage [...] Load Address: 80008000 Entry Point: 80008000 Image arch/arm/boot/uImage is ready [linux-2.6.38.8]$ make ARCH=arm CROSS_COMPILE=~/cross-panda/usr/bin/arm-linux- modules [...] IHEX2FW firmware/keyspan_pda/keyspan_pda.fw IHEX2FW firmware/keyspan_pda/xircom_pgs.fw [linux-2.6.38.8]$ Copier le noyau sur la partition de boot de la Pandaboard [linux-2.6.38.8]$ cp arch/arm/boot/uImage /media/Boot/ Copier les modules sur la partition racine de la Pandaboard [linux-2.6.38.8]$ make ARCH=arm INSTALL_MOD_PATH=/media/Root modules_install [...] INSTALL /media/Root/lib/firmware/keyspan_pda/keyspan_pda.fw INSTALL /media/Root/lib/firmware/keyspan_pda/xircom_pgs.fw DEPMOD 2.6.38.8-xenomai [linux-2.6.38.8]$ Compiler et installer les bibliothèques de Xenomai [linux-2.6.38.8]$ cd ../xenomai [xenomai]$ PATH=$PATH:~/cross-panda/usr/bin/ [xenomai]$ ./configure --prefix=/media/Root/usr/xenomai --host=arm-linux CFLAGS='-march=armv7-a' LDFLAGS='-march=armv7-a' --enable-smp [...] config.status: linking ./include/asm-generic to src/include/asm-generic/xenomai config.status: executing depfiles commands config.status: executing libtool commands [xenomai]$ make [...] [xenomai]$ make install (peut nécessiter les droits root)
Avant de démarrer notre Pandaboard sur Xenomai, il nous faut un outil de test des timers. Voici un programme, calqué sur celui que nous avons employé pour Linux et Linux-Rt, qui emploie l’API native de Xenomai.
fluctuations-timer-xenomai.c: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <rtdk.h> #include <native/task.h> #include <native/timer.h> static RTIME periode; static int nb_mesures = 0; // Nombre de mesures entre deux affichages void fonction_periodique (void * unused) { RTIME precedent = 0; RTIME heure = 0; RTIME duree; int mesure = 0; long long int min = -1; long long int max = 0; long long int max_max = 0; double sum = 0.0; periode = periode * 1000; // en ns rt_task_set_periodic(NULL, TM_NOW, periode); while(1) { rt_task_wait_period(NULL); heure = rt_timer_read(); if (mesure != 0) { duree = heure - precedent; duree = duree / 1000; // en microsecondes if ((min == -1) || (duree < min)) min = duree; if (duree > max) { max = duree; if (max_max < max) max_max = max; } sum += duree; } precedent = heure; mesure ++; if (mesure >= nb_mesures) { rt_fprintf(stdout, "[%ld] Min.= %lld, Moy.= %.1lf, Max.= %lld, Max.Max.= %lldn", (long int)(heure/1000000000), min, sum / nb_mesures, max, max_max); min = -1; max = 0; sum = 0.0; mesure = 0; rt_print_flush_buffers(); } } } int main (int argc, char * argv[]) { int cpu = 0; RT_TASK task; int err; mlockall(MCL_CURRENT|MCL_FUTURE); rt_print_auto_init(1); if ((argc < 2) || (sscanf(argv[1], "%lld", & periode) != 1) || ((argc == 3) && (sscanf(argv[2], "%d", & cpu) != 1))) { fprintf(stderr, "usage: %s periode_us [cpu]n", argv[0]); exit(EXIT_FAILURE); } if ((periode <= 0) || (periode > 2000000)) { fprintf(stderr, "%s: La periode doit etre dans [1, 2000000]n", argv[0]); exit(EXIT_FAILURE); } if ((cpu < 0) || (cpu >= sysconf(_SC_NPROCESSORS_ONLN))) { fprintf(stderr, "%s: Le CPU doit etre dans [0, %ld]n", argv[0], sysconf(_SC_NPROCESSORS_ONLN) - 1); exit(EXIT_FAILURE); } setvbuf(stdout, NULL, _IONBF, 0); nb_mesures = 5000000 / periode; if (nb_mesures == 0) { fprintf(stderr, "periode trop longuen"); exit(EXIT_FAILURE); } if ((err = rt_task_spawn(& task, "Fluctuation-RT-TIMER", 0, 99, T_JOINABLE | T_CPU(cpu), fonction_periodique, NULL)) != 0) { fprintf(stderr, "rt_task_spawn: %sn", strerror(-err)); exit(EXIT_FAILURE); } rt_task_join(& task); return EXIT_SUCCESS; }
On passe au programme deux arguments : la période du timer (en microsecondes) et le numéro du CPU sur lequel il doit s’exécuter. Pour compiler ce code, il nous faut un Makefile qui gère les options de compilation de Xenomai.
Makefile : .PHONY: all all: fluctuations-timer-xenomai XENOCONFIG?=/usr/xenomai/bin/xeno-config fluctuations-timer-xenomai:fluctuations-timer-xenomai.c $(shell $(XENOCONFIG) --cc) $(shell $(XENOCONFIG) --skin=native --cflags) $(shell $(XENOCONFIG) --skin=native --ldflags) -L $(shell $(XENOCONFIG) --skin=native --libdir) -o fluctuations-timer-xenomai fluctuations-timer-xenomai.c -lnative -lxenomai .PHONY: clean clean:: rm -f *.o .*.o .*.o.* *.ko .*.ko *.mod.* .*.mod.* .*.cmd *~ rm -f Module.symvers Module.markers modules.order rm -rf .tmp_versions rm -f fluctuations-timer-xenomai
Les paramètres de compilation seront fournis par le script xeno-config
qui se trouve dans le répertoire d’installation de Xenomai (sur la partition Root de la carte SD).
$ make XENOCONFIG=/media/Root/usr/xenomai/bin/xeno-config arm-linux-gcc -I/media/Root/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT -D__XENO__ -lnative -L/media/Root/usr/xenomai/lib -lxenomai -lpthread -lrt -L /media/Root/usr/xenomai/lib -o fluctuations-timer-xenomai fluctuations-timer-xenomai.c -lnative -lxenomai $ cp fluctuations-timer-xenomai /media/Root/usr/local/bin/ $
Enfin, pour lancer le programme en boucle, j’ai réutilisé le script mis au point précédemment, en remplaçant le nom du fichier de résultat
resultat-fluctuations-timer-linux-${COMPTEUR}.txt
en
resultat-fluctuations-timer-xenomai-${COMPTEUR}.txt
et l’invocation
chrt -f 99 /usr/local/bin/fluctuations-timer 100
par l’appel du programme ci-dessus ainsi
/usr/local/bin/fluctuations-timer-xenomai 100 0
Nous copions donc le script modifié dans le système de fichiers sur la carte SD.
$ wget https://www.blaess.fr/christophe/files/article-2012-07-09/lance-test-fluctuations-timer-xenomai.sh [...] $ cp lance-test-fluctuations-timer-xenomai.sh /media/Root/usr/local/bin/ $ umount /media/*oot $
Lancement du test
J’ai tout d’abord fait tourner le test sur le cœur 1, en modifiant dans le script le second argument sur la ligne invoquant le programme fluctuations-timer-xenomai
. Le système était soumis à une très forte charge en appels-système, en processus, et en interruptions externes. Nous avons vu dans l’article précédent que les traitements des interruptions étaient, par défaut, réalisés sur le cœur 0. Aussi notre programme s’exécutant sur le cœur 1 est légèrement préservé de leurs effets.
Le premier test s’est déroulé pendant une quinzaine d’heures (puis j’ai dû interrompre l’expérience car il me fallait débrancher l’alimentation). J’ai alors réalisé un graphique avec le même script que les expériences sous Linux et Linux-rt
Quelle surprise ! Alors qu’avec Linux vanilla et Linux-rt les fluctuations s’étendaient jusqu’à 6 millisecondes, les résultats sous Xenomai montrent des timers dont la pire variation ne dépasse pas 128 microsecondes au lieu de 100 microsecondes, soient 28 microsecondes de jitter. J’ai dû modifier le script de création du graphique en zoomant 20 fois l’axe des ordonnées.
On peut remarquer sur ce graphique des périodes nettes où les valeurs fluctuent dans des intervalles différents. Je suppose qu’il s’agit des moments où j’ajoutais des ping
flood supplémentaires depuis d’autres machines.
Encouragé par ces premiers résultats, j’ai relancé le test pendant deux jours, en le plaçant cette fois sur le cœur zéro, là où les interruptions sont traitées. Les variations sont légèrement plus importantes puisque l’on atteint un maximum de 151 microsecondes au lieu de 100 microsecondes. Voici les graphiques correspondants.
Conclusion
Ce test met en relief les performances de Xenomai, comparées à celles de Linux et Linux-rt. Les tâches temps réel de Xenomai s’exécutent avec une fiabilité beaucoup plus grande en ce qui concerne l’instant de déclenchement. Nous voyons que la fluctuation maximale obtenue sur une Pandaboard avec un timer Xenomai est de 51 microsecondes (j’ai prolongé encore l’expérience depuis, et obtenu la même limite maximale). Ceci est cohérent avec les résultats fournis par l’outil latency
livré avec Xenomai, qui nous indique ici une latence maximale de 51.579 microsecondes sur un test à haute charge de 6 heures.
[Panda]# export LD_LIBRARY_PATH=/usr/xenomai/lib [Panda]# /usr/xenomai/bin/latency -p 100 -T 21700 == Sampling period: 100 us == Test mode: periodic user-mode task == All results in microseconds warming up... [...] RTD| 3.507| 7.674| 27.321| 0| 0| 2.908| 51.579 RTD| 3.517| 7.724| 30.472| 0| 0| 2.908| 51.579 ---|-----------|-----------|-----------|--------|------|------------------------- RTS| 2.908| 7.797| 51.579| 0| 0| 06:00:00/06:00:00 [Panda]#
Pour en savoir plus:
- L’archive contenant les fichiers des résultats.
- Mon nouveau livre « Solutions temps réel sous Linux«
- Sessions de formation « Temps réel Linux et Xenomai » que j’anime chez Logilin.
Christopher,
Thank you very much for your well-written, comprehensive articles! I am a complete beginner in what concerns both hardware and real-time and currently experimenting with my Raspberry Pi 2. And now I have finally understood what ‘latency’ does after wrapping my head around it yesterday and today. Your articles make my task so much easier and pleasurable, so, again, thank you!
Corneliu.