Dank SSDs starten aktuelle Systeme so schnell, dass keine Zeit für eine Kaffeepause bleibt. Aber es geht noch schneller: Wir kitzeln das letzte Quäntchen aus Bootloader und Kernel heraus.
Trotz immer schnellerer Prozessoren, RAM-Module und Speichermedien brauchen moderne Linux-Systeme immer noch einige Sekunden bis zum Anzeigen des grafischen Logins. Solid-State-Disks und Systemd brachten deutliche Verbesserungen, aber es dauert nach dem Drücken des Einschaltknopfs immer noch mehr als einen Augenblick, bis der Anmeldebildschirm erscheint. Das von Systemd mitgelieferte Werkzeug Systemd-analyze gibt einen ersten Eindruck davon, wo die Zeit bleibt.
Wie immer ist hier Vorsicht geboten, und Sie als Admin sollten die von Systemd-analyze gelieferten Zeiten auf Plausibilität prüfen und ihnen nicht blind vertrauen. Laut der Messung aus Listing 1 beansprucht bei unserem Testrechner die UEFI-Firmware gut drei Sekunden, der Bootloader Grub schluckt weitere zehn. Mit langsamer Firmware, die manchmal über zehn Sekunden braucht, und einem Bootloader wie Grub kommen oft fast zwanzig Sekunden zusammen. Daher schicken viele Nutzer den Rechner lieber nur in den Standby, um sich diese Wartezeiten zu sparen. Es lohnt sich also, vor allem Bootloader und Kernel an den Kragen zu gehen, um die ersten Sekunden einzusparen.
Listing 1
Startzeit analysieren
$ systemd-analyze time
Startup finished in 3.393s (firmware) + 10.554s (loader) + 2.123s (kernel) + 4.789s (userspace) = 20.860s
graphical.target reached after 4.778s in userspace
Testaufbau
Als Testsystem kommt ein vier Jahre alter Tuxedo BU1406 mit einer “Kaby-Lake”-CPU Intel i7-7500U, 32 GByte DDR4 RAM und einer 512 GByte großen NVMe-SSD zum Einsatz, ein System, das seinerzeit rund 1000 Euro kostete. Ausgangspunkt ist ein über den Debian-Installer aufgesetztes Debian “Bullseye” (“Testing”) vom 19. November 2020 mit Kernel 5.9.9 und Systemd 246.6. Als Oberfläche dient das Standardsystem mit Gnome 3.38.1, GDM 3.38.2 und einem OpenSSH-Server. Im Fokus stehen vor allem Systeme mit UEFI-Firmware, die mittlerweile auf aktueller Hardware am meisten verbreitet ist.
Das Ziel ist es, die Startzeit zu minimieren, wobei als Grundlage die Messwerte für firmware, loader und kernel in der Ausgabe von Systemd-analyze fungieren. Ältere Systeme mit deutlich längerer Standardstartzeit bieten wahrscheinlich deutlich mehr Potenzial, die Boot-Geschwindigkeit zu verbessern.
Einstieg
Bei der Firmware (siehe Kasten “Eingebaut”) lässt sich in der Regel wenig optimieren, da diese oft proprietär ist und sie nur der Gerätehersteller verändert und verteilen kann. Danach startet die UEFI-Firmware den unter Debian standardmäßig installierten Bootloader Grub. Andere Distributionen nutzen Systemd-boot. Die Datei liegt in einem speziellen Format auf der EFI-Systempartition (ESP), das den Start über die Firmware ermöglicht.
Eingebaut
Auf x86-Systemen ist mittlerweile UEFI-Firmware weitverbreitet und hat das sogenannte BIOS abgelöst. Oft findet man beide Begriffe synonym im Einsatz. Der Startbildschirm zeigt meistens die Taste zum Aufrufen der Firmware-Einstellungen an. In diesem oft grafischen Menü sehen Sie, ob sich bremsende Funktionen wie Netzwerk-Boot ausschalten lassen oder ob es eine Option zum schnelleren Start gibt, etwa Quick Boot oder Fast Boot.
Neben den fehlenden Quellen – und somit Freiheiten – ist die Größe der UEFI-Firmware ein Hauptkritikpunkt. Im Prinzip handelt es sich um ein eigenes Betriebssystem mit Treibern für Dateisysteme, Grafik und Netzwerk, das eine große Angriffsfläche bietet und eventuell auch Fehler aufweist.
Als Alternative käme für x86-Systeme Coreboot infrage, für ARM-Systeme U-Boot und Coreboot. Das Ziel von Coreboot besteht unter anderem darin, nur so viel Hardware zu initialisieren, um das Betriebssystem zu starten. Es kommt unter anderem in Chromebooks von Google und auf Geräten von Herstellern wie System76 und Purism zum Einsatz. Der minimale Ansatz führt zu Startzeiten der Firmware von unter einer Sekunde, bei manchen Geräten sogar nur 500 Millisekunden.
Grub selbst geht ansatzweise selbst als Betriebssystem durch: Es bringt eigene Treiber und eine Kommandozeile mit und stellt ein Menü zum Auswählen und Start des Linux-Kernels oder anderer Systeme bereit. Standardmäßig gibt Grub dem Anwender fünf Sekunden Zeit, um den automatischen Startvorgang zu unterbrechen.
Über die Variable GRUB_TIMEOUT=1 in /etc/default/grub reduzieren Sie das auf eine Sekunde. Danach überträgt sudo update-grub diesen Wert, indem es /boot/grub/grub.cfg neu erstellt. Setzen Sie den Wert auf 0, dann müssten Sie mangels Boot-Menü im Fehlerfall ein Live-System zur Reparatur heranziehen.
Kernel und Initrd
Das Ziel beim Starten ist es, Zugriff auf die Root-Partition zu erlangen, um auf die Dateien zuzugreifen und das Init-System – meist Systemd, früher Sys-V – zu starten. Letzteres könnte aber auf einem Netzwerklaufwerk, einem USB-Gerät mit einem Dateisystem oder einer NVMe-Platte mit einem anderen Dateisystem liegen. Der Linux-Kernel bringt daher eine Vielzahl an Treibern mit.
Aus Platz- und Geschwindigkeitsgründen sind diese Treiber jedoch nicht direkt in das Kernel-Abbild eingebaut, sondern liegen als Module zum Nachladen vor. Hier kommt die Initrd ins Spiel, die jene Treiber enthält, die der Linux-Kernel bei Bedarf in den Arbeitsspeicher entpackt (Listing 2).
Listing 2
Initrd
$ ls -lh /boot/initrd*
insgesamt 74M
-rw-r--r-- 1 root root 32M 22. Nov 09:55 initrd.img-5.9.0-2-amd64
-rw-r--r-- 1 root root 31M 25. Nov 22:11 initrd.img-5.9.0-3-amd64
In den Linux-Meldungen, die Sie mit sudo dmesg oder journalctl -k einsehen, findet sich eine Ausgabe wie in Listing 3: Nach fast 400 Millisekunden entpackt der Linux-Kernel das Initrd-Abbild und braucht dafür rund 420 Millisekunden.
Listing 3
Log-Meldungen zu Initrd
$ sudo dmesg | grep -A1 initramfs
[ 0.398506] Trying to unpack rootfs image as initramfs...
[ 0.817686] Freeing initrd memory: 25484K
Analysieren leicht gemacht
Das Werkzeug Systemd-bootchart zeigt die Messwerte des Kernels grafisch an. Dazu installieren Sie mit sudo apt install systemd-bootchart das entsprechende Paket und fügen in der /etc/default/grub der Variable GRUB_CMDLINE_LINUX_DEFAULT die Zeichenkette aus Listing 4 hinzu. Nach einem sudo update-grub und einem darauf folgenden Neustart befindet sich im Verzeichnis /run/log/ eine SVG-Datei, die Sie im Browser oder einem Bildbetrachter anschauen (Abbildung 1). Anhand der Balkenlänge erkennen Sie leicht die am längsten laufenden Routinen, die somit auch das meiste Optimierungspotenzial bieten.
Listing 4
Zusatz für Grub-Commandline
initcall_debug log_buf_len=2M init=/lib/systemd/systemd-bootchart

