Startzeiten optimieren

Dieses Dokument enthält eine Anleitung für Partner zur Verbesserung der Startzeiten für bestimmte Android-Geräten Die Startzeit ist ein wichtiger Bestandteil der Systemleistung, Nutzer müssen warten, bis der Bootvorgang abgeschlossen ist, bevor sie das Gerät verwenden können. Für Geräte z. B. in Autos, bei denen der Kaltstart häufiger erfolgt, ein schneller Start Zeit ist entscheidend. Niemand möchte nur Dutzende von Sekunden warten, um einen Navigationsziel).

Dank Android 8.0 und mehreren Verbesserungen lassen sich die Startzeiten verkürzen. für eine Reihe von Komponenten. In der folgenden Tabelle sind diese Leistungen zusammengefasst. (gemessen an Google Pixel- und Pixel XL-Geräten)

Komponente Verbesserung
Bootloader
  • 1,6 s durch Entfernen des UART-Protokolls gespeichert
  • Einsparung von 0,4 Sek.durch Wechsel von GZIP zu LZ4
Gerätekernel
  • Einsparungen von 0,3 Sekunden durch Entfernen nicht verwendeter Kernel-Konfigurationen und Reduzieren der Treibergröße
  • 0,3 Sek.durch dm-verity-Prefetch-Optimierung eingespart
  • 0,15 Sekunden gespeichert, um unnötige Wartezeiten/Tests im Treiber zu entfernen
  • 0,12 Sek.zur Entfernung von CONFIG_CC_OPTIMIZE_FOR_SIZE gespeichert
E/A-Abstimmung
  • 2 Sek. beim normalen Start eingespart
  • Einsparung von 25 Sekunden beim ersten Start
init.*.rc
  • 1,5 Sekunden durch parallele init-Befehle eingespart
  • Durch vorzeitiges Starten von Zygote 0,25 Sek.eingespart
  • 0,22 Sek.durch CPU-Set-Abstimmung eingespart
Startanimation
  • Zwei Sekunden früher beim Booten gestartet, ohne dass fsck ausgelöst wurde, viel größer beim Booten mit Von fsck ausgelöster Start
  • Einsparung von 5 Sekunden auf Pixel XL durch sofortiges Herunterfahren der Startanimation
SELinux-Richtlinie 0,2 Sek.von genfscon eingespart

Bootloader optimieren

So optimieren Sie den Bootloader für kürzere Startzeiten:

  • Für die Protokollierung: <ph type="x-smartling-placeholder">
      </ph>
    • Deaktivieren Sie das Schreiben von Protokollen in UART, da dies mit vielen Logging. (Auf Google Pixel-Geräten verlangsamt es den Bootloader um 1, 5 Sek.).
    • Protokollieren Sie nur Fehlersituationen und legen Sie eventuell andere Informationen im Arbeitsspeicher fest mit einem separaten Mechanismus abzurufen.
  • Erwägen Sie für die Kernel-Dekomprimierung die Verwendung von LZ4 für moderne Hardware. statt GZIP (Beispiel patch). Beachten Sie, dass Kernelkomprimierungsoptionen können unterschiedliche Lade- und Dekomprimierungszeiten. Einige Optionen sind möglicherweise besser geeignet als andere für Ihre bestimmte Hardware nutzen.
  • Unnötige Wartezeiten auf Entprellung/Sondermodus prüfen und minimieren .
  • Übergeben Sie die im Bootloader-Startzeit als cmdline an den Kernel.
  • CPU-Takt und Parallelisierung prüfen (Unterstützung von Mehrkernen erforderlich) für das Laden des Kernels und die Initialisierung von E/A.

E/A-Effizienz optimieren

Die Verbesserung der E/A-Effizienz ist entscheidend, um die Startzeit zu verkürzen und das Lesen von Alles, was nicht notwendig ist, sollte erst nach dem Booten aufgeschoben werden (auf einem Google Pixel, etwa 1,2 GB Daten beim Booten gelesen werden.)

Dateisystem abstimmen

Der Linux-Kernel-Lesevorgang tritt ein, wenn eine Datei vom Anfang an oder werden sequenziell gelesen, was eine Feinabstimmung des E/A-Planers erfordert. Parameter speziell für das Booten (die eine andere Arbeitslast hat) als normale Apps).

