Essai anticipé du temps réel de Linux 6.12

Publié par cpb
Oct 07 2024

La future branche 6.12 du noyau Linux, qui sera publiée à la fin du mois de novembre, contiendra plusieurs nouveautés par rapport au noyau actuel. La plus commentée depuis deux semaines concerne l’intégration complète du patch PREEMPT_RT dans le noyau. Annoncée lors du Maintainer Summit du 17 septembre dernier, cette intégration se manifeste par un patch sur la fonction printk() qui représentait le dernier point de blocage.

Il n’y aura donc plus besoin de patch pour bénéficier de la préemptibilité totale du noyau sur les trois architectures principales pour le temps réel : x86, riscv et aarch64 (ARM 64 bits). Il faudra néanmoins toujours appliquer un patch (du moins pendant quelques temps) pour l’architecture ARM 32 bits par exemple.

Comment tester cette nouveauté ? C’est très simple : je vous propose de faire un build rapide pour une machine virtuelle Risc-V 64 bits en utilisant Buildroot et la version release candidate 6.12-rc2 du kernel, disponible depuis quelques heures.

Compilation d’une image avec le kernel 6.12

Nous téléchargeons et extrayons l’archive de Buildroot (la dernière version stable à ce jour) :

$ wget https://www.buildroot.org/downloads/buildroot-2024.02.6.tar.xz
$ tar xf buildroot-2024.02.6.tar.xz
$ cd buildroot-2024.02.6

Nous préparons un build pour une machine virtuelle Risc-V 64 bits (dans la première commande l’option -O est un « O majuscule » pas un zéro) :

$ make  O=../build-riscv64  qemu_riscv64_virt_defconfig
   [...]
$ cd  ../build-riscv64
$ make  menuconfig

Nous voici devant le menu de configuration de Buildroot.

Nous faisons deux modifications dans la configuration par défaut :

  • menu Toolchain, option Toolchain type, on sélectionne External toolchain : ceci va accélérer très sensiblement notre build,
  • menu Kernel, dans la troisième ligne (Kernel version) on inscrit le numéro 6.12-rc2

Faisons un premier build avec les options par défaut du noyau :

$ make

Essai du noyau standard

Une fois la compilation terminée, nous lançons l’émulateur Qemu pour tester l’image produite :

$ ./images/start-qemu.sh 

L’image virtuelle démarre, et une ligne de login nous permet de nous connecter :

OpenSBI v1.2
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : riscv-virtio,qemu
Platform Features         : medeleg
Platform HART Count       : 1
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 10000000Hz
Platform Console Device   : uart8250
Platform HSM Device       : ---
Platform PMU Device       : ---
Platform Reboot Device    : sifive_test
Platform Shutdown Device  : sifive_test
Firmware Base             : 0x80000000
Firmware Size             : 252 KB
Runtime SBI Version       : 1.0

 [...]

[    0.349051] ALSA device list:
[    0.349163]   No soundcards found.
[    0.362716] EXT4-fs (vda): mounting ext2 file system using the ext4 subsystem
[    0.369613] EXT4-fs (vda): mounted filesystem ce6ccc3f-186a-416c-8df7-30c7aecdfe27 ro without journal. Quota mode: disabled.
[    0.369979] VFS: Mounted root (ext2 filesystem) readonly on device 254:0.
[    0.372643] devtmpfs: mounted
[    0.400024] Freeing unused kernel image (initmem) memory: 2280K
[    0.400449] Run /sbin/init as init process
[    0.513732] EXT4-fs (vda): re-mounted ce6ccc3f-186a-416c-8df7-30c7aecdfe27 r/w. Quota mode: disabled.
Saving 256 bits of creditable seed for next boot
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: udhcpc: started, v1.36.1
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
deleting routers
adding dns 10.0.2.3
OK

Welcome to Buildroot
buildroot login: root

Une fois connectés, nous pouvons vérifier la version du kernel et ses options principales avec

# uname -a
Linux buildroot 6.12.0-rc2 #1 SMP Sun Oct  7 05:55:21 CEST 2024 riscv64 GNU/Linux

Nous pouvons aussi examiner la liste des tâches présentes :

