Linux Embedded

Le blog des technologies libres et embarquées

Linux temps réel avec Yocto

1. Préambule

Le but n'est pas ici d'introduire le projet Yocto qui a déjà fait l'objet de nombreuses publications que ce soit dans ce blog ou plus généralement dans la presse spécialisée. La lecture de l'article nécessite donc la connaissance des concepts de base du projet Yocto, en particulier l'utilisation de BitBake, la notion de recette et de layer (couche). Pour en savoir plus, le lecteur pourra se référer à quelques entrées de la bibliographie en fin d'article.

2. Linux et temps réel

De nouveau, la notion de Linux temps réel a été abordée plusieurs fois dans ces colonnes. En résumé nous pouvons dire qu'il existe deux techniques permettant de rendre un noyau Linux préemptif :

  • appliquer le patch PREEMPT_RT qui, depuis octobre 2015, est un projet officiel de la fondation Linux
  • utiliser le projet Xenomai, utilisant une technique de "co-noyau" (double noyau) dérivé du projet RTLinux de la fin des années 90

L'utilisation du temps réel est assez rare dans le cas d'une distribution classique (Debian, Ubuntu, Fedora, etc.), à l'exception d'Ubuntu Studio qui peut utiliser de manière native un noyau PREEMPT_RT. L'intégration d'un support temps réel passe donc par la compilation d'un noyau spécial (pour PREEMPT_RT et Xenomai) ainsi que la mise en place de bibliothèques dédiées dans le cas de Xenomai. La mise en place à la main peut être fastidieuse (surtout si l'on doit en plus prendre en compte la compilation croisée) et des outils comme Buildroot ou Yocto peuvent simplifier la tâche de manière significative.

Concernant Buildroot, le support Xenomai est déjà intégré dans le menu Kernel >  Linux Kernel Extensions. Dans le cas de Yocto, seul le support PREEMPT_RT est disponible. Dans la suite de l'article, nous verrons comment l'utiliser ainsi que la mise en place d'un nouveau support pour Xenomai.

3. Yocto et PREEMPT_RT

Comme nous l'avons dit le projet Yocto maintient une version du noyau intégrant PREEMPT_RT et correspondant à la recette de noyau linux-yocto-rt (et non linux-yocto). Par contre ce noyau est utilisable uniquement sur les cibles QEMU prises en compte par Yocto, ce qui est assez étonnant vu qu’il paraît difficile de respecter des échéances temporelles dans un émulateur purement logiciel !

$ grep COMPATIBLE_MACHINE meta/recipes-kernel/linux/linux-yocto-rt_4.9.bb
 COMPATIBLE_MACHINE = "(qemux86|qemux86-64|qemuarm|qemuppc|qemumips)"

D’autres cibles pourraient fonctionner sous réserve d'une adaptation de la recette, cependant dans la plupart des cas l’adaptation de la recette du noyau Linux en appliquant le patch PREEMPT_RT suffit largement. Yocto fournit également une recette d’image core-image-rt utilisant le noyau temps réel. Outre le fait de forcer l’utilisation de ce noyau, l’image inclut simplement deux recettes dédiées au temps réel dont  rt-tests qui contient des outils de mesures comme cyclictest ou hackbench .

$ cat meta/recipes-rt/images/core-image-rt.bb
require recipes-core/images/core-image-minimal.bb
...
DESCRIPTION = "A small image just capable of allowing a device to boot plus a \
 real-time test suite and tools appropriate for real-time use."

DEPENDS = "linux-yocto-rt"

IMAGE_INSTALL += "rt-tests hwlatdetect"

L'application du patch PREEMPT_RT est cependant relativement simple à mettre en place si l'on utilise le principe de l'extension de recette grâce à un fichier .bbappend pour la recette du noyau. La première ligne indique que les données du répertoire files/ seront prises en compte dans la recette initiale (.bb). La deuxième décrit le chemin d'accès aux deux fichiers ajoutés, soit le patch PREEMPT_RT et le nouveau fichier de configuration du noyau (defconfig). Lors de la production du noyau, le patch PREEMPT_RT sera appliqué automatiquement et l'on utilisera le nouveau fichier de configuration.

FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI += "file://patch-4.4.50-rt63.patch file://defconfig"

Le test du noyau intégrant le patch PREEMPT_RT démontre un comportement "temps réel" car la variation du temps de réponse est inférieure à 90 µs, bien moindre que dans le cas d'un noyau standard.

root@raspberrypi3:~# cyclictest -p 99 -t 5 -n -q &                              
root@raspberrypi3:~# hackbench -p -g 20 -l 1000                                 
Running in process mode with 20 groups using 40 file descriptors each (== 800 tasks)                                                                            
Each sender will pass 1000 messages of 100 bytes                                
T: 0 (  418) P:99 I:1000 C:  37808 Min:     13 Act:   17 Avg:   22 Max:      57
T: 1 (  419) P:99 I:1500 C:  25205 Min:     13 Act:   14 Avg:   21 Max:      75
T: 2 (  420) P:99 I:2000 C:  18904 Min:     13 Act:   17 Avg:   20 Max:      46
T: 3 (  421) P:99 I:2500 C:  15123 Min:     13 Act:   16 Avg:   21 Max:      88
T: 4 (  422) P:99 I:3000 C:  12603 Min:     13 Act:   17 Avg:   20 Max:      53

