Ottimizza i tempi di avvio

Questo documento fornisce ai partner indicazioni su come migliorare i tempi di avvio per Dispositivi Android Il tempo di avvio è un componente importante delle prestazioni del sistema Gli utenti devono attendere il completamento dell'avvio prima di poter utilizzare il dispositivo. Per i dispositivi come nel caso di auto in cui l'avvio a freddo avviene più spesso, il tempo è fondamentale (a nessuno piace aspettare decine di secondi solo per inserire destinazione di navigazione).

Android 8.0 consente di ridurre i tempi di avvio grazie al supporto di diversi miglioramenti in una serie di componenti. La tabella seguente riassume questo rendimento miglioramenti (misurati su dispositivi Google Pixel e Pixel XL).

Componente Miglioramento
Bootloader
  • Hai salvato 1,6 secondi rimuovendo il log UART
  • Hai risparmiato 0,4 secondi passando a LZ4 da GZIP
Kernel del dispositivo
  • Sono stati salvati 0,3 secondi rimuovendo le configurazioni del kernel inutilizzate e riducendo le dimensioni del driver
  • Hai risparmiato 0,3 secondi con l'ottimizzazione del precaricamento dm-verity
  • È stato risparmiato 0,15 secondi per rimuovere attesa/test non necessari nel driver
  • Salvato 0,12 sec per rimuovere CONFIG_CC_OPTIMIZE_FOR_SIZE
Ottimizzazione I/O
  • 2 secondi salvati sull'avvio normale
  • Risparmio di 25 secondi al primo avvio
init.*.rc
  • Risparmio di 1,5 secondi con il parallelo dei comandi init
  • Risparmio di 0,25 secondi avviando lo zigote in anticipo
  • Salvato di 0,22 secondi dalla traccia di cpuset
Animazione di avvio
  • Iniziato 2 s prima all'avvio senza fsck attivato, molto più grande all'avvio con avvio attivato fsck
  • Risparmio di 5 secondi su Pixel XL con l'arresto immediato dell'animazione all'avvio
Criterio SELinux 0,2 sec risparmiati da genfscon

Ottimizza bootloader

Per ottimizzare il bootloader in modo da migliorare i tempi di avvio:

  • Per il logging:
    • Disattiva la scrittura dei log in UART perché può richiedere molto tempo e molti log. Sui dispositivi Google Pixel, abbiamo riscontrato che rallenta il bootloader di 1,5 secondi.
    • Registra solo le situazioni di errore e valuta la possibilità di archiviare altre informazioni in memoria con un meccanismo separato per il recupero.
  • Per la decompressione del kernel, considerare l'uso di LZ4 per l'hardware contemporaneo anziché GZIP (esempio patch). Tieni presente che opzioni di compressione del kernel diverse possono avere tempi di decompressione e alcune opzioni potrebbero funzionare meglio di altre per il tuo per uno specifico hardware.
  • Controlla i tempi di attesa non necessari per il debouncing/l'accesso in modalità speciale e riduci a icona che li rappresentano.
  • Passa il tempo di avvio nel bootloader nel kernel come cmdline.
  • Controllare il clock della CPU e considerare il caricamento in contemporanea (richiede supporto multi-core) per il caricamento del kernel e l'inizializzazione di I/O.

Ottimizza l'efficienza dell'I/O

Migliorare l'efficienza di I/O è fondamentale per velocizzare i tempi di avvio e tutto ciò che non è necessario deve essere differito fino a dopo l'avvio (su Google Pixel, circa 1,2 GB di dati vengono letti all'avvio).

Ottimizza il file system

La lettura anticipata del kernel Linux si attiva quando un file viene letto dall'inizio o quando i blocchi vengono letti in sequenza, rendendo necessario l'ottimizzazione dello scheduler specifici per l'avvio (che ha un carico di lavoro diverso rispetto alle normali app).

I dispositivi che supportano aggiornamenti senza interruzioni (A/B) traggono un notevole vantaggio dal file system ottimizzazione al primo avvio (ad es. 20 secondi su Google Pixel). Per fare un esempio, abbiamo ottimizzato i seguenti parametri per 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
    ...

Vari

  • Attivare la dimensione di precaricamento dell'hash dm-verity utilizzando la configurazione del kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (la dimensione predefinita è 128).
  • Per una migliore stabilità del file system e un controllo forzato eliminato che si verifica su ad ogni avvio, usa il nuovo strumento di generazione ext4 impostando TARGET_USES_MKE2FS in BoardConfig.mk.

Analizza I/O

Per comprendere le attività di I/O durante l'avvio, usa i dati ftrace del kernel (utilizzati anche systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Per ripartire l'accesso ai file per ogni file, apporta le seguenti modifiche al kernel (solo kernel di sviluppo, non usare nei kernel di produzione):

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);

