Bei Einsatz von CONFIG_PREEMPT_VOLUNTARY lässt sich Kernel-Code an definierten Stellen unterbrechen (might_sleep()), an denen der Scheduler zusätzlich aktiv werden kann. So erfolgt die Reaktion auf Ereignisse etwas schneller. Diese Anpassung ist für einen normalen Desktop-Rechner vorgesehen.
Verwenden Sie CONFIG_PREEMPT, lassen sich die meisten Stellen im Kernel-Code unterbrechen. Beim Auftreten eines Ereignisses (Interrupts) kann der Scheduler direkt aktiv werden und muss nicht erst auf das Ende einer gerade aktiven Kernel-Codesequenz (zum Beispiel eines gerade aktiven Systemaufrufs) warten. Wer auf seinem Desktop schnelle Reaktionen wünscht, nutzt diese Einstellung.
Mit CONFIG_PREEMPT_RT schließlich lässt sich jeglicher Kernel-Code unterbrechen, und typischerweise nicht schlafende Spinlocks können plötzlich schlafen. Interrupt-Service-Routinen sind als Threaded Interrupts realisiert und damit priorisiert. Diese Konfiguration kommt bei Realzeitsystemen mit harten Zeitanforderungen zum Einsatz.
In unserem Fall setzen Sie das Preemption-Modell (Abbildung 3) auf Real-Time (Abbildung 4). Beim Verlassen des Konfigurationsprogramms werden die Änderungen abgespeichert.
Listing 1
Cross-Generierung eines PREEMPT_RT-Kernels
### Installation der notwendigen Werkzeuge $ sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev ### Installation Cross-Compiler $ sudo apt install crossbuild-essential-armhf $ mkdir ~/preempt-rt-kernel $ cd preempt-rt-kernel ### Quellcode herunterladen $ git clone --depth=1 https://github.com/raspberrypi/linux $ cd linux ### Patch herunterladen -- ACHTUNG: Auf die richtige Version achten! $ wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.15/patch-5.15.44-rt46.patch.gz ### Kernel patchen $ patch patch-5.15.44-rt46.patch.gz $ patch -p1 <patch-5.15.44-rt46.patch ### Grundkonfiguration für Raspberry Pi 4 $ KERNEL=kernel7l $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig ### Aktivierung des PREEMPT_RT-Patches $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig ### General Setup | Configure standard kernel features (expert users) -> ### General Setup | Preemption Model (Fully Preemptible Kernel (Real-Time)) -> ### exit -> exit -> yes ### Cross-Generierung von Kernel, Modulen und Devicetree $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j 4 zImage modules dtbs
Kurze Weile
Mit der Generierung des Kernels, der Module und des Devicetrees ist eine Host-Maschine durchaus einmal ein gutes Stündchen beschäftigt. Die Installation des fertig generierten Kernels veranschaulicht Listing 2. Dazu stecken Sie die SD-Karte mit dem darauf bereits installierten Pi OS in den Rechner. Per Lsblk identifizieren Sie die Gerätedateien, über die Sie auf die beiden Partitionen der SD-Karte zugreifen. Anders als in der Anleitung [2] angegeben, waren das bei uns im Test beispielsweise /dev/mmcblk0p1 und /dev/mmcblk0p2.
Möglicherweise hat Ihr Linux-System die Partitionen auf der SD-Karte automatisch gemountet. Das erkennen Sie an der Angabe eines Verzeichnisses wie /media/quade/boot/ auf der rechten Seite der Ausgabe des Kommandos lsblk. In diesem Fall können Sie entweder diese Verzeichnisse für die Installation verwenden oder hängen die Partitionen aus und dann wie in Listing 2 wieder ein.
Legen Sie dazu zwei Verzeichnisse an, auf die Sie die beiden Partitionen mounten. Installieren Sie schließlich die Kernel-Module, die Devicetree-Overlays und den Haupt-Devicetree. Bevor Sie dann den Realzeit-Kernel Marke Eigenbau installieren, sollten Sie ein Backup des aktuellen Kernels erstellen. Nun gilt es, die beiden Partitionen auszuhängen. Die SD-Karte stecken Sie zurück in den Raspberry Pi und versorgen diesen mit Strom, woraufhin der Mini-Rechner hochfährt.
Listing 2
PREEMPT_RT-Kernel auf SD-Karte installieren
cd ~/preempt-rt-kernel lsblk ### Gerätedatei evaluieren. Sind die Partitionen der SD-Karte eingehängt, ### werden sie mit den zwei nachfolgenden Kommandos wieder ausgehängt: $ sudo umount /dev/mmcblk0p1 $ sudo umount /dev/mmcblk0p2 ### Partitionen einhängen $ mkdir mnt $ mkdir mnt/fat32 $ mkdir mnt/ext4 $ sudo mount /dev/mmcblk0p1 mnt/fat32 $ sudo mount /dev/mmcblk0p2 mnt/ext4 ### Kernel-Module installieren cd linux $ KERNEL=kernel7l $ sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install ### Kernel und Devicetree installieren $ cd ~/preempt-rt-kernel $ sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img $ sudo cp linux/arch/arm/boot/zImage mnt/fat32/$KERNEL.img $ sudo cp linux/arch/arm/boot/dts/*.dtb mnt/fat32/ $ sudo cp linux/arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/ $ sudo cp linux/arch/arm/boot/dts/overlays/README mnt/fat32/overlays/ $ sudo umount mnt/fat32 $ sudo umount mnt/ext4 $ sync
Sein oder nicht sein
Nach dem Booten und Einloggen lässt sich anhand zweier Kriterien feststellen, ob der PREEMPT_RT-Patch wirkt. Ein auf der Konsole eingegebenes uname -a sollte PREEMPT_RT ausweisen. Außerdem muss die Datei /sys/kernelrealtime existieren und eine 1 enthalten (Abbildung 5).
Um den eigentlichen Effekt des Patches zu testen, empfiehlt es sich, die Test-Suite rt-tests zu installieren. Das Paket gelangt per git clone auf den RasPi (Listing 3) und lässt sich nach dem Wechsel in das neue Verzeichnis rt-tests/ per Make ruckzuck generieren. Aus dem Reigen der jetzt zur Verfügung stehenden Testprogramme wählen Sie für den ersten Test cyclictest und hackbench aus. Ersteres führt Messungen zur Latenzzeit durch, Letzteres bringt den RasPi gehörig ins Schwitzen und provoziert damit Worst-Case-Situationen.
Listing 3
Testprogramme installieren
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/clrkwllms/rt-tests.git $ cd rt-tests $ make
Um die Latenzzeit zu bestimmen, legt sich Cyclictest [6] per clock_nanosleep() für eine definierte Zeit schlafen. Sobald Sie die Task aufwecken, liest es die aktuelle Zeit und berechnet durch Differenzbildung zur erwarteten Weckzeit die Abweichung und damit die Latenz. Das Ganze wird in einer Schleife wiederholt ausgeführt und statistisch ausgewertet.
Cyclictest gibt die minimale Latenz, die durchschnittliche und vor allem die bei den Durchläufen aufgetretene maximale Latenz in Mikrosekunden aus. Aber Achtung: Tritt während der Messung keine hohe Latenz auf, bedeutet das nicht, dass es sie nicht geben kann. Je länger allerdings die Messung dauert und je unterschiedlicher dabei die Lastsituationen für den RasPi ausfallen, desto höher ist die Wahrscheinlichkeit, den Worst Case erwischt zu haben. Für eine erste Bewertung des PREEMPT_RT-Patches genügt das Ergebnis jedoch.