Geräte, die nahtlose (A/B-)Updates unterstützen, profitieren stark vom Dateisystem. Feinabstimmung beim ersten Start (z.B. 20 Sekunden auf Google Pixel). Ein Beispiel: Wir haben die folgenden Parameter für das Google Pixel:

on late-fs
  # boot time fs tune
    # boot time fs tune
    write /sys/block/sda/queue/iostats 0
    write /sys/block/sda/queue/scheduler cfq
    write /sys/block/sda/queue/iosched/slice_idle 0
    write /sys/block/sda/queue/read_ahead_kb 2048
    write /sys/block/sda/queue/nr_requests 256
    write /sys/block/dm-0/queue/read_ahead_kb 2048
    write /sys/block/dm-1/queue/read_ahead_kb 2048

on property:sys.boot_completed=1
    # end boot time fs tune
    write /sys/block/sda/queue/read_ahead_kb 512
    ...

Sonstiges

  • Aktivieren Sie die dm-verity-Hash-Prefetch-Größe mit der Kernel-Konfiguration DM_VERITY_HASH_PREFETCH_MIN_SIZE (Standardgröße ist 128).
  • Für eine bessere Stabilität des Dateisystems und eine geringere erzwungene Prüfung, Verwenden Sie bei jedem Start das neue Tool der ext4-Generation, indem Sie TARGET_USES_MKE2FS in BoardConfig.mk.

E/A analysieren

Um E/A-Aktivitäten während des Bootvorgangs zu verstehen, verwenden Sie ftrace-Kernel-Daten, die auch von systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Nehmen Sie die folgenden Änderungen am Kernel vor, um den Dateizugriff für jede Datei aufzuschlüsseln (nur Entwicklungs-Kernel; nicht in Produktions-Kerneln verwenden):

diff --git a/fs/open.c b/fs/open.c
index 1651f35..a808093 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -981,6 +981,25 @@
 }
 EXPORT_SYMBOL(file_open_root);
 
+static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd)
+{
+       char *buf;
+       char *fname;
+
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+       fname = d_path(&filp-<f_path, buf, PAGE_SIZE);
+
+       if (IS_ERR(fname))
+               goto out;
+
+       trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n",
+                     current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino);
+out:
+       kfree(buf);
+}
+
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
 	struct open_flags op;