Utilizza i seguenti script per facilitare l'analisi delle prestazioni dell'avvio.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py Misura il tempo di avvio con una suddivisione dei passaggi importanti del processo di avvio.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Fornisce informazioni di accesso per ogni file.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Fornisce un'analisi a livello di sistema.

Ottimizza init.*.rc

L'inizializzazione è il bridge dal kernel fino a quando il framework non viene stabilito. i dispositivi in genere impiegano alcuni secondi in diverse fasi di avvio.

Esegui attività in parallelo

Anche se l'attuale inizializzazione di Android è più o meno un singolo processo in thread, può comunque eseguire alcune attività in parallelo.

  • Eseguire comandi lenti in un servizio di script shell e unirlo in un secondo momento in attesa di una proprietà specifica. Android 8.0 supporta questo caso d'uso con una nuova Comando wait_for_property.
  • Identifica le operazioni lente in init. Il sistema registra il comando init exec/wait_for_prop o qualsiasi azione che richiede molto tempo (in Android 8.0, qualsiasi comando che impiega più di 50 ms). Ad esempio:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    La revisione di questo log potrebbe indicare opportunità di miglioramento.

  • Avvia i servizi e abilita in anticipo i dispositivi periferici sul percorso critico. Per Ad esempio, alcuni SOC richiedono di avviare i servizi relativi alla sicurezza prima SurfaceFlinger. Rivedi il log di sistema quando ServiceManager restituisce "wait for" " : di solito indica che è necessario avviare un servizio dipendente. per prima cosa.
  • Rimuovi eventuali servizi e comandi inutilizzati in init.*.rc. Qualsiasi elemento non utilizzato in la fase iniziale di init deve essere rinviata al completamento dell'avvio.

Nota: il servizio immobiliare fa parte del processo di inizializzazione, quindi le chiamate setproperty durante l'avvio può causare un ritardo lungo se il comando init è occupato in comandi integrati.

Usa l'ottimizzazione dello scheduler

Utilizza l'ottimizzazione dello scheduler per l'avvio anticipato. Esempio da 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

Alcuni servizi potrebbero richiedere un boost di priorità durante l'avvio. Esempio:

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

Inizia presto lo zigote

I dispositivi con crittografia basata su file possono avviare lo zigote prima (per impostazione predefinita, zygote viene lanciato nella classe main, che è molto più tardi di zygote-start). Quando esegui questa operazione, assicurati di consentire l'esecuzione di zygote in tutte le CPU (come l'impostazione del cpuset errata può forzare l'esecuzione dello zygote in CPU specifiche).

Disattiva risparmio energetico

Durante l'avvio del dispositivo, l'impostazione di risparmio energetico per componenti come UFS e/o CPU e il governatore può essere disattivato.

Attenzione:il risparmio energetico deve essere attivato in modalità di ricarica per maggiore efficienza.

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

Rimanda l'inizializzazione non critica

L'inizializzazione non critica, come la ZRAM, può essere differita a boot_complete.

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

Ottimizza animazione all'avvio

Utilizza i suggerimenti riportati di seguito per ottimizzare l'animazione all'avvio.

Configura avvio anticipato

Android 8.0 consente di avviare l'animazione all'avvio in anticipo, prima di montare i dati utente della partizione di testo. Tuttavia, anche quando si utilizza la nuova catena di strumenti ext4 in Android 8.0, fsck viene comunque attivata periodicamente per motivi di sicurezza, causando un ritardo nella avviando il servizio bootanimation.