4. Ajout du support Xenomai

L'utilisation de Xenomai est plus complexe car outre un patch à appliquer au noyau il est nécessaire de compiler des bibliothèques (en espace utilisateur). Le plus simple est de mettre en place un nouveau layer (soit meta-xenomai) qui contiendra les recettes nécessaires à la mise en place des deux étapes.

La première étape ne se limite pas à l’application d’un simple patch (comme dans le cas de PREEMPT_RT). En effet Xenomai fournit le script prepare-kernel.sh que l’on utilise comme décrit ci-dessous à partir du répertoire des sources de Xenomai.

$ ./scripts/prepare-kernel.sh --help 
usage: prepare-kernel --linux=<linux-tree> --ipipe=<ipipe-patch> [--arch=<arch>] [--outpatch=<file> [--filterkvers=y|n] [--filterarch=y|n]] [--forcelink] [--default] [--verbose]

Les principales options à utiliser sont le chemin d’accès aux sources du noyau à utiliser (--linux), le chemin d’accès au patch (--ipipe) et enfin l’architecture de la cible (--arch). Au niveau de Yocto cette action s’effectue dans la recette du noyau en définissant une nouvelle fonction do_prepare_kernel(). Nous présentons ci-dessous un extrait de la recette linux-xenomai-rpi3_4.9.bb .

...
SRC_URI = "git://github.com/raspberrypi/linux.git;protocol=git;branch=rpi-4.9.y"
SRC_URI += "file://ipipe-core-4.9.45-arm-custom.patch;apply=0"
SRC_URI += "file://defconfig"
...

do_prepare_kernel () {
  # Set linux kernel source directory
  linux_src="${S}"

  # Set xenomai source directory 
  xenomai_src="${WORKDIR}/xenomai-3.0.5"

  # Set ipipe patch (adapted for Pi 3)
  ipipe_patch="${WORKDIR}/ipipe-core-4.9.45-arm-custom.patch"

  # Prepare kernel
  ${xenomai_src}/scripts/prepare-kernel.sh --arch=arm --linux=${linux_src} --ipipe=${ipipe_patch} --default
}

addtask prepare_kernel after do_patch before do_configure

On remarque l’utilisation de la directive addtask permettant d’indiquer à quel moment exécuter la fonction puisque celle-ci n’est pas définie dans Yocto.

La recette de la partie espace utilisateur est simple à mettre en place car Xenomai utilise Autotools et pkg-config ce qui permet d’utiliser les classes Yocto correspondantes. Nous citons ci-dessous un bref extrait de la recette xenomai_3.0.5.bb . L'option --with-core=cobalt force l'utilisation du double noyau (Cobalt) car la version 3 de Xenomai permet également d'utiliser PREEMPT_RT comme noyau temps réel (Mercury).

SRC_URI = "http://xenomai.org/downloads/xenomai/stable/xenomai-3.0.5.tar.bz2"

S = "${WORKDIR}/xenomai-${PV}"

inherit autotools pkgconfig

includedir = "/usr/include/xenomai"

SRC_URI[md5sum] = "c309036358fd403e9894fbbf53be91a1"

EXTRA_OECONF += "--enable-smp --with-core=cobalt"

La fin de la recette permet de résoudre quelques problèmes de QA (Quality Assurance) liés à Yocto.

#Fixes QA Issues: non debug package contains .debug directory
FILES_${PN}-dbg += "/usr/bin/regression/posix/.debug"
...

 

Le test d'une image intégrant le support Xenomai s'effectue en ajoutant tout d'abord le nouveau layer à l'environnement de compilation.

$ bitbake-layers add-layer <path>/meta-xenomai

On peut ensuite modifier le fichier conf/local.conf afin d’ajouter les recettes et la configuration requises pour l’utilisation de Xenomai.

PREFERRED_PROVIDER_virtual/kernel = "linux-xenomai-rpi3" 
IMAGE_INSTALL_append = " xenomai rt-tests"

La première ligne indique que nous utiliserons le noyau spécial modifié pour Xenomai au lieu du noyau par défaut. La deuxième ligne indique la liste des recettes à ajouter à l’image, soit xenomai correspondant à la partie espace utilisateur de Xenomai et la recette rt-tests.

Il suffit alors de créer l'image:

$ bitbake core-image-minimal

Après installation de l’image, un test rapide basé sur latency et hackbench indique que Xenomai fonctionne correctement sur la cible (jitter d’environ 25 µs avec charge).

root@raspberrypi3:~# latency & 
root@raspberrypi3:~# hackbench -p -g 20 -l 1000
Running in process mode with 20 groups using 40 file descriptors each (== 800 tasks)
... 
Each sender will pass 1000 messages of 100 bytes 
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|      1.091|      7.918|     24.685|       0|     0|      0.624|     24.685 
RTD|      2.029|      4.630|     12.810|       0|     0|      0.624|     24.685 
RTD|      2.236|      4.966|     14.893|       0|     0|      0.624|     24.685 
RTD|      2.236|      5.223|     11.924|       0|     0|      0.624|     24.685 
RTD|      2.288|      5.589|     15.881|       0|     0|      0.624|     24.685 
RTD|      2.391|      5.216|     14.944|       0|     0|      0.624|     24.685 
RTD|      2.183|      5.208|     15.724|       0|     0|      0.624|     24.685 
...

4. Bibliographie et références

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.