# ps
PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [pool_workqueue_]
    4 root     [kworker/R-rcu_g]
    5 root     [kworker/R-sync_]
    6 root     [kworker/R-slub_]
    7 root     [kworker/R-netns]
    8 root     [kworker/0:0-eve]
    9 root     [kworker/0:0H-ev]
   10 root     [kworker/0:1-eve]
   11 root     [kworker/u4:0-ev]
   12 root     [kworker/R-mm_pe]
   13 root     [rcu_tasks_trace]
   14 root     [ksoftirqd/0]
   15 root     [rcu_sched]
   16 root     [rcu_exp_par_gp_]
   17 root     [rcu_exp_gp_kthr]
   18 root     [migration/0]
   19 root     [cpuhp/0]
   20 root     [kdevtmpfs]
   21 root     [kworker/R-inet_]
   22 root     [kworker/u4:1-ev]
   23 root     [kauditd]
   24 root     [khungtaskd]
   25 root     [oom_reaper]
   26 root     [kworker/R-write]
   27 root     [kcompactd0]
   28 root     [kworker/R-kbloc]
   29 root     [kworker/R-blkcg]
   30 root     [kworker/R-ata_s]
   31 root     [kworker/R-devfr]
   32 root     [watchdogd]
   33 root     [kworker/R-rpcio]
   34 root     [kworker/0:1H-kb]
   35 root     [kworker/R-xprti]
   36 root     [kswapd0]
   37 root     [kworker/R-nfsio]
   38 root     [kworker/R-kthro]
   40 root     [kworker/R-uas]
   41 root     [kworker/R-mld]
   42 root     [kworker/R-ipv6_]
   43 root     [kworker/R-ext4-]
   62 root     /sbin/syslogd -n
   66 root     /sbin/klogd -n
  106 root     udhcpc -t1 -A3 -b -R -O search -O staticroutes -p /var/run/udhcp
  108 root     -sh
  109 root     [kworker/u4:2]
  110 root     [kworker/0:2]
  113 root     ps

Essai du noyau temps réel

Nous quittons l’émulateur (avec les touches CTRL-A X) et nous allons à présent activer l’option PREEMPT_RT du noyau. Pour cela nous appelons le menu de configuration du kernel :

$ make linux-menuconfig

Un nouveau menu s’ouvre, qui propose les options spécifiques au noyau :

Nous entrons dans le premier menu General setup et modifions le sous-menu Preemption Model pour sélectionner Fully Preemptible Kernel (Real-Time).

Suivant les architectures, il peut être nécessaire d’activer d’abord l’option Configure standard kernel features (expert users) située un peu plus bas dans le même menu General setup pour que l’option Fully Preemptible Kernel (Real-Time) apparaisse.

Nous pouvons relancer la compilation :

$ make

Puis relancer l’émulateur qui démarre comme précédemment :

OpenSBI v1.2
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : riscv-virtio,qemu
Platform Features         : medeleg
Platform HART Count       : 1
 [...]
[    0.600687] VFS: Mounted root (ext2 filesystem) readonly on device 254:0.
[    0.602597] devtmpfs: mounted
[    0.630470] Freeing unused kernel image (initmem) memory: 2284K
[    0.630809] Run /sbin/init as init process
[    0.756784] EXT4-fs (vda): warning: mounting unchecked fs, running e2fsck is recommended
[    0.764133] EXT4-fs (vda): re-mounted dc00b5c2-5b9d-4344-a4ff-cf1359ce6268 r/w. Quota mode: disabled.
Seeding 256 bits and crediting
Saving 256 bits of creditable seed for next boot
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: udhcpc: started, v1.36.1
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
deleting routers
adding dns 10.0.2.3
OK

Welcome to Buildroot
buildroot login: root
# uname -a
Linux buildroot 6.12.0-rc2 #2 SMP PREEMPT_RT Sun Oct  7 06:27:48 CEST 2024 riscv64 GNU/Linux

Nous voyons que l’option PREEMPT_RT est bien activée dans le noyau. Cette option garantit que le temps de réveil d’une tâche temps réel lors de l’arrivée d’une interruption qu’elle attend sera beaucoup plus constant qu’avec un noyau standard. C’est un premier point très important pour améliorer la qualité du temps réel de Linux.

Vérifions à présent la liste des tâches :