Per fare in modo che bootanimation venga avviato prima, suddividi il montaggio fstab in due fasi:

  • Nella fase iniziale, monta solo le partizioni (come system/ e vendor/) che non richiedono l'esecuzione avvia i servizi di animazione all'avvio e le sue dipendenze (come servicemanager e Surfaceflinger).
  • Nella seconda fase, monta le partizioni (ad esempio data/) che non richiedono l'esecuzione di controlli.

L'animazione di avvio verrà avviata molto più velocemente (e in modo costante) indipendentemente caspita.

Termina pulizia

Dopo aver ricevuto il segnale di uscita, bootanimation riproduce l'ultima parte, la lunghezza che possono rallentare i tempi di avvio. Un sistema che si avvia rapidamente non richiede tempi lunghi animazioni che possono nascondere efficacemente eventuali miglioramenti apportati. I nostri suggerimenti rendendo sia il loop ripetuto che il finale corto.

Ottimizza SELinux

Utilizza i seguenti suggerimenti per ottimizzare SELinux per tempi di avvio migliori.

  • Utilizza espressioni regolari chiare (regex). Regex non corretta può comportare un overhead elevato durante la corrispondenza del criterio SELinux per sys/devices a file_contexts. Ad esempio, l'espressione regolare /sys/devices/.*abc.*(/.*)? forza erroneamente l'analisi di tutti /sys/devices sottodirectory che contengono "abc", abilitando le corrispondenze sia per /sys/devices/abc che per /sys/devices/xyz/abc. Migliorare questa espressione regolare in /sys/devices/[^/]*abc[^/]*(/.*)? attiva una corrispondenza solo per /sys/devices/abc.
  • Sposta le etichette in genfscon. Questa funzionalità SELinux esistente passa i prefissi corrispondenti ai file nel kernel in il file binario SELinux, dove il kernel li applica ai file tra i file system. Ciò è utile anche per correggere errori di etichettatura dei file creati dal kernel, impedendo condizioni di gara che possono verificarsi tra i processi dello spazio utente che tentano di accedere prima della rietichettatura.

Strumenti e metodi

Per raccogliere dati per i target di ottimizzazione, utilizza i seguenti strumenti.

Grafico di avvio

Bootchart fornisce un'analisi del carico di CPU e I/O di tutti i processi dell'intero di un sistema operativo completo. Non richiede la ricreazione dell'immagine di sistema e può essere utilizzato come rapido dello stato di salute prima di immergersi in systrace.

Per attivare bootchart:

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

Dopo l'avvio, recupera il grafico di avvio:

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

Al termine, elimina /data/bootchart/enabled per impedire la raccolta i dati ogni volta.

Se bootchart non funziona e ricevi un errore che indica che bootchart.png non esiste, esegui le seguenti:
  1. Esegui questi comandi:
          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. Aggiorna $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh per indirizzare alla copia locale di pybootchartgui (si trova presso ~/Documents/bootchart/pybootchartgui.py)

Fioritura

Systrace consente di raccogliere tracce sia del kernel che di Android durante l'avvio. La visualizzazione di Systrace può aiutare ad analizzare un problema specifico durante il avvio automatico. (Tuttavia, per controllare il numero medio o il numero accumulato durante il durante l'intero avvio, è più facile esaminare direttamente la traccia del kernel).

Per abilitare systrace durante l'avvio:

  • In frameworks/native/cmds/atrace/atrace.rc, modifica:
      write /sys/kernel/debug/tracing/tracing_on 0
      write /sys/kernel/tracing/tracing_on 0

    A:

      #    write /sys/kernel/debug/tracing/tracing_on 0
      #    write /sys/kernel/tracing/tracing_on 0
  • Questa opzione attiva il tracciamento (disattivato per impostazione predefinita).

  • Nel file device.mk, aggiungi la seguente riga:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • Nel file BoardConfig.mk del dispositivo, aggiungi quanto segue:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • Per un'analisi I/O dettagliata, aggiungi anche block, ext4 e f2fs.

  • Nel file init.rc specifico per il dispositivo, aggiungi quanto segue:
    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
    
  • Dopo l'avvio, recupera la traccia:

    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
    
di Gemini Advanced.