Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Optimización de tiempos de arranque

Este documento proporciona orientación para socios para mejorar los tiempos de arranque de dispositivos Android específicos. El tiempo de inicio es un componente importante del rendimiento del sistema, ya que los usuarios deben esperar a que se complete el inicio antes de poder usar el dispositivo. Para dispositivos como los automóviles, donde el arranque en frío ocurre con más frecuencia, tener un tiempo de arranque rápido es fundamental (a nadie le gusta esperar decenas de segundos solo para ingresar un destino de navegación).

Android 8.0 permite reducir los tiempos de arranque al admitir varias mejoras en una variedad de componentes. La siguiente tabla resume estas mejoras de rendimiento (medidas en dispositivos Google Pixel y Pixel XL).

Componente Mejora
Cargador de arranque
  • Guardado 1,6 s al eliminar el registro UART
  • Ahorró 0.4 s al cambiar a LZ4 desde GZIP
Kernel del dispositivo
  • Se ahorraron 0,3 segundos al eliminar las configuraciones del kernel no utilizadas y reducir el tamaño del controlador
  • Se ahorraron 0,3 s con la optimización de captación previa de dm-verity
  • Se ahorraron 0,15 s para eliminar la espera / prueba innecesaria en el controlador
  • Se guardó 0.12s para eliminar CONFIG_CC_OPTIMIZE_FOR_SIZE
Sintonización de E / S
  • 2 segundos guardados en el arranque normal
  • Ahorró 25 segundos en el primer arranque
init. *. rc
  • Se ahorraron 1,5 s mediante comandos de inicio en paralelo
  • Ahorró 0,25 s al iniciar el cigoto temprano
  • Guardado 0.22s por cpuset tune
Animación de inicio
  • Comenzó 2 s antes en el arranque sin fsck activado, mucho más grande en el arranque con arranque activado por fsck
  • 5 segundos guardados en Pixel XL con el apagado inmediato de la animación de arranque
Política de SELinux Guardado 0.2s en por genfscon

Optimización del cargador de arranque

Para optimizar el cargador de arranque para mejorar los tiempos de arranque:

  • Para el registro:
    • Desactive la escritura de registros en UART, ya que puede llevar mucho tiempo con muchos registros. (En los dispositivos Google Pixel, encontramos que ralentiza el cargador de arranque 1.5s).
    • Registre solo situaciones de error y considere almacenar otra información en la memoria con un mecanismo separado para recuperar.
  • Para la descompresión del kernel, considere usar LZ4 para hardware actual en lugar de GZIP ( parche de ejemplo). Tenga en cuenta que las diferentes opciones de compresión del kernel pueden tener diferentes tiempos de carga y descompresión, y algunas opciones pueden funcionar mejor que otras para su hardware específico.
  • Compruebe los tiempos de espera innecesarios para la entrada de modo antirrebote / especial y minimícelos.
  • Pase el tiempo de arranque empleado en el gestor de arranque al kernel como cmdline.
  • Verifique el reloj de la CPU y considere la paralelización (requiere soporte de múltiples núcleos) para la carga del kernel e inicialización de E / S.

Optimización del kernel

Utilice los siguientes consejos para optimizar el kernel y mejorar los tiempos de arranque.

Minimizar la defconfig del dispositivo

