Boot-Zeit von Embedded Linux optimieren: messen, bevor Sie schrauben
Von Power-on bis zum ersten Bild: wie Sie die Boot-Zeit eines Embedded-Linux-Geräts belastbar messen und in Bootloader, Kernel und User-Space die Hebel finden, die tatsächlich Sekunden bringen.
Kurz gesagt: Boot-Zeit ist ein Produktmerkmal, kein Nebeneffekt. Ob ein Gerät nach zwei oder nach fünfzehn Sekunden bedienbar ist, entscheidet über den Eindruck, den es hinterlässt – und in manchen Anwendungen darüber, ob es die Anforderungen überhaupt erfüllt. Der Weg dorthin führt nicht über eine Liste bekannter Tricks, sondern über eine Messung: Erst wenn feststeht, welche Phase wie viel kostet, lohnt sich das Schrauben. Fast jedes ungeprüfte System hat einen dominanten Einzelposten, und er sitzt selten dort, wo man ihn vermutet.
Die Kette vom Einschalten bis zum ersten Bild
Zwischen Power-on und einer bedienbaren Oberfläche liegen mehrere Stationen, die sich unabhängig voneinander optimieren lassen:
Das Boot-ROM im SoC lädt einen kleinen Erstlader aus Flash oder eMMC. Es ist unveränderlich und damit die Untergrenze, die Sie nicht unterschreiten können. Der SPL initialisiert den Arbeitsspeicher und lädt den eigentlichen Bootloader. U-Boot initialisiert Peripherie, sucht Kernel und Device Tree, wartet gegebenenfalls auf eine Eingabe und übergibt. Der Kernel dekomprimiert sich, bringt Treiber hoch, hängt das Root-Dateisystem ein. Das Init-System startet Dienste. Zuletzt startet die Anwendung und zeichnet ihr erstes Bild.
Nutzer bewerten nicht die Summe dieser Phasen, sondern den Moment, in dem das Gerät reagiert. Das ist eine wichtige Unterscheidung, auf die wir weiter unten zurückkommen.
Zuerst messen
Ohne Messung optimiert man Vermutungen. Vier Werkzeuge decken die gesamte Kette ab:
Zeitstempel auf der Konsole. CONFIG_PRINTK_TIME versieht jede Kernel-Meldung mit einem Zeitstempel. Auf der Bootloader-Seite protokolliert ein Werkzeug wie grabserial die serielle Ausgabe mit Zeitstempeln des Hostrechners und schließt damit die Lücke vor dem Kernel-Start.
Initcall-Analyse. Der Kernel-Parameter initcall_debug protokolliert jede Initialisierungsfunktion samt Dauer. Damit fallen die Treiber auf, die auf ein Timeout laufen – ein einzelner davon kostet oft mehr als alle Feinoptimierungen zusammen.
# Nach dem Start: die teuersten Initcalls sichtbar machen
dmesg | grep initcall | sort -t' ' -k2 -rn | head -20
Analyse des User-Space. Bei systemd zeigt systemd-analyze blame die langsamsten Dienste und systemd-analyze critical-chain die tatsächlich kritische Kette – der wichtigere der beiden Befehle, weil ein langsamer Dienst irrelevant ist, solange er nebenher startet.
Der ehrliche Referenzpunkt. Die belastbarste Messung ist ein GPIO, den die Anwendung nach dem ersten gezeichneten Bild umschaltet, aufgezeichnet mit einem Oszilloskop gegen die Versorgungsspannung. Das misst, was der Kunde erlebt – inklusive Boot-ROM und aller Anteile, die keine Software je protokolliert.
Wo die Zeit üblicherweise steckt
| Phase | Typische Zeitfresser | Wirksame Hebel |
|---|---|---|
| SPL / U-Boot | bootdelay, Netzwerk- und USB-Initialisierung, langsames Laden | bootdelay=0, ungenutzte Treiber abschalten, Falcon Mode |
| Kernel | Dekompression, Treiber mit Timeout, gesprächige Konsole | Passendes Kompressionsformat, quiet, Treiber entrümpeln |
| Root-Dateisystem | Große initramfs, Dateisystem-Prüfung, langsames Medium | Kleines oder kein initramfs, read-only-Root, squashfs |
| Init / Dienste | Serialisierte Abhängigkeiten, unnötige Dienste | Kritische Kette entflechten, Dienste streichen |
| Anwendung | Vollständige Initialisierung vor dem ersten Bild | Anzeige zuerst, Rest nachladen |
Die Hebel im Einzelnen
Bootloader
Der schnellste Gewinn ist meist bootdelay=0 – die Wartezeit auf eine Tastatureingabe hat in einem Serienimage nichts verloren. Danach lohnt der Blick auf die Peripherie: Ein U-Boot, das Netzwerk, USB und alle Speichercontroller initialisiert, obwohl es nur von eMMC lädt, verschenkt Zeit. Wer weiter gehen will, kommt zum Falcon Mode: Der SPL lädt Kernel und Device Tree direkt und überspringt das vollständige U-Boot. Das kann eine Sekunde und mehr sparen, kostet aber Flexibilität – Boot-Menü, interaktive Eingriffe und manche Update-Verfahren brauchen dann einen zweiten Pfad. In Kombination mit A/B-Updates, wie wir sie im Beitrag zu sicheren OTA-Updates beschreiben, will dieser Schritt sorgfältig durchdacht sein.
Kernel
Drei Punkte tragen den Großteil. Erstens die Konsolenausgabe: Jede Zeile wird bei 115.200 Baud synchron herausgeschrieben. Ein gesprächiges System verliert hier leicht mehrere hundert Millisekunden – quiet als Boot-Parameter ist eine der billigsten Verbesserungen überhaupt, verschlechtert allerdings die Diagnosefähigkeit im Feld.
Zweitens die Kompression des Kernel-Images. Hier gibt es keine pauschal richtige Antwort: LZ4 und LZO dekomprimieren deutlich schneller als gzip oder XZ, erzeugen aber größere Images. Auf einem langsamen Speichermedium kann ein kleineres, stärker komprimiertes Image insgesamt schneller sein, weil das Laden dominiert; auf schnellem eMMC gewinnt fast immer die schnelle Dekompression. Diese Frage lässt sich nur messen, nicht ableiten.
Drittens die Treiberauswahl. Alles, was das Gerät nicht besitzt, gehört nicht in die Konfiguration. Besonders lohnend sind Treiber, die auf ein Timeout laufen, weil sie auf nicht vorhandene Hardware warten – initcall_debug findet sie zuverlässig.
Root-Dateisystem und Init
Ein initramfs, das nur dazu dient, ein paar Module zu laden, lässt sich oft ganz einsparen, indem die nötigen Treiber fest in den Kernel gebaut werden. Ein read-only-Root-Dateisystem entfällt der Konsistenzprüfung beim Start und ist ohnehin die robustere Wahl für Geräte, die jederzeit hart abgeschaltet werden können.
Beim Init-System zählt weniger die Gesamtzahl der Dienste als deren Verkettung. systemd-analyze critical-chain zeigt den Pfad, der tatsächlich bremst; oft lässt sich eine Abhängigkeit auflösen oder ein Dienst so umstellen, dass er nach dem Start der Anwendung nachläuft statt davor.
Anwendung und gefühlte Zeit
Der wirksamste Hebel ist häufig kein technischer, sondern ein gestalterischer. Ein Gerät, das nach 1,5 Sekunden ein Logo zeigt und nach 6 Sekunden vollständig bedienbar ist, wird als schneller empfunden als eines, das 4 Sekunden schwarz bleibt und dann fertig ist. Ein früher Splash aus dem Bootloader oder Kernel überbrückt die Zeit, in der ohnehin nichts zu sehen wäre.
Konsequent weitergedacht heißt das: Die Anwendung zeichnet zuerst, was der Nutzer sieht, und lädt den Rest danach. Bei Qt-Oberflächen ist das ein bewusster Architekturentscheid – welche QML-Komponenten sofort geladen werden und welche verzögert. Wir haben die Zusammenhänge im Beitrag zu Qt im Embedded-Umfeld ausgeführt.
Was Sie nicht opfern sollten
Zwei Dinge sind es nicht wert, für Boot-Zeit geopfert zu werden. Update-Sicherheit: Ein Boot-Pfad ohne Rückfallebene ist schnell, bis ein Update fehlschlägt und das Gerät nicht mehr startet. Signaturprüfung: Secure Boot kostet messbar Zeit, und das ist eingeplante Zeit – sie zu streichen, um eine Sekunde zu gewinnen, tauscht ein Produktmerkmal gegen ein Sicherheitsversprechen.
Ebenfalls im Blick behalten: Boot-Zeit ist eine Größe, die schleichend zurückwandert. Ein neuer Dienst hier, ein zusätzlicher Treiber dort, und ein Jahr später ist der mühsam erarbeitete Vorsprung aufgebraucht. Deshalb gehört die Messung in die Verifikation – auf unserem Embedded Testrack läuft sie als regulärer Testfall bei jedem Build gegen echte Hardware, sodass eine Verschlechterung sofort auffällt statt beim nächsten Serienstart.
Im Yocto-Setup verankern
Damit die Optimierung nicht als Sammlung händischer Eingriffe endet, gehört sie in die Distributionskonfiguration: Kernel-Konfiguration als Fragment im eigenen Layer, Boot-Parameter über die Bootloader-Konfiguration, das Image ohne Entwicklungswerkzeuge, die im Feld nichts zu suchen haben. So ist die Boot-Zeit reproduzierbar statt ein Zufallsprodukt des jeweiligen Builds. Wie wir solche Layer aufsetzen, beschreiben wir unter Yocto BSP & Distributionen und in unserer Arbeit an Embedded-Linux-Plattformen.
Fazit
Boot-Zeit-Optimierung ist Handwerk, kein Trickvorrat: messen, die dominante Phase identifizieren, dort ansetzen, erneut messen. Die größten Gewinne liegen fast immer in wenigen Posten – einer gesprächigen Konsole, einem Treiber im Timeout, einer serialisierten Dienstkette, einer Anwendung, die alles vor dem ersten Bild erledigt. Und vergessen Sie die gefühlte Zeit nicht: Ein früh gezeigtes Bild ist oft mehr wert als die letzten dreihundert eingesparten Millisekunden. Wenn Ihr Gerät zu lange braucht und Sie wissen möchten, wo die Sekunden bleiben, melden Sie sich.
Häufige Fragen
- Womit fange ich an, wenn das Gerät zu langsam startet?
- Mit einer Messung, nie mit einer Vermutung. Aktivieren Sie Zeitstempel auf der seriellen Konsole, protokollieren Sie den gesamten Startvorgang mit und werten Sie aus, welche Phase wie viel kostet. In fast jedem ungeprüften System liegt der größte Einzelposten woanders als erwartet – häufig im User-Space oder in einem einzelnen Treiber, der auf ein Timeout läuft.
- Wie viel bringt es, die serielle Konsole abzuschalten?
- Oft überraschend viel. Jede Zeile Kernel-Ausgabe wird bei niedriger Baudrate synchron herausgeschrieben; bei gesprächigen Systemen summiert sich das auf Hunderte von Millisekunden bis in den Sekundenbereich. Für Serie mit `quiet` arbeiten und die Konsole nur in Entwicklungs-Images voll aktivieren – aber daran denken, dass damit auch die Diagnose im Feld schwerer wird.
- Lohnt sich der Falcon Mode?
- Er lohnt sich, wenn der Bootloader messbar Zeit kostet und die Hardware-Initialisierung stabil und unveränderlich ist. Der SPL springt dabei direkt in den Kernel und überspringt das vollständige U-Boot. Der Preis ist Flexibilität: Interaktive Eingriffe, Boot-Menüs und einige Update-Verfahren fallen weg oder brauchen einen zweiten Pfad – bei A/B-Update-Strategien will das sorgfältig durchdacht sein.
Alexander Nassian
Geschäftsführer, bitshift dynamics
Entwickelt mit seinem Team hardwarenahe Software für Embedded-Produkte – C++, Qt/QML, Embedded Linux und das Yocto Project. bitshift dynamics arbeitet seit 2005 in diesem Feld.