En esta página, se proporcionan sugerencias para mejorar el tiempo de inicio.
Quita los símbolos de depuración de los módulos
De manera similar a cómo se quitan los símbolos de depuración del kernel en una instancia asegúrate de quitar también los símbolos de depuración de los módulos. Quita la depuración de los módulos ayuda al inicio mediante la reducción de lo siguiente:
- El tiempo que lleva leer los objetos binarios desde Flash.
- El tiempo que lleva descomprimir el disco RAM.
- El tiempo que lleva cargar los módulos.
Si quitas el símbolo de depuración de los módulos, es posible que ahorres varios segundos durante el inicio.
La eliminación de símbolos está habilitada de forma predeterminada en la compilación de la plataforma de Android, pero
para habilitarlos explícitamente, establece
BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES
en la configuración específica de tu dispositivo
en device/vendor/device.
Cómo usar la compresión LZ4 para kernel y ramdisk
Gzip genera un resultado comprimido más pequeño en comparación con LZ4, pero se descomprime más rápido que Gzip. Para el kernel y los módulos, el almacenamiento absoluto la reducción de tamaño con Gzip no es tan significativa en comparación con tiempo de descompresión de LZ4.
Se agregó compatibilidad con la compresión de ramdisk LZ4 a la plataforma de Android.
compila mediante BOARD_RAMDISK_USE_LZ4
. Puedes configurar esta opción en tu
la configuración específica del dispositivo. La compresión del kernel se puede configurar con la defconfig.
Si cambias a LZ4, el tiempo de inicio debería ser de 500 ms a 1,000 ms más rápido.
Cómo evitar registros excesivos en tus controladores
En ARM64 y ARM32, las llamadas a funciones que están a más de una distancia específica de el sitio de la llamada necesita que una tabla de salto (llamada tabla de vinculación de procedimientos o PLT) se y se puede codificar la dirección de salto completa. Como los módulos se cargan de forma dinámica, estas tablas de salto deben arreglarse durante la carga del módulo. Las llamadas que necesitan reubicación se denominan entradas de reubicación con sumas explícitos. (o RELA, para abreviar) en formato ELF.
El kernel de Linux optimiza el tamaño de la memoria (como el acierto de caché).
(optimización) cuando se asigna el PLT. Con este flujo ascendente,
confirmación,
el esquema de optimización tiene una complejidad O(N^2)
, donde N
es la cantidad de
RELA de tipo R_AARCH64_JUMP26
o R_AARCH64_CALL26
Es por eso que tener menos RELA
de estos tipos es útil para reducir el tiempo de carga del módulo.
Un patrón de codificación común que aumenta la cantidad de
R_AARCH64_CALL26
o R_AARCH64_JUMP26
RELA son registros excesivos en un
controlador. Cada llamada a printk()
o cualquier otro esquema de registro suele agregar un
CALL26
/JUMP26
entrada de RELA. En el texto de confirmación del flujo de
confirmación,
Ten en cuenta que incluso con la optimización, los seis módulos tardan alrededor de 250 ms
ya que esos seis módulos fueron los seis módulos principales con
la mayor cantidad de registros.
Reducir el registro puede ahorrar entre 100 y 300 ms en los tiempos de inicio de lo excesivo que es el registro existente.
Habilitar el sondeo asíncrono de forma selectiva
Cuando se carga un módulo, si el dispositivo que admite ya se
se completa a partir de la DT (devicetree) y se agrega al núcleo del controlador, luego, el dispositivo
el sondeo se realiza en el contexto de la llamada a module_init()
. Cuando se realiza un sondeo de dispositivo
en el contexto de module_init()
, el módulo no puede terminar de cargarse hasta que
el sondeo se complete. Como la carga de módulos suele estar serializada, un dispositivo que
lleva un tiempo relativamente largo sondear ralentiza el tiempo de inicio.
Para evitar tiempos de inicio más lentos, habilita el sondeo asíncrono para los módulos que tarden mientras sondean sus dispositivos. Habilita el sondeo asíncrono para todos los módulos podría no ser beneficioso, ya que el tiempo que lleva bifurcar un hilo y comenzar puede ser tan alto como el tiempo que demore en sondear el dispositivo.
Dispositivos que se conectan a través de un bus lento, como I2C, dispositivos que no la carga del firmware en la función de sondeo y los dispositivos que hacen mucho hardware la inicialización puede generar un problema de tiempo. La mejor manera de identificar cuándo es recopilar el tiempo de sondeo de cada conductor y clasificarlo.
Para habilitar el sondeo asíncrono para un módulo, no es suficiente solamente
configura PROBE_PREFER_ASYNCHRONOUS
en el código del controlador. Para los módulos, también debes agregar
module_name.async_probe=1
en la línea de comandos del kernel
o pasa async_probe=1
como parámetro del módulo cuando se carga el módulo con
modprobe
o insmod
.
Si habilitas el sondeo asíncrono puede ahorrar alrededor de 100 ms a 500 ms en los tiempos de inicio según el hardware o los controladores.
Sondea el controlador de CPUfreq lo antes posible
Cuanto antes investigue el controlador de CPUfreq, antes podrás escalar la CPU
frecuencia al máximo (o un máximo limitado térmicamente) durante el inicio. El
más rápido será la CPU, más rápido será el inicio. Este lineamiento también se aplica a devfreq
.
controladores que controlan la DRAM, la memoria y la frecuencia de interconexión.
Con los módulos, el orden de la carga puede depender del nivel de initcall
y
el orden de compilación o vinculación de los controladores. Usa un alias MODULE_SOFTDEP()
para hacer
Asegúrate de que el controlador cpufreq
esté entre los primeros módulos que se cargarán.
Además de cargar el módulo con antelación, debes asegurarte de que para sondear el controlador de CPUfreq. Por ejemplo, si necesitas un reloj o una manija de regulador para controlar la frecuencia de tu CPU, asegúrate antes de verificar que se sondean primero. O es posible que necesites controladores térmicos para cargar antes que el controlador de CPUfreq si es posible que las CPU se en caliente durante el inicio. Así que, haga lo que pueda para asegurarse de que la CPUfreq los controladores de devfreq sondeos lo antes posible.
El ahorro por sondear el controlador de CPUfreq de manera anticipada puede ser desde muy pequeño hasta muy grandes, dependiendo de qué tan temprano puedas hacer el sondeo y con qué frecuencia el bootloader deja las CPU en su interior.
Mueve módulos a la partición init, provider o provider_dlkm de la segunda etapa.
Debido a que el proceso init de la primera etapa es serializado, no hay muchos
oportunidades para paralelizar el proceso de inicio. Si no se necesita un módulo para
init de primera etapa para finalizar, coloca el módulo a init de segunda etapa colocándolo
en la partición del proveedor o vendor_dlkm
.
El inicio de la primera etapa no requiere el sondeo de varios dispositivos para llegar a la segunda etapa init. Solo se requieren las capacidades de almacenamiento flash y de la consola para un flujo de inicio normal.
Carga los siguientes controladores esenciales:
watchdog
reset
cpufreq
Para el modo fastbootd
de recuperación y espacio del usuario, el init de la primera etapa requiere más
dispositivos para sondear (como USB) y mostrar. Guarda una copia de estos módulos en el
ramdisk de primera etapa y en la partición vendor_dlkm
o del proveedor. Esto les permite
cargarse en el inicio de la primera etapa para la recuperación o en el flujo de inicio de fastbootd
. Sin embargo,
No cargues los módulos del modo de recuperación en el inicio de la primera etapa durante el inicio normal.
de tu flujo de trabajo. Los módulos de modo de recuperación pueden aplazarse al init de la segunda etapa para disminuir la
tiempo de inicio. Todos los demás módulos que no sean necesarios en el init de la primera etapa deben
se movió a la partición del proveedor o vendor_dlkm
.
Dada una lista de dispositivos de hoja (por ejemplo, el modelo UFS o el número de serie),
dev needs.sh
secuencia de comandos encuentra todos los controladores, dispositivos y módulos necesarios para las dependencias o
proveedores (por ejemplo, relojes, reguladores o gpio
) para sondear.
Mover los módulos a init de segunda etapa disminuye los tiempos de inicio en las siguientes situaciones: maneras:
- Reducción del tamaño del ramdisk
- Esto produce lecturas más rápidas cuando el bootloader carga el disco RAM. (paso de inicio serializado).
- Esto produce velocidades de descompresión más rápidas cuando el kernel descomprime la ramdisk (paso de inicio serializado)
- El init de la segunda etapa funciona en paralelo, lo que oculta el tiempo de carga del módulo y el trabajo se hace en el init de la segunda etapa.
Mover módulos a la segunda etapa puede ahorrar entre 500 y 1,000 ms en los tiempos de inicio, según de cuántos módulos puedes pasar a la init de la segunda etapa.
Logística de la carga del módulo
Las últimas configuraciones de la placa de funciones de compilación de Android que controlan qué los módulos se copian en cada etapa y qué módulos se cargan. Esta sección se centra en el siguiente subconjunto:
BOARD_VENDOR_RAMDISK_KERNEL_MODULES
Esta lista de módulos se copiará en el ramdisk.BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
Esta lista de módulos para cargar en el init de la primera etapa.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD
Esta lista de módulos para se cargará cuando se seleccione la recuperación o se seleccionefastbootd
del disco RAM.BOARD_VENDOR_KERNEL_MODULES
Esta lista de módulos se copiará en proveedor ovendor_dlkm
en el directorio/vendor/lib/modules/
.BOARD_VENDOR_KERNEL_MODULES_LOAD
Esta lista de módulos que se cargarán en init de segunda etapa.
Los módulos de inicio y recuperación de ramdisk también se deben copiar en el proveedor
vendor_dlkm
de partición en /vendor/lib/modules
. Copiar estos módulos en el
la partición de proveedor garantiza que los módulos no sean invisibles durante el inicio de la segunda etapa,
que es útil para depurar y recopilar modinfo
para los informes de errores.
La duplicación debería costar un espacio mínimo en el proveedor o vendor_dlkm
.
partición
siempre y cuando se minimice el conjunto de módulos de inicio. Asegúrate de que la configuración del proveedor
El archivo modules.list
tiene una lista filtrada de módulos en /vendor/lib/modules
.
La lista filtrada garantiza que los tiempos de inicio no se vean afectados por la carga de los módulos
(lo que es un proceso costoso).
Asegúrate de que los módulos del modo de recuperación se carguen como un grupo. Cargando módulos de Modo de recuperación puede hacerse en modo de recuperación o al comienzo de la segunda etapa init en cada flujo de inicio.
Puedes usar los archivos Board.Config.mk
del dispositivo para realizar estas acciones como se ve
en el siguiente ejemplo:
# 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)))
En este ejemplo, se muestra un subconjunto más fácil de administrar de BOOT_KERNEL_MODULES
y
RECOVERY_KERNEL_MODULES
se especificará de forma local en la configuración de la placa
archivos. La secuencia de comandos anterior encuentra y completa cada uno de los módulos de subconjunto del
módulos de kernel disponibles seleccionados, dejando los demás módulos por segundo
init de la etapa.
Para init de segunda etapa, recomendamos ejecutar la carga del módulo como servicio para no bloquea el flujo de inicio. Usa una secuencia de comandos de shell para administrar la carga del módulo para que otros aspectos logísticos, como el manejo y la mitigación de errores, o la carga de módulos del proyecto, se pueden informar (o ignorar) si es necesario.
Puedes ignorar un error de carga del módulo de depuración que no está presente en las compilaciones de usuario.
Para ignorar esta falla, establece la propiedad vendor.device.modules.ready
en
Activa etapas posteriores del flujo de inicio de secuencias de comandos de init rc
para continuar con el lanzamiento
en la pantalla. Consulta la siguiente secuencia de comandos de ejemplo si tienes el siguiente código
en /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
En el archivo rc de hardware, el servicio one shot
se podría especificar con lo siguiente:
service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg
class main
user root
group root system
Disabled
oneshot
Se pueden realizar optimizaciones adicionales después de que los módulos pasen del primer módulo a la segunda etapa. Puedes usar la función de lista de entidades bloqueadas de modprobe para dividir el segundo para incluir la carga diferida de módulos de módulos no esenciales. Se puede aplazar la carga de módulos que usa exclusivamente una HAL específica para cargar los módulos solo cuando se inicia la HAL.
Para mejorar los tiempos de inicio aparente, puedes elegir módulos en la sección
de carga de módulos propicio para la carga después del lanzamiento
en la pantalla. Por ejemplo, puedes cargar de forma explícita tarde los módulos para
decodificador de video o Wi-Fi después de que se haya borrado el flujo de inicio de inicio
(sys.boot_complete
)
como el indicador de propiedad de Android). Asegúrate de que las HALs de carga tardía
Los módulos se bloquean lo suficiente cuando los controladores del kernel no están presentes.
Como alternativa, puedes usar el comando wait<file>[<timeout>]
de init en el archivo de inicio
La secuencia de comandos de Flow rc espera a que las entradas seleccionadas de sysfs
muestren que los módulos del controlador
completaron las operaciones de sondeo. Un ejemplo de esto es esperar a que
mostrar el controlador para completar la carga en segundo plano de la recuperación o fastbootd
antes de presentar los gráficos del menú.
Inicializa la frecuencia de la CPU en un valor razonable en el bootloader
Es posible que no todos los SoC o productos puedan iniciar la CPU con la frecuencia más alta. debido a problemas térmicos o de alimentación durante las pruebas del bucle de inicio. Sin embargo, asegúrate de que el bootloader establece la frecuencia de todas las CPU en línea en un nivel tan alto como seguro para un SoC o producto. Esto es muy importante porque, con una visión kernel modular, la descompresión de ramdisk init se realiza antes de que el controlador de cargas. Por lo tanto, si la CPU se deja en el extremo inferior de su frecuencia, por el bootloader, el tiempo de descompresión del ramdisk puede tardar más kernel compilado de forma estática (después de ajustar la diferencia de tamaño del ramdisk) ya que la frecuencia de la CPU sería muy baja cuando se realizara un trabajo intensivo. (descompresión). Lo mismo se aplica a la memoria y la frecuencia de interconexión.
Inicializa la frecuencia de la CPU grande en el bootloader
Antes de cargar el controlador CPUfreq
, el kernel no reconoce la
las frecuencias de CPU y no ajusta la capacidad
de programación de la CPU para su uso
frecuencia. El kernel puede migrar subprocesos a la CPU grande si la carga se
es lo suficientemente alta
en la CPU pequeña.
Asegúrese de que las CPU grandes tengan, al menos, el mismo rendimiento que las CPU pequeñas para el la frecuencia con la que el bootloader los deja. Por ejemplo, si la CPU grande es 2 veces más eficaz que una CPU pequeña para la misma frecuencia, pero bootloader establece la frecuencia de la CPU pequeña en 1.5 GHz y la frecuencia de la a 300 MHz, el rendimiento del inicio disminuirá si el kernel empieza mueve un subproceso a la CPU grande. En este ejemplo, si es seguro iniciar a 750 MHz, deberías hacerlo incluso si no planeas usarlo explícitamente.
Los controladores no deberían cargar el firmware en el inicio de la primera etapa.
Puede haber algunos casos inevitables en los que primero se deba cargar el firmware. init de la etapa. Pero, en general, los conductores no deberían cargar ningún firmware en la primera etapa especialmente en el contexto de sondeo del dispositivo. Cargando firmware en el inicio de la primera etapa hace que todo el proceso de inicio se detenga si el firmware no está disponible en el en el disco RAM de primera etapa. Incluso si el firmware está presente en la primera etapa ramdisk, aún causa un retraso innecesario.