# ps
PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [pool_workqueue_]
    4 root     [kworker/R-rcu_g]
    5 root     [kworker/R-sync_]
    6 root     [kworker/R-slub_]
    7 root     [kworker/R-netns]
    8 root     [kworker/0:0-eve]
    9 root     [kworker/0:1-eve]
   10 root     [kworker/0:0H-ev]
   11 root     [kworker/u4:0-ev]
   12 root     [kworker/R-mm_pe]
   13 root     [rcu_tasks_kthre]
   14 root     [rcu_tasks_trace]
   15 root     [ksoftirqd/0]
   16 root     [pr/legacy]
   17 root     [rcu_preempt]
   18 root     [rcub/0]
   19 root     [rcu_exp_par_gp_]
   20 root     [rcuc/0]
   21 root     [rcu_exp_gp_kthr]
   22 root     [migration/0]
   23 root     [irq_work/0]
   24 root     [cpuhp/0]
   25 root     [kdevtmpfs]
   26 root     [kworker/R-inet_]
   27 root     [kworker/u4:1-ev]
   28 root     [kauditd]
   29 root     [khungtaskd]
   30 root     [oom_reaper]
   31 root     [kworker/R-write]
   32 root     [kcompactd0]
   33 root     [kworker/R-kbloc]
   34 root     [kworker/R-blkcg]
   35 root     [kworker/R-ata_s]
   36 root     [kworker/R-devfr]
   37 root     [backlog_napi/0]
   38 root     [watchdogd]
   39 root     [kworker/0:1H-kb]
   40 root     [kworker/R-rpcio]
   41 root     [kworker/R-xprti]
   42 root     [kswapd0]
   43 root     [kworker/R-nfsio]
   44 root     [kworker/R-kthro]
   46 root     [irq/13-virtio0]
   47 root     [irq/14-virtio1]
   48 root     [kworker/R-uas]
   49 root     [irq/15-101000.r]
   50 root     [kworker/R-mld]
   51 root     [kworker/R-ipv6_]
   52 root     [irq/12-ttyS0]
   53 root     [kworker/R-ext4-]
   72 root     /sbin/syslogd -n
   76 root     /sbin/klogd -n
   98 root     [kworker/0:2]
  117 root     udhcpc -t1 -A3 -b -R -O search -O staticroutes -p /var/run/udhcp
  119 root     -sh
  121 root     [kworker/u4:2-ev]
  123 root     ps

Par rapport à la première liste, nous observons la présence de lignes [irq/...].

Il s’agit de threads du kernel chargés de prendre en charge la partie non-urgente d’un gestionnaire d’interruption. Cela évite de suspendre les tâches applicatives temps réel pendant une durée prolongée lorsqu’une interruption sans urgence (réseau, clavier, etc.) se présente. C’est le second point crucial pour la qualité du temps réel de Linux.

Conclusion

Nous voyons, avec cette petite expérience rapide, que l’option CONFIG_PREEMPT_RT est effectivement disponible dans le noyau Linux 6.12 sans ajout de patch supplémentaire (du moins pour les architectures X86, Risc-V et ARM 64 bits). Cela permet une mise en oeuvre plus simple des fonctionnalités temps réel proposée par Linux.

Bien sûr pour vérifier véritablement le comportement temps réel du système, il faudrait utiliser des outils de test comme cyclictest et hackbench par exemple, mais cela ne présenterait pas d’intérêt sur une machine virtuelle, il faudra refaire ce test sur une vraie carte lors de la sortie du noyau finalisé.

Pour en savoir plus sur les apports du projet PREEMPT_RT déjà intégrés dans le noyau depuis une vingtaine d’années, je vous conseille la conférence de Steven Rostedt lors des Kernel Recipes 2024 :

Pour en savoir plus et mettre en pratique le temps réel de Linux, n’hésitez à participer à une session de formation « Temps réel sous Linux » que j’anime chez Logilin.

Une réponse

  1. lym dit :

    Bonjour,
    Peut-être que cette intégration permettra un usage plus large… et d’éviter de tomber dans des bugs tordus qui peuvent se situer à la frontière du matériel et du logiciel, liés à un cas d’usage RT peu courant donc testé.
    J’ai en particulier en mémoire un problème de stockage eUSB qui n’appréciait pas vraiment la possibilité que l’usb-storage du kernel puisse se retrouver, avec un kernel patché, préempté par notre applicatif temps réel ce qui n’est pas possible avec un noyau vanilla: Quand cela tombait pile entre les phases commande et donnée et durait au delà de qq centaines de ms, cette référence d’eUSB avait un firmware qui trouvait visiblement ce délai anormal et provoquait un usb-reset, qui se voyait alors dans les logs (la cause précise, un peu moins, surtout que cela restait un pb rare même en stressant le RT côté applicatif). Tous les montages courants perdus, c’était reset de la carte.

URL de trackback pour cette page