Minimizar la configuración del kernel puede reducir el tamaño del kernel para una descompresión de carga más rápida, inicialización y superficies de ataque más pequeñas. Para optimizar la defconfig del dispositivo:

  • Identifique los controladores no utilizados . Revise los directorios /dev y /sys y busque nodos con etiquetas SELinux generales (lo que indica que esos nodos no están configurados para ser accesibles por espacio de usuario). Elimine dichos nodos si los encuentra.
  • Desarmar CONFIG no utilizados . Revise el archivo .config generado por la compilación del kernel para desarmar explícitamente cualquier CONFIG no utilizado que estaba activado de forma predeterminada. Por ejemplo, eliminamos las siguientes CONFIG no utilizadas de Google Pixel:
    CONFIG_ANDROID_LOGGER=y
    CONFIG_IMX134=y
    CONFIG_IMX132=y
    CONFIG_OV9724=y
    CONFIG_OV5648=y
    CONFIG_GC0339=y
    CONFIG_OV8825=y
    CONFIG_OV8865=y
    CONFIG_s5k4e1=y
    CONFIG_OV12830=y
    CONFIG_USB_EHCI_HCD=y
    CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
    CONFIG_IKCONFIG=y
    CONFIG_RD_BZIP2=y
    CONFIG_RD_LZMA=y
    CONFIG_TI_DRV2667=y
    CONFIG_CHR_DEV_SCH=y
    CONFIG_MMC=y
    CONFIG_MMC_PERF_PROFILING=y
    CONFIG_MMC_CLKGATE=y
    CONFIG_MMC_PARANOID_SD_INIT=y
    CONFIG_MMC_BLOCK_MINORS=32
    CONFIG_MMC_TEST=y
    CONFIG_MMC_SDHCI=y
    CONFIG_MMC_SDHCI_PLTFM=y
    CONFIG_MMC_SDHCI_MSM=y
    CONFIG_MMC_SDHCI_MSM_ICE=y
    CONFIG_MMC_CQ_HCI=y
    CONFIG_MSDOS_FS=y
    # CONFIG_SYSFS_SYSCALL is not set
    CONFIG_EEPROM_AT24=y
    # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
    CONFIG_INPUT_HBTP_INPUT=y
    # CONFIG_VGA_ARB is not set
    CONFIG_USB_MON=y
    CONFIG_USB_STORAGE_DATAFAB=y
    CONFIG_USB_STORAGE_FREECOM=y
    CONFIG_USB_STORAGE_ISD200=y
    CONFIG_USB_STORAGE_USBAT=y
    CONFIG_USB_STORAGE_SDDR09=y
    CONFIG_USB_STORAGE_SDDR55=y
    CONFIG_USB_STORAGE_JUMPSHOT=y
    CONFIG_USB_STORAGE_ALAUDA=y
    CONFIG_USB_STORAGE_KARMA=y
    CONFIG_USB_STORAGE_CYPRESS_ATACB=y
    CONFIG_SW_SYNC_USER=y
    CONFIG_SEEMP_CORE=y
    CONFIG_MSM_SMEM_LOGGING=y
    CONFIG_IOMMU_DEBUG=y
    CONFIG_IOMMU_DEBUG_TRACKING=y
    CONFIG_IOMMU_TESTS=y
    CONFIG_MOBICORE_DRIVER=y
    # CONFIG_DEBUG_PREEMPT is not set
    
  • Elimine los CONFIG que conducen a ejecuciones de prueba innecesarias en cada arranque . Si bien son útiles en el desarrollo, tales configuraciones (es decir, CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST) deben eliminarse en un kernel de producción.

Minimizar el tamaño del controlador

Algunos controladores en el kernel del dispositivo se pueden eliminar si la función no se usa para reducir aún más el tamaño del kernel. Por ejemplo, si la WLAN está conectada a través de PCIe, la compatibilidad con SDIO no se utiliza y debe eliminarse durante el tiempo de compilación. Para obtener más información, consulte el kernel de Google Pixel: net: wireless: cnss: add para deshabilitar la compatibilidad con SDIO.

Eliminando la optimización del compilador por tamaño

Elimine la configuración del kernel para CONFIG_CC_OPTIMIZE_FOR_SIZE. Este indicador se introdujo originalmente cuando se suponía que un tamaño de código más pequeño produciría un acierto de caché en caliente (y por lo tanto sería más rápido). Sin embargo, esta suposición ya no es válida a medida que los SoC móviles modernos se han vuelto más poderosos.

Además, eliminar el indicador puede habilitar la advertencia del compilador para las variables no inicializadas, que se suprime en los kernels de Linux cuando el indicador CONFIG_CC_OPTIMIZE_FOR_SIZE está presente (hacer este cambio por sí solo nos ha ayudado a descubrir muchos errores significativos en algunos controladores de dispositivos Android).

Aplazamiento de la inicialización

Muchos procesos se inician durante el arranque, pero solo los componentes en la ruta crítica (cargador de arranque> kernel> init> montaje del sistema de archivos> zygote> servidor del sistema) afectan directamente el tiempo de arranque. Perfile initcall durante el arranque del kernel para identificar los periféricos / componentes que son lentos y no críticos para iniciar el proceso de inicio, luego retrase esos periféricos / componentes hasta más adelante en el proceso de arranque moviéndose a módulos de kernel cargables. Pasar a una sonda de controlador / dispositivo asíncrono también puede ayudar a conectar componentes lentos en paralelo en la ruta crítica del kernel> init.

BoardConfig-common.mk:
    BOARD_KERNEL_CMDLINE += initcall_debug ignore_loglevel

driver:
    .probe_type = PROBE_PREFER_ASYNCHRONOUS,