@@ -1003,6 +1022,7 @@
 		} else {
 			fsnotify_open(f);
 			fd_install(fd, f);
+			_trace_do_sys_open(f, flags, mode, fd);

Verwenden Sie die folgenden Skripts, um die Startleistung zu analysieren.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py Misst die Startzeit anhand einer Aufschlüsselung wichtiger Schritte im Startvorgang.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Stellt Zugriffsinformationen zu jeder Datei bereit.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Gibt eine Aufschlüsselung auf Systemebene an.

init.*.rc optimieren

Init ist die Brücke vom Kernel bis zur Festlegung des Frameworks. -Geräte verbringen in der Regel einige Sekunden in verschiedenen Init-Phasen.

Aufgaben parallel ausführen

Die aktuelle Android-Init-Instanz ist mehr oder weniger ein einzelner Thread-Prozess, dennoch einige Aufgaben parallel ausführen können.

  • Führen Sie langsame Befehle in einem Shell-Skriptdienst aus und fügen Sie diese später durch auf eine bestimmte Property warten. Android 8.0 unterstützt diesen Anwendungsfall mit einer neuen wait_for_property-Befehl.
  • Identifizieren Sie langsame Vorgänge in Init. Das System protokolliert den init-Befehl. exec/wait_for_prop oder einer Aktion, die lange dauert (unter Android 8.0 dauert es länger als 50 ms). Hier einige Beispiele:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    Ein Blick auf dieses Protokoll kann auf Verbesserungsmöglichkeiten hinweisen.

  • Starten Sie frühzeitig Dienste und aktivieren Sie Peripheriegeräte im kritischen Pfad. Für Bei einigen SOCs müssen beispielsweise sicherheitsrelevante Dienste gestartet werden, SurfaceFlinger. Überprüfen Sie das Systemprotokoll, wenn ServiceManager die Meldung "wait for Dienst“ – ist normalerweise ein Zeichen dafür, dass ein abhängiger Dienst gestartet werden muss. .
  • Entfernen Sie alle nicht verwendeten Dienste und Befehle in init.*.rc. Nichts verwendet in „Init im frühen Stadium“ sollte auf den Bootvorgang zurückgestellt werden.

Hinweis:Der Property-Dienst ist Teil des Initialisierungsprozesses. Das Aufrufen von setproperty beim Booten kann zu einer langen Verzögerung führen, wenn die Initialisierung in integrierte Befehle.

Planer-Feinabstimmung verwenden

Verwenden Sie die Planerabstimmung für den frühen Start. Beispiel von einem Google Pixel:

on init
    # boottime stune
    write /dev/stune/schedtune.prefer_idle 1
    write /dev/stune/schedtune.boost 100
    on property:sys.boot_completed=1
    # reset stune
    write /dev/stune/schedtune.prefer_idle 0
    write /dev/stune/schedtune.boost 0

    # or just disable EAS during boot
    on init
    write /sys/kernel/debug/sched_features NO_ENERGY_AWARE
    on property:sys.boot_completed=1
    write /sys/kernel/debug/sched_features ENERGY_AWARE

Einige Dienste benötigen möglicherweise eine Prioritätserhöhung während des Startvorgangs. Beispiel:

init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
...

Zygote frühzeitig starten

Geräte mit dateibasierter Verschlüsselung können Zygote früher bei „zygote-start“ starten Trigger (standardmäßig wird Zygote in der Klasse "main" gestartet, die viel später zygote-start. Stellen Sie dabei sicher, dass Zygote auf allen CPUs (wie eine falsche CPUset-Einstellung kann dazu führen, dass Zygote auf bestimmten CPUs ausgeführt wird.

Energiesparmodus deaktivieren

Beim Starten des Geräts Energiespareinstellung für Komponenten wie UFS und/oder CPU kann deaktiviert werden.

Achtung:Der Energiesparmodus sollte in für mehr Effizienz.

on init
    # Disable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
    write /sys/module/lpm_levels/parameters/sleep_disabled Y
on property:sys.boot_completed=1
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/module/lpm_levels/parameters/sleep_disabled N
on charger
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/class/typec/port0/port_type sink
    write /sys/module/lpm_levels/parameters/sleep_disabled N

Nicht kritische Initialisierung aufschieben

Nicht kritische Initialisierung wie ZRAM kann auf boot_complete verschoben werden.

on property:sys.boot_completed=1
   # Enable ZRAM on boot_complete
   swapon_all /vendor/etc/fstab.${ro.hardware}

Startanimation optimieren

Beachten Sie die folgenden Tipps, um die Startanimation zu optimieren.

Vorzeitigen Start konfigurieren

Unter Android 8.0 kann die Startanimation frühzeitig gestartet werden, bevor Nutzerdaten bereitgestellt werden. -Partition an. Aber selbst bei Verwendung der neuen ext4-Toolchain in Android 8.0, fsck wird aus Sicherheitsgründen weiterhin regelmäßig ausgelöst, was zu einer Verzögerung bei und den Bootanimation-Dienst starten.

Damit die Bootanimation frühzeitig gestartet wird, teilen Sie die fstab-Bereitstellung in zwei Phasen auf:

  • In der frühen Phase stellen Sie nur die Partitionen bereit, z. B. system/ und vendor/), die nicht ausgeführt werden müssen überprüft und startet dann Bootanimationsdienste und ihre Abhängigkeiten (z. B. Servicemanager und Surfaceflinger).
  • Stellen Sie in der zweiten Phase Partitionen (z. B. data/) bereit, die Tests ausführen.

Die Startanimation wird viel schneller (und in konstanter Zeit) gestartet, unabhängig von fsck aus.

Reinigung beenden

Nach Empfang des Exit-Signals spielt die Bootanimation den letzten Teil, die Länge die die Startzeit verlangsamen können. Ein System, das schnell startet, braucht keine lange Animationen, die vorgenommene Verbesserungen verdecken könnten. Wir empfehlen, sodass sowohl die Wiederholungsschleife als auch das Finale kurz sind.

SELinux optimieren

Mit den folgenden Tipps können Sie SELinux für kürzere Startzeiten optimieren.

  • Verwenden Sie saubere reguläre Ausdrücke (Regex). Falsch formatierte Regex kann zu viel Aufwand führen, wenn die SELinux-Richtlinie für sys/devices in file_contexts. Beispiel: Der reguläre Ausdruck /sys/devices/.*abc.*(/.*)? erzwingt versehentlich einen Scan aller /sys/devices Unterverzeichnisse, die „abc“ enthalten, sodass Übereinstimmungen möglich sind für /sys/devices/abc und /sys/devices/xyz/abc. Wenn Sie diesen regulären Ausdruck auf /sys/devices/[^/]*abc[^/]*(/.*)? ändern, eine Übereinstimmung nur für /sys/devices/abc aktivieren.
  • Verschieben Sie die Labels zu genfscon. Diese bestehende SELinux-Funktion übergibt Dateizuordnungspräfixe an den Kernel in dem SELinux-Binärprogramm, bei dem der Kernel sie auf vom Kernel generierte Dateisystemen. Dadurch werden auch vom Kernel erstellte Dateien mit falschem Label behoben, Race-Bedingungen zwischen Userspace-Prozessen, die versuchen, auf diese Dateien vor der Umbenennung.

Tools und Methoden

Verwenden Sie die folgenden Tools, um Daten für Optimierungsziele zu erfassen.

Bootchart

Bootchart bietet eine Aufschlüsselung der CPU- und E/A-Last aller Prozesse für das gesamte System. System. Sie müssen das System-Image nicht neu erstellen und können vor der Verwendung von Systrace überprüfen.

So aktivieren Sie Bootchart:

adb shell 'touch /data/bootchart/enabled'
adb reboot

Rufen Sie nach dem Start das Boot-Diagramm ab:

$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

Wenn Sie fertig sind, löschen Sie /data/bootchart/enabled, damit keine Daten erhoben werden die Daten jedes Mal abrufen.

Wenn Bootchart nicht funktioniert und Sie die Fehlermeldung erhalten, dass bootchart.png nicht vorhanden ist, tun Sie Folgendes: <ph type="x-smartling-placeholder">
    </ph>
  1. Führen Sie die folgenden Befehle aus:
          sudo apt install python-is-python3
          cd ~/Documents
          git clone https://github.com/xrmx/bootchart.git
          cd bootchart/pybootchartgui
          mv main.py.in main.py
        
  2. $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh aktualisieren um auf die lokale Kopie von pybootchartgui zu verweisen (Adresse: ~/Documents/bootchart/pybootchartgui.py)

Logo: Systrace

Systrace ermöglicht das Erfassen von Kernel- und Android-Traces während des Starts. Die Visualisierung von Systrace kann bei der Analyse eines bestimmten Problems während Systemstart hoch. Um jedoch die durchschnittliche oder die kumulierte Zahl während der ist es einfacher, den Kernel-Trace direkt zu überprüfen.

So aktivieren Sie Systrace beim Start:

  • In frameworks/native/cmds/atrace/atrace.rc Folgendes ändern:
      write /sys/kernel/debug/tracing/tracing_on 0
      write /sys/kernel/tracing/tracing_on 0

    Sie haben folgende Optionen:

      #    write /sys/kernel/debug/tracing/tracing_on 0
      #    write /sys/kernel/tracing/tracing_on 0
  • Dadurch wird das Tracing aktiviert (standardmäßig deaktiviert).

  • Fügen Sie in der Datei device.mk die folgende Zeile hinzu:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • Fügen Sie in der Datei BoardConfig.mk des Geräts Folgendes hinzu:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • Für detaillierte E/A-Analysen können Sie auch block und ext4 und f2fs hinzufügen.

  • Fügen Sie in der gerätespezifischen Datei init.rc Folgendes hinzu:
    on property:sys.boot_completed=1          // This stops tracing on boot complete
    write /d/tracing/tracing_on 0
    write /d/tracing/events/ext4/enable 0
    write /d/tracing/events/f2fs/enable 0
    write /d/tracing/events/block/enable 0
    
  • Rufen Sie nach dem Start den Trace ab:

    adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
    adb pull /data/local/tmp/boot_trace
    $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
    
<ph type="x-smartling-placeholder">