Auf dieser Seite finden Sie Tipps zur Verbesserung der Startzeit.
Debugging-Symbole aus Modulen entfernen
Ähnlich wie beim Entfernen von Symbolen zum Debuggen aus dem Kernel bei einer Produktionsumgebung entfernen Sie auch die Symbole zum Debuggen aus den Modulen. Wenn Sie Debugsymbole aus Modulen entfernen, verkürzt sich die Bootzeit, da Folgendes reduziert wird:
- Die Zeit, die zum Lesen der Binärdateien aus dem Flash-Speicher benötigt wird.
- Die Zeit, die zum Dekomprimieren des RAM-Laufwerks benötigt wird.
- Die Zeit, die zum Laden der Module benötigt wird.
Durch das Entfernen des Debug-Symbols aus Modulen kann während des Starts einige Sekunden eingespart werden.
Das Entfernen von Symbolen ist im Android-Plattform-Build standardmäßig aktiviert. Wenn Sie es explizit aktivieren möchten, legen Sie in Ihrer gerätespezifischen Konfiguration unter „device/vendor/device“ die Option BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES
fest.
LZ4-Komprimierung für Kernel und Ramdisk verwenden
Gzip generiert eine kleinere komprimierte Ausgabe als LZ4, aber LZ4. schneller als gzip. Bei Kernel und Modulen ist die absolute Speicherplatzeinsparung durch die Verwendung von Gzip im Vergleich zum Vorteil bei der Dekomprimierungszeit von LZ4 nicht so signifikant.
Der Android-Plattformversion ab BOARD_RAMDISK_USE_LZ4
wurde Unterstützung für die LZ4-Ramdisk-Komprimierung hinzugefügt. Sie können diese Option in Ihrem
gerätespezifische Konfiguration. Die Kernelkomprimierung kann über „Kernel defconfig“ festgelegt werden.
Durch den Wechsel zu LZ4 sollte die Bootzeit um 500 ms bis 1.000 ms verkürzt werden.
Vermeiden Sie übermäßiges Logging in Ihren Treibern
Bei ARM64 und ARM32 benötigen Funktionsaufrufe, die sich weiter als eine bestimmte Entfernung vom Aufrufort befinden, eine Sprungtabelle (Procedure Linking Table, PLT), um die vollständige Sprungadresse zu codieren. Da Module dynamisch geladen werden, müssen diese Jump-Tables beim Laden des Moduls repariert werden. Die Aufrufe, die neu angeordnet werden müssen, werden im ELF-Format als Relocation-Einträge mit expliziten Addenden (kurz RELA) bezeichnet.
Der Linux-Kernel nimmt einige Optimierungen der Arbeitsspeichergröße vor (z. B. Cache-Treffer).
Optimierung) beim Zuweisen des PLT. Bei diesen vorgelagerten
commit
hat das Optimierungsschema eine O(N^2)
-Komplexität, wobei N
die Anzahl der
RELAs vom Typ R_AARCH64_JUMP26
oder R_AARCH64_CALL26
. Mit weniger RELAs
dass die Modulladezeit verkürzt wird.
Ein gemeinsames Codierungsmuster, das die Anzahl der
R_AARCH64_CALL26
- oder R_AARCH64_JUMP26
-RELAs protokolliert zu viele in einem
. Bei jedem Aufruf von printk()
oder einem anderen Protokollschema wird in der Regel ein CALL26
/JUMP26
-RELA-Eintrag hinzugefügt. Im Commit-Text im Upstream
commit
Beachten Sie, dass die sechs Module nach der Optimierung etwa 250 ms benötigen.
zu laden. Das liegt daran, dass diese sechs Module
am meisten protokolliert.
Durch eine Verringerung des Loggings können Sie je nach Umfang der vorhandenen Protokollierung etwa 100 bis 300 ms beim Starten sparen.
Asynchrone Prüfungen selektiv aktivieren
Wenn ein Modul geladen wird und das unterstützte Gerät bereits
die aus der DT (Devicetree) ausgefüllt und dem Treiberkern hinzugefügt wurden,
Die Prüfung wird im Kontext des module_init()
-Aufrufs durchgeführt. Wenn eine Geräteprüfung im Kontext von module_init()
ausgeführt wird, kann das Modul erst geladen werden, wenn die Prüfung abgeschlossen ist. Da das Laden von Modulen größtenteils seriell erfolgt, verlängert sich die Bootzeit bei Geräten, bei denen die Prüfung relativ lange dauert.
Aktivieren Sie die asynchrone Prüfung für Module, die eine um ihre Geräte zu prüfen. Asynchrone Prüfung für alle Module aktivieren ist vielleicht nicht von Vorteil, weil die Zeit, die es braucht, um einen Thread aufzuspalten und den ersten kann so lang sein wie die Zeit, die für die Prüfung des Geräts benötigt wird.
Geräte, die über einen langsamen Bus verbunden sind, z. B. I2C, sowie Geräte, die und Geräte, die viel Hardware kann die Initialisierung zu Zeitproblemen führen. Um herauszufinden, die Prüfungszeit für jeden Fahrer zu erfassen und zu sortieren.
Um das asynchrone Prüfen für ein Modul zu aktivieren, reicht es nicht aus, nur das Flag PROBE_PREFER_ASYNCHRONOUS
im Treibercode festzulegen. Bei Modulen müssen Sie außerdem
module_name.async_probe=1
in der Kernel-Befehlszeile
oder async_probe=1
als Modulparameter übergeben, wenn das Modul mit
modprobe
oder insmod
.
Durch die Aktivierung der asynchronen Prüfung können 100–500 ms Startzeiten eingespart werden je nach Hardware/Treiber.
Prüfen Sie so früh wie möglich Ihren CPUfreq-Treiber
Je früher Ihr CPUfreq-Treiber testet, desto früher können Sie die CPU skalieren
während des Starts bis zum Maximum (oder einem thermischen Höchstwert) erreicht. Je schneller die CPU, desto schneller der Start. Diese Richtlinie gilt auch für devfreq
-Treiber, die die DRAM-, Speicher- und Interconnect-Frequenz steuern.
Bei Modulen kann die Ladereihenfolge von der initcall
-Ebene und der Kompilierungs- oder Verknüpfungsreihenfolge der Treiber abhängen. Verwenden Sie einen Alias MODULE_SOFTDEP()
, damit der cpufreq
-Treiber zu den ersten Modulen gehört, die geladen werden.
Sie müssen nicht nur das Modul frühzeitig laden, sondern auch sicherstellen, für die Prüfung des CPUfreq-Treibers. Wenn Sie beispielsweise einen Takt- oder Regler-Handle benötigen, um die Taktfrequenz Ihrer CPU zu steuern, müssen Sie diese zuerst prüfen. Möglicherweise müssen auch thermische Treiber vor dem CPUfreq-Treiber geladen werden, wenn Ihre CPUs beim Starten zu heiß werden können. Stellen Sie also sicher, dass die CPU-Frequenz und die relevanten devfreq-Treiber prüfen so früh wie möglich.
Die Einsparungen durch ein frühzeitiges Prüfen des CPUfreq-Treibers können sehr gering bis sehr hoch sein, je nachdem, wie früh Sie diese prüfen können und mit welcher Taktfrequenz der Bootloader die CPUs beibehält.
Module in die Partition „init der zweiten Stufe“, „vendor“ oder „vendor_dlkm“ verschieben
Da der Initialisierungsprozess der ersten Phase serialisiert ist, gibt es nicht viele
um den Bootprozess zu parallelisieren. Wenn ein Modul für die
init für die erste Phase verschieben möchten, verschieben Sie das Modul in
die zweite init-Phase, indem Sie es
in der Anbieter- oder vendor_dlkm
-Partition.
Bei der Initialisierung der ersten Phase müssen nicht mehrere Geräte geprüft werden, um zur zweiten Phase zu gelangen. init. Nur Konsolen- und Flash-Speicherfunktionen sind erforderlich für normalen Bootvorgang ausführen.
Laden Sie die folgenden wichtigen Treiber:
watchdog
reset
cpufreq
Für den Wiederherstellungs- und Nutzerbereich im fastbootd
-Modus sind für die Erstphase der Initialisierung mehr Geräte (z. B. USB) und ein Display erforderlich. Bewahren Sie eine Kopie dieser Module im RAM-Disk der ersten Stufe und in der Anbieter- oder vendor_dlkm
-Partition auf. So können sie
wird in der ersten Initialisierungsphase für die Wiederherstellung oder den fastbootd
-Boot-Flow geladen. Sie können jedoch
Module für den Wiederherstellungsmodus in der ersten Initialisierungsphase beim normalen Start nicht laden
Ablauf. Module für den Wiederherstellungsmodus können auf die Initialisierung der zweiten Stufe verschoben werden,
Startzeit. Alle anderen Module, die in der ersten Phase der Initialisierung nicht benötigt werden, sollten in die Anbieter- oder vendor_dlkm
-Partition verschoben werden.
Bei einer Liste der untergeordneten Geräte (z. B. UFS oder serielle Geräte)
dev needs.sh
alle Treiber, Geräte und Module, die für Abhängigkeiten oder
Lieferanten (z. B. Uhren, Regulierungsbehörden oder gpio
) zu prüfen.
Durch das Verschieben von Modulen zur Initialisierung der zweiten Stufe werden die Startzeiten in den folgenden Möglichkeiten:
- Reduzierung der Größe des RAM-Laufwerks.
- Dadurch werden Flash-Lesevorgänge schneller, wenn der Bootloader die Ramdisk lädt. (serialisierter Bootschritt).
- Dies führt zu einer schnelleren Dekomprimierung, wenn der Kernel das Ramdisk dekomprimiert (sequenzieller Bootschritt).
- Die Initialisierung der zweiten Phase erfolgt parallel, sie blendet die Ladezeit des Moduls aus mit der Arbeit in der zweiten Init-Phase.
Wenn Sie Module in die zweite Phase verschieben, können Sie je nach Anzahl der Module, die Sie in die zweite Phase der Initialisierung verschieben können, 500 bis 1.000 ms beim Starten sparen.
Logistik für das Laden des Moduls
Der neueste Android-Build enthält Board-Konfigurationen, mit denen gesteuert wird, welche Module in die einzelnen Phasen kopiert und welche geladen werden. In diesem Abschnitt geht es hauptsächlich um die folgenden Untergruppen:
BOARD_VENDOR_RAMDISK_KERNEL_MODULES
: Liste der Module, die in das RAM-Disk kopiert werden sollen.BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
Diese Liste der zu ladenden Module in der ersten Init-Phase.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD
Diese Liste der Module zur wird geladen, wenn die Wiederherstellung oderfastbootd
aus der RAM-Disk ausgewählt wird.BOARD_VENDOR_KERNEL_MODULES
: Liste der Module, die in das Verzeichnis/vendor/lib/modules/
in die Anbieter- odervendor_dlkm
-Partition kopiert werden sollen.BOARD_VENDOR_KERNEL_MODULES_LOAD
: Liste der Module, die in der zweiten Phase der Initialisierung geladen werden sollen.
Die Boot- und Wiederherstellungsmodule in Ramdisk müssen ebenfalls
Partition vendor_dlkm
bei /vendor/lib/modules
. Wenn Sie diese Module in den
Die Anbieterpartitionierung sorgt dafür,
dass die Module nicht unsichtbar sind,
Dies ist hilfreich beim Debuggen und Erfassen von modinfo
für Fehlerberichte.
Die Duplizierung sollte nur wenig Speicherplatz auf dem Anbieter oder vendor_dlkm
kosten.
Partition
solange der Bootmodulsatz minimiert ist. Die modules.list
-Datei des Anbieters muss eine gefilterte Liste der Module in /vendor/lib/modules
enthalten.
Durch die gefilterte Liste wird sichergestellt, dass die Startzeiten von den Modulen, die geladen werden, nicht beeinträchtigt werden.
was wiederum teuer ist.
Achten Sie darauf, dass die Module für den Wiederherstellungsmodus als Gruppe geladen werden. Das Laden von Modulen im Wiederherstellungsmodus kann entweder im Wiederherstellungsmodus oder zu Beginn der zweiten Phase der Init-Phase in jedem Boot-Vorgang erfolgen.
Sie können die Board.Config.mk
-Dateien des Geräts verwenden, um diese Aktionen auszuführen, wie im folgenden Beispiel gezeigt:
# All kernel modules
KERNEL_MODULES := $(wildcard $(KERNEL_MODULE_DIR)/*.ko)
KERNEL_MODULES_LOAD := $(strip $(shell cat $(KERNEL_MODULE_DIR)/modules.load)
# First stage ramdisk modules
BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m))
# Recovery ramdisk modules
RECOVERY_KERNEL_MODULES_FILTER := $(foreach m,$(RECOVERY_KERNEL_MODULES),%/$(m))
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \
$(filter $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# ALL modules land in /vendor/lib/modules so they could be rmmod/insmod'd,
# and modules.list actually limits us to the ones we intend to load.
BOARD_VENDOR_KERNEL_MODULES := $(KERNEL_MODULES)
# To limit /vendor/lib/modules to just the ones loaded, use:
# BOARD_VENDOR_KERNEL_MODULES := $(filter-out \
# $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# Group set of /vendor/lib/modules loading order to recovery modules first,
# then remainder, subtracting both recovery and boot modules which are loaded
# already.
BOARD_VENDOR_KERNEL_MODULES_LOAD := \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
BOARD_VENDOR_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# NB: Load order governed by modules.load and not by $(BOOT_KERNEL_MODULES)
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# Group set of /vendor/lib/modules loading order to boot modules first,
# then the remainder of recovery modules.
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
In diesem Beispiel wird eine leichter zu verwaltende Teilmenge von BOOT_KERNEL_MODULES
und RECOVERY_KERNEL_MODULES
gezeigt, die lokal in den Board-Konfigurationsdateien angegeben werden kann. Das vorherige Skript sucht nach jedem der untergeordneten Module aus der
verfügbaren Kernelmodule ausgewählt, und die Reamining-Module
Stage init an.
Für die zweite Phase der Initialisierung empfehlen wir, das Laden des Moduls als Dienst auszuführen, damit der Bootvorgang nicht blockiert wird. Verwenden Sie ein Shell-Script, um das Laden des Moduls zu verwalten, damit andere Logistikaufgaben wie Fehlerbehandlung und -behebung oder der Abschluss des Modulladevorgangs bei Bedarf gemeldet (oder ignoriert) werden können.
Sie können einen Fehler beim Laden des Debug-Moduls ignorieren, der in Nutzer-Builds nicht vorhanden ist.
Wenn Sie diesen Fehler ignorieren möchten, setzen Sie das Attribut vendor.device.modules.ready
auf
Auslösung späterer Phasen des init rc
-Scripting-Bootflows, um mit dem Start fortzufahren
Bildschirm. Verweisen Sie auf das folgende Beispielskript, wenn Sie den folgenden Code haben:
in /vendor/etc/init.insmod.sh
:
#!/vendor/bin/sh
. . .
if [ $# -eq 1 ]; then
cfg_file=$1
else
# Set property even if there is no insmod config
# to unblock early-boot trigger
setprop vendor.common.modules.ready
setprop vendor.device.modules.ready
exit 1
fi
if [ -f $cfg_file ]; then
while IFS="|" read -r action arg
do
case $action in
"insmod") insmod $arg ;;
"setprop") setprop $arg 1 ;;
"enable") echo 1 > $arg ;;
"modprobe") modprobe -a -d /vendor/lib/modules $arg ;;
. . .
esac
done < $cfg_file
fi
In der Hardware-RC-Datei kann der Dienst one shot
so angegeben werden:
service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg
class main
user root
group root system
Disabled
oneshot
Nach dem Wechsel von der ersten in die zweite Phase können weitere Optimierungen vorgenommen werden. Mit der Blocklist-Funktion von modprobe können Sie den Bootvorgang der zweiten Phase aufteilen, um das verzögerte Laden nicht erforderlicher Module zu ermöglichen. Das Laden von Modulen, die ausschließlich von einer bestimmten HAL verwendet werden, kann verschoben werden, sodass die Module erst beim Starten der HAL geladen werden.
Um die Startzeiten zu verbessern, können Sie im Modul
Modulladedienst, die für das Laden nach der Markteinführung
Bildschirm. Beispielsweise können Sie die Module für
Videodecoder oder WLAN, nachdem der Init-Boot-Ablauf beendet wurde
(sys.boot_complete
Android-Property-Signal. Achten Sie darauf, dass die HALs für das späte Laden
Module lange genug zu blockieren, wenn die Kernel-Treiber nicht vorhanden sind.
Alternativ können Sie den Befehl wait<file>[<timeout>]
von init im Boot-Flow-RC-Script verwenden, um auf ausgewählte sysfs
-Einträge zu warten, die anzeigen, dass die Treibermodule die Prüfvorgänge abgeschlossen haben. Ein Beispiel dafür ist das Warten auf das
Treiber laden, um das Laden im Hintergrund der Wiederherstellung abzuschließen, oder fastbootd
,
bevor Sie die Menügrafiken
präsentieren.
CPU-Frequenz auf einen angemessenen Wert im Bootloader initialisieren
Möglicherweise können nicht alle SoCs/Produkte die CPU mit der höchsten Frequenz starten aufgrund von Problemen mit der Stromversorgung oder der Überhitzung während der Startschleifentests. Achten Sie jedoch darauf, Bootloader legt die Frequenz aller Online-CPUs so hoch wie sicher fest. für ein SoC oder Produkt möglich ist. Das ist sehr wichtig, denn bei einer vollständigen modularen Kernel erfolgt die Init-RAMdisk-Dekomprimierung vor CPUfreq. Treiber geladen werden kann. Wenn sich die CPU-Leistung am unteren Ende kann die Dekomprimierungszeit der Ramdisk länger dauern als statisch kompilierter Kernel (nach Anpassung der Ramdisk-Größendifferenz) da die CPU-Frequenz bei CPU-intensiver Arbeit sehr niedrig wäre. (Dekomprimierung). Dasselbe gilt für den Arbeitsspeicher und die Verbindungshäufigkeit.
CPU-Frequenz von großen CPUs im Bootloader initialisieren
Bevor der CPUfreq
-Treiber geladen wird, erkennt der Kernel den
CPU-Frequenzen und skaliert die CPU-geplante Kapazität nicht für den aktuellen
Häufigkeit. Der Kernel migriert Threads zur großen CPU, wenn die Last
für die wenig CPU ausreichend hoch ist.
Achten Sie darauf, dass die großen CPUs bei der Taktfrequenz, mit der der Bootloader sie aktiviert, mindestens so leistungsfähig sind wie die kleinen CPUs. Wenn die große CPU beispielsweise bei gleicher Taktfrequenz doppelt so leistungsfähig ist wie die kleine CPU, der Bootloader aber die Taktfrequenz der kleinen CPU auf 1,5 GHz und die der großen CPU auf 300 MHz festlegt, sinkt die Bootleistung, wenn der Kernel einen Thread auf die große CPU verschiebt. Wenn es in diesem Beispiel sicher ist, die große CPU bei 750 MHz sollten Sie dies auch dann tun, wenn Sie sie nicht explizit verwenden möchten.
Treiber dürfen die Firmware nicht in der ersten Phase der Initialisierung laden
Es kann unvermeidlich sein, dass zuvor die Firmware geladen werden muss. Stage init an. Im Allgemeinen sollten Treiber jedoch keine Firmware in der ersten Phase laden. init, insbesondere bei Geräteprüfungen. Wenn die Firmware in der ersten Phase der Initialisierung geladen wird, kommt der gesamte Bootvorgang zum Stillstand, wenn die Firmware nicht im RAM-Disk der ersten Phase verfügbar ist. Selbst wenn die Firmware im ersten RAM-Disk vorhanden ist, führt dies zu einer unnötigen Verzögerung.