Nota: Las dependencias de los controladores deben resolverse con cuidado agregando compatibilidad con EPROBEDEFER .

Optimización de la eficiencia de E / S

Mejorar la eficiencia de E / S es fundamental para acelerar el tiempo de inicio, y la lectura de cualquier cosa que no sea necesaria debe posponerse hasta después del inicio (en un Google Pixel, se leen aproximadamente 1,2 GB de datos al iniciar).

Ajuste del sistema de archivos

La lectura anticipada del kernel de Linux se activa cuando se lee un archivo desde el principio o cuando los bloques se leen secuencialmente, por lo que es necesario ajustar los parámetros del programador de E / S específicamente para el arranque (que tiene una caracterización de carga de trabajo diferente a la de las aplicaciones normales).

Los dispositivos que admiten actualizaciones integradas (A / B) se benefician enormemente del ajuste del sistema de archivos en el primer arranque (por ejemplo, 20 en Google Pixel). Como ejemplo, ajustamos los siguientes parámetros para 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
    ...

Diverso

  • Active el tamaño de captación previa de hash dm-verity mediante la configuración del kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (el tamaño predeterminado es 128).
  • Para una mejor estabilidad del sistema de archivos y una verificación forzada descartada que ocurre en cada arranque, use la nueva herramienta de generación ext4 configurando TARGET_USES_MKE2FS en BoardConfig.mk.

Analizando E / S