Abbildung 1: Die in /run/log/ abgelegte SVG-Datei stellt die Resourcenauslastung sowie Ausführungszeitpunkte und -dauer grafisch übersichtlich da.
Die Methode populate_rootfs() erzeugt die oben genannten Meldungen. Der Linux-Parameter initcall_debug sorgt dafür, dass Linux am Anfang und Ende der Methode eine Nachricht ausgibt und die Ausführungszeit notiert. Die Methode selbst ist mit 420 Millisekunden Laufzeit in der Tat einer der größten Brocken (Abbildung 2). Die Herausforderung lautet daher, diese Zeit auf 10 Millisekunden zu reduzieren.

Abbildung 2: Bei den Kernel-Init-Threads benötigt die Funktion populate_rootfs während des Bootens mit einer Dauer von 420 Millisekunden am meisten Zeit.
Kompression
Standardmäßig komprimiert Debians Initramfs-tool die Initrd mit Gzip und fügt alle Treiber hinzu. Das Abbild ist dann nur noch 31 MByte groß, das Laden und Entpacken dauert jedoch entsprechend lange. Sie konfigurieren das Verhalten über die Variable COMPRESS in /etc/initramfs-tools/initramfs.conf.
Ein sudo update-initramfs -u, das im Hintergrund Mkinitramfs aufruft, aktualisiert das Abbild für den neuesten Kernel. Somit erlaubt das Grub-Menü, im Fehlerfall ältere Kernel zu starten, um das kaputtoptimierte System zu reparieren.
Andere Algorithmen versprechen Besserung: Facebooks Zstandard (kurz: Zstd) braucht beim Komprimieren länger, produziert aber ein kleineres Archiv und entpackt es schneller (siehe Tabelle “Vergleich Kompressionsverfahren”). Auf Kosten eines größeren Abbilds erweist sich LZ4 als noch flotter beim Entpacken. Die passenden Werkzeuge installieren Sie mit sudo apt install zstd lz4.
|
Algorithmus |
Größe Initrd |
Entpackzeit |
Parameter |
|---|---|---|---|
|
Gzip |
31 MByte |
419 ms |
|
|
Zstd |
25 MByte |
260 ms |
|
|
LZ4 |
38 MByte |
84 ms |
|
Trotz des größeren Archivs braucht LZ4 zum Dekomprimieren mit 84 Millisekunden nur ein Fünftel der Zeit von Gzip und ein Drittel von Zstd. Das Ergebnis gilt aber nur für das Testsystem: Abhängig von der Geschwindigkeit des Prozessors und der Festplatte könnten auf anderen Systemen Zstd oder Gzip vorteilhafter sein.
Inhalt
Weiteres Optimierungspotenzial bietet das Reduzieren des Initrd-Umfangs. Das Paket initramfs-tools-core enthält dafür einige Werkzeuge, mit denen Sie unter anderem den Inhalt analysieren (Listing 5, Zeile 1 und 3). Von den 1377 Dateien beim Testsystem sind 665 Kernel-Module. Den Inhalt der Initrd entpacken Sie mit dem Befehl aus der ersten Zeile von Listing 6, sodass Sie den Platzverbrauch der einzelnen Verzeichnisse auf dem Testsystem analysieren können (ab Zeile 3).
Listing 5
Inhalt Initrd analysieren
$ lsinitramfs /boot/initrd.img-5.9.0-3-amd64 | wc -l 1377 $ lsinitramfs /boot/initrd.img-5.9.0-3-amd64 | grep -c ko$ 665
Listing 6
Platzverbrauch analysieren
$ unmkinitramfs /boot/initrd.img-5.9.0-3-amd64 5.9.0-3-amd64 $ cd 5.9.0-3-amd64 $ du -sh * 3,4M early 98M main $ du -sh main/usr/lib/* | sort -rh 84M main/usr/lib/modules 9,0M main/usr/lib/x86_64-linux-gnu 2,3M main/usr/lib/firmware 200K main/usr/lib/udev 76K main/usr/lib/klibc-zlroYG-5K-Jd0h1P0SDWWOT4wCA.so 16K main/usr/lib/systemd 16K main/usr/lib/modprobe.d $ du -sh main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/* | sort -rh | head -10 29M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/net 17M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/scsi 2,6M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/infiniband 2,5M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/block 2,2M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/usb 2,2M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/hid 1,9M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/ata 1,3M main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/mmc 940K main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/nvme 880K main/usr/lib/modules/5.9.0-3-amd64/kernel/drivers/input
Die Kernel-Module benötigen, wie vermutet, den meisten Platz. Die gebotene Vielfalt ist aber nur nötig, falls die Installation kompatibel zu verschiedenen Systemen mit vielen Szenarien sein soll. Im vorliegenden Fall muss die Installation jedoch nur auf einem einzigen Rechner funktionieren und bietet damit Raum zum Optimieren.
Der Parameter MODULES=dep in initramfs.conf sorgt dafür, dass nur jene Module in der Initrd landen, die zum Lesen des Root-Dateisystems und der Eingabe – etwa von LUKS-Passwörtern – nötig sind. Nach dem erneuten Erstellen des Abbilds schrumpft die Intitrd ganz wesentlich. Mit LZ4 lässt sich das Resultat nach wie vor am schnellsten entpacken (siehe Tabelle “Entschlackte Initrd”).
|
Algorithmus |
Größe Initrd |
Entpackzeit |
Parameter |
|---|---|---|---|
|
Zstd |
6,1 MByte |
58 ms |
|
|
LZ4 |
8,4 MByte |
18 ms |
|
Die Kernel-Module belegen statt 84 nur noch 4,6 MByte, und das Library-Verzeichnis beansprucht jetzt den meisten Platz. Ein erneuter Blick auf die dort gelagerten Dateien offenbart einige große Brocken (Listing 7).
Listing 7
Libraries analysieren
$ du -sh main/usr/lib/x86_64-linux-gnu/* | sort -rh | head -10
3,0M main/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
1,8M main/usr/lib/x86_64-linux-gnu/libc-2.31.so
1,3M main/usr/lib/x86_64-linux-gnu/libm-2.31.so
572K main/usr/lib/x86_64-linux-gnu/libpcre2-8.so.0.9.0
432K main/usr/lib/x86_64-linux-gnu/libdevmapper.so.1.02.1
412K main/usr/lib/x86_64-linux-gnu/libext2fs.so.2.4
368K main/usr/lib/x86_64-linux-gnu/libmount.so.1.1.0
332K main/usr/lib/x86_64-linux-gnu/libntfs-3g.so.883.0.0
320K main/usr/lib/x86_64-linux-gnu/libblkid.so.1.1.0
252K main/usr/lib/x86_64-linux-gnu/libfuse3.so.3.10.0
Die Bibliothek libcrypto.so.1.1 braucht Kmod (libkmod.so.2.3.5), um damit die Signatur der Linux-Module zu überprüfen [1]. Man könnte zwar prinzipiell Kmod mit --without-openssl bauen (der Autor hat es ausprobiert) und damit diese Abhängigkeit entfernen, was sich aber aus Sicherheitsgründen verbietet.
Es stellt sich jedoch die Frage, was Bibliotheken für NTFS und FUSE in der Initrd verloren haben. Viele Programme verfügen über einen Schalter, um ausführlichere Meldungen auszugeben. Das gilt auch für update-initramfs mit der Option -v (Listing 8).
Listing 8
Was macht update-initramfs?
$ sudo update-initramfs -uv
Available versions: 5.9.0-3-amd64
5.9.0-2-amd64
[...]
Calling hook ntfs_3g
Adding binary /bin/ntfs-3g
Adding binary-link /usr/lib/x86_64-linux-gnu/libntfs-3g.so.883
Adding binary /usr/lib/x86_64-linux-gnu/libntfs-3g.so.883.0.0
[...]
Diese Hooks – eine Möglichkeit für Pakete, eigene Skripte einzuhängen – liegen im Verzeichnis /usr/share/initramfs-tools/hooks/ und sind ausführbar. Ein nicht benötigtes Skript lässt sich deaktivieren, indem man das Dateimodusbit zum Ausführen mit Chmod entfernt (Listing 9). Beachten Sie dabei, dass ein System-Update die Änderung wieder rückgängig machen kann. LVM und verschlüsselte Root-Partitionen benötigen Dmsetup. Auf Systemen, auf denen /dev/mapper/ keine entsprechenden Dateien enthält, können Sie auch den Hook dmsetup deaktivieren.
Listing 9
Deaktivieren von drei benötigten Hooks
$ sudo chmod -x /usr/share/initramfs-tools/hooks/{fuse,ntfs_3g,thermal} $ sudo update-initramfs -uv [...] /usr/share/initramfs-tools/hooks/ntfs_3g ignored: not executable [...]
Auf Systemen, deren Firmware die aktuellen Microcode-Aktualisierungen mitbringt und anwendet (Listing 10), brauchen auch diese Aktualisierungen nicht noch einmal in die Initrd. Auf Intel-Systemen, auf denen Linux die Aktualisierung nicht protokolliert, dürfen Sie auch den Hook intel_microcode deaktivieren, was 500 KByte einspart.
Listing 10
Microcode-Aktualisierung prüfen
$ dmesg | grep microcode
[ 0.000000] microcode: microcode updated early to revision 0xde, date = 2020-05-26
[ 0.529552] microcode: sig=0x906e9, pf=0x2, revision=0xde
[ 0.529744] microcode: Microcode Update Driver: v2.2.
All diese vergleichsweise einfachen Änderungen sorgen dafür, dass das System die Initrd in 14,5 ms entpackt (Listing 11), wozu es zuvor 419 ms brauchte – satte achtundzwanzig Mal schneller.
Listing 11
Weniger als 15 ms
$ sudo dmsg
[...]
[ 0.398422] calling populate_rootfs+0x0/0x109 @ 1
[ 0.398453] Trying to unpack rootfs image as initramfs...
[ 0.413173] Freeing initrd memory: 6968K
[ 0.413254] initcall populate_rootfs+0x0/0x109 returned 0 after 14480 usecs
Entsprechend der 80-20-Regel benötigen die letzten Millisekunden unweit mehr Aufwand. Sie können noch ein paar Linux-Kernel-Module entfernen. Auf dem Testsystem etwa erfordert der Start weder den AHCI- noch den MMC-Treiber. Die Option MODULES=list in initramfs.conf sorgt dafür, nur die in /etc/initramfs-tools/modules aufgeführten Module hinzuzufügen (Listing 12). Das verringert die Zeit zum Auspacken und Laden der Initrd auf 9,5 ms. Damit ist das Ziel für das Testsystem erreicht (siehe Kasten “Potenzial”).
Listing 12
Explizit aufgeführte Module
crc32c-intel crc32c_generic jbd2 mbcache crc16 ext4 crct10dif_common crct10dif-pclmul crct10dif_generic crc-t10dif t10-pi nvme-core nvme
Potenzial
Es sei angemerkt, dass Sie ohne verschlüsselte Root-Partition ganz auf die Initrd verzichten können, falls der Kernel die Treiber für die Schnittstelle und das Dateisystem direkt enthält. Bei Debian ist das nicht der Fall, deshalb müssten Sie dafür den Linux-Kernel selbst bauen und die von Update-grub erzeugte Grub-Konfiguration /boot/grub/grub.cfg jedes Mal anpassen. Wegen dieser schlechten Integration ist das nicht zu empfehlen.
Tests
Die Grafik von Systemd-bootchart zeigt den großen Anteil der Methoden dh_init und rsa_init an der Startzeit (Abbildung 3). Es stellt sich heraus, dass diese Kryptografiemodule Hardware-Tests ausführen, die entsprechend viel Zeit in Anspruch nehmen (Listing 13). Falls Sie Wert auf Sicherheit legen, sollten Sie den Entwicklern vertrauen, dass diese Tests vonnöten sind. Falls Sie die 124 ms nicht warten möchten, fügen Sie der Variable GRUB_CMDLINE_LINUX_DEFAULT aus der /etc/default/grub noch die Option cryptomgr.notests hinzu.

Abbildung 3: Statt 419 ms braucht populate_rootfs nun weniger als 10 ms. In der ersten Sekunde treten jetzt dh_init, rsa_init und acpi_init hervor.
Listing 13
Zeitverbrauch der Kryptografietests
$ sudo dmesg | grep dh_init [ 0.144678] calling dh_init+0x0/0x20 @ 1 [ 0.245015] initcall dh_init+0x0/0x20 returned 0 after 97656 usecs $ sudo dmesg | grep rsa_init [ 0.245015] calling rsa_init+0x0/0x50 @ 1 [ 0.275009] initcall rsa_init+0x0/0x50 returned 0 after 27343 usecs
Weiterhin initialisiert der Linux-Kernel den Netzwerk-Stack sehr frühzeitig, was ebenfalls ein wenig Zeit kostet. Sollten Sie kein IPv6 benötigen, deaktivieren Sie das Modul, indem Sie wieder die Datei /etc/default/grub bearbeiten und in der Zeile GRUB_CMDLINE_LINUX_DEFAULT die Option ipv6.disable=1 ergänzen. Nach einem Neustart aktiviert das System nur noch den IPv4-Stack, was in lokalen Netzwerken oft genügt.
Fazit
Die vorgestellten Methoden verbessern das Verständnis des Startvorgangs einer Debian-Installation. Inklusive aller im Artikel genannten Optimierungen startet der selbst gebaute Linux-Kernel mit integriertem i915-Treiber den für die Laptop-Tastatur und das Touchpad verantwortlichen i8042-Treiber, bevor 300 ms vergangen sind (Abbildung 4). Die Treiber für ACPI und die Intel-Grafikkarte brauchen jetzt am meisten Zeit, wobei man den Intel-Treiber auf manchen Systemen asynchron starten könnte. Ohne den Parameter initcall_debug benötigt acpi_init einige Millisekunden weniger. Bei allen Optimierungsversuchen sollten Sie nie vergessen, dass das Messen selbst die Messung beeinflussen kann.

Abbildung 4: Mit allen Optimierungen benötigt das Laden der wichtigsten Treiber keine 300 ms mehr. Die Treiber für ACPI und die Intel-Grafik brauchen jetzt am meisten Zeit.
Moderne, leistungsstarke Systeme starten zwar schneller als ihre Vorgänger, aber in Anbetracht der Möglichkeiten immer noch zu langsam. Ein Grund dafür sind möglichst universelle Installationen, die auf möglichst vielen verschiedenen Systemen funktionieren sollen. Das gibt Admins alle Freiheiten, das System beliebig zu starten, zum Beispiel über Netzwerk oder von einem NTFS-formatierten USB-Medium. Als normaler Nutzer benötigen Sie diese Features jedoch in der Regel nicht und können das System speziell für ein Gerät und dessen Anwendungsfall konfigurieren. Auf einem leistungsstarken System ließ sich im Test die Bootzeit um eine Sekunde reduzieren, ältere Rechner mit entsprechend längeren Startzeiten bieten noch mehr Optimierungspotenzial. (agr/cla)
Glossar
-
80-20-Regel
-
Auch als Pareto-Prinzip bekannt: 80 Prozent einer Aufgabe lassen sich mit 20 Prozent des Gesamtaufwands abarbeiten, die restlichen 20 Prozent erfordern 80 Prozent der Arbeit.
Infos
-
“Increases size of initrd considerably since linking with OpenSSL”: https://bugs.debian.org/930752