Para comprender las actividades de E / S durante el arranque, use los datos de kernel ftrace (también usados ​​por systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Para desglosar el acceso a los archivos para cada archivo, realice los siguientes cambios en el kernel (solo kernel de desarrollo; no utilizar en kernels de producción):

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

Utilice las siguientes secuencias de comandos para ayudar a analizar el rendimiento de arranque.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py Mide el tiempo de arranque con un desglose de los pasos importantes en el proceso de arranque.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Proporciona información de acceso para cada archivo.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Proporciona un desglose a nivel del sistema.

Optimización de init. *. Rc

Init es el puente desde el kernel hasta que se establece el marco, y los dispositivos suelen pasar unos segundos en diferentes etapas de inicio.

Ejecución de tareas en paralelo

Si bien el inicio de Android actual es más o menos un proceso de un solo subproceso, aún puede realizar algunas tareas en paralelo.

  • Ejecute comandos lentos en un servicio de script de shell y únase a eso más tarde esperando una propiedad específica. Android 8.0 admite este caso de uso con un nuevo comando wait_for_property .
  • Identifique operaciones lentas en init. El sistema registra el comando init exec / wait_for_prop o cualquier acción que demore mucho tiempo (en Android 8.0, cualquier comando que demore más de 50 ms). Por ejemplo:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    La revisión de este registro puede indicar oportunidades de mejoras.

  • Inicie los servicios y habilite los dispositivos periféricos en la ruta crítica con anticipación. Por ejemplo, algunos SOC requieren iniciar servicios relacionados con la seguridad antes de iniciar SurfaceFlinger. Revise el registro del sistema cuando ServiceManager devuelva "esperar servicio"; esto suele ser una señal de que se debe iniciar primero un servicio dependiente.
  • Elimine todos los servicios y comandos no utilizados en init. *. Rc. Todo lo que no se use en la etapa inicial de inicio debe posponerse para que se complete el inicio.

Nota: El servicio de propiedades es parte del proceso de inicio, por lo que llamar a setproperty durante el arranque puede provocar una gran demora si init está ocupado en los comandos integrados.

Usando el ajuste del planificador

Utilice el ajuste del programador para un inicio temprano. Ejemplo de un 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

Algunos servicios pueden necesitar un impulso de prioridad durante el arranque. Ejemplo:

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

Inicio temprano del cigoto

Los dispositivos con cifrado basado en archivos pueden iniciar zygote antes en el disparador de zygote-start (de forma predeterminada, zygote se inicia en la clase principal, que es mucho más tarde que zygote-start). Al hacer esto, asegúrese de permitir que zygote se ejecute en todas las CPU (ya que la configuración incorrecta de cpuset puede obligar a que zygote se ejecute en CPU específicas).

Desactivar el ahorro de energía

Durante el arranque del dispositivo, la configuración de ahorro de energía para componentes como UFS y / o el regulador de la CPU se puede desactivar.

Precaución: El ahorro de energía debe habilitarse en el modo de cargador para mayor eficiencia.

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

Aplazar la inicialización no crítica

La inicialización no crítica como ZRAM se puede diferir a boot_complete.

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

Optimización de la animación de arranque

Utilice los siguientes consejos para optimizar la animación de arranque.

Configurar inicio temprano

Android 8.0 permite iniciar la animación de arranque antes de montar la partición de datos de usuario. Sin embargo, incluso cuando se usa la nueva cadena de herramientas ext4 en Android 8.0, fsck se activa periódicamente por motivos de seguridad, lo que provoca un retraso en el inicio del servicio de animación de arranque.

Para que bootanimation comience temprano, divida el montaje de fstab en dos fases:

  • En la primera fase, monte solo las particiones (como system/ y vendor/ ) que no requieran verificaciones de ejecución, luego inicie los servicios de animación de arranque y sus dependencias (como servicemanager y surfaceflinger).
  • En la segunda fase, monte particiones (como data/ ) que requieran verificaciones de ejecución.

La animación de arranque se iniciará mucho más rápido (y en tiempo constante) independientemente de fsck.

Acabado limpio

Después de recibir la señal de salida, bootanimation juega la última parte, cuya duración puede ralentizar el tiempo de arranque. Un sistema que se inicia rápidamente no necesita animaciones largas que podrían ocultar de manera efectiva cualquier mejora realizada. Recomendamos que tanto el bucle de repetición como el final sean cortos.

Optimización de SELinux

Utilice los siguientes consejos para optimizar SELinux y mejorar los tiempos de arranque.

  • Utilice expresiones regulares limpias (regex) . Las expresiones regulares mal formadas pueden generar una gran sobrecarga al hacer coincidir la política de SELinux para sys/devices en file_contexts . Por ejemplo, la expresión regular /sys/devices/.*abc.*(/.*)? fuerza por error un análisis de todos los subdirectorios /sys/devices que contienen "abc", lo que permite coincidencias tanto para /sys/devices/abc como para /sys/devices/xyz/abc . ¿Mejorando esta expresión regular a /sys/devices/[^/]*abc[^/]*(/.*)? habilitará una coincidencia solo para /sys/devices/abc .
  • Mueva las etiquetas a genfscon . Esta característica existente de SELinux pasa prefijos de coincidencia de archivos al kernel en el binario de SELinux, donde el kernel los aplica a los sistemas de archivos generados por el kernel. Esto también ayuda a reparar los archivos creados por el núcleo mal etiquetados, evitando las condiciones de carrera que pueden ocurrir entre los procesos del espacio de usuario que intentan acceder a estos archivos antes de que ocurra el reetiquetado.

Herramienta y métodos

Utilice las siguientes herramientas para ayudarlo a recopilar datos para los objetivos de optimización.

Bootchart

Bootchart proporciona un desglose de la carga de CPU y E / S de todos los procesos para todo el sistema. No requiere la reconstrucción de la imagen del sistema y se puede usar como una verificación rápida de cordura antes de sumergirse en systrace.

Para habilitar el diagrama de arranque:

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

Después del arranque, busque el gráfico de arranque:

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

Cuando termine, elimine /data/bootchart/enabled para evitar la recopilación de datos cada vez.

Systrace

Systrace permite recopilar seguimientos del kernel y de Android durante el arranque. La visualización de systrace puede ayudar a analizar un problema específico durante el arranque. (Sin embargo, para verificar el número promedio o el número acumulado durante todo el arranque, es más fácil mirar directamente el rastreo del kernel).

Para habilitar systrace durante el arranque:

  • En frameworks/native/atrace/atrace.rc , cambie:
    write /sys/kernel/debug/tracing/tracing_on 0

    A:

    #write /sys/kernel/debug/tracing/tracing_on 0
  • Esto habilita el rastreo (que está deshabilitado de forma predeterminada).

  • En el archivo device.mk , agregue la siguiente línea:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • En el archivo BoardConfig.mk del dispositivo, agregue lo siguiente:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • Para un análisis detallado de E / S, agregue también block y ext4 y f2fs.

  • En el archivo init.rc específico del dispositivo, realice los siguientes cambios:
    • on property:sys.boot_completed=1 (esto detiene el seguimiento en el inicio completo)
    • 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

Después de arrancar, busque el rastro:

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

Nota: Chrome no puede manejar archivos demasiado grandes. Considere cortar el archivo boot_trace usando tail , head o grep para las porciones necesarias. Y el análisis de E / S a menudo requiere analizar el boot_trace capturado directamente, ya que hay demasiados eventos.