Usa Simpleperf para evaluar el rendimiento de un dispositivo. Simpleperf es una herramienta de generación de perfiles nativa para apps y procesos nativos en Android. Usa el Generador de perfiles de CPU para inspeccionar el uso de la CPU de la app y la actividad de subprocesos en tiempo real.
Existen dos indicadores de rendimiento visibles para el usuario:
- Rendimiento predecible y perceptible ¿La interfaz de usuario (IU) descarta fotogramas o se renderiza de forma coherente a 60 FPS? ¿El audio se reproduce sin artefactos ni chasquidos? ¿Cuánto tiempo transcurre entre que el usuario toca la pantalla y el efecto se muestra en la pantalla?
- Tiempo necesario para operaciones más largas (como abrir apps)
El primero es más notable que el segundo. Por lo general, los usuarios notan el jank, pero no podrán distinguir entre un tiempo de inicio de la app de 500 ms y uno de 600 ms, a menos que estén mirando dos dispositivos uno al lado del otro. La latencia táctil se nota de inmediato y contribuye significativamente a la percepción de un dispositivo.
Como resultado, en un dispositivo rápido, la canalización de IU es lo más importante del sistema, además de lo necesario para mantenerla funcional. Esto significa que la canalización de la IU debe interrumpir cualquier otro trabajo que no sea necesario para una IU fluida. Para mantener una IU fluida, la sincronización en segundo plano, la entrega de notificaciones y el trabajo similar deben retrasarse si se puede ejecutar el trabajo de la IU. Es aceptable sacrificar el rendimiento de las operaciones más largas (tiempo de ejecución de HDR+, inicio de la app, etcétera) para mantener una IU fluida.
Capacidad en comparación con la fluctuación
Cuando se considera el rendimiento del dispositivo, la capacidad y la fluctuación son dos métricas significativas.
Capacidad
La capacidad es la cantidad total de un recurso que posee el dispositivo durante un período determinado. Pueden ser recursos de CPU, recursos de GPU, recursos de E/S, recursos de red, ancho de banda de memoria o cualquier métrica similar. Cuando se examina el rendimiento de todo el sistema, puede ser útil abstraer los componentes individuales y suponer una sola métrica que determine el rendimiento (especialmente cuando se ajusta un dispositivo nuevo, ya que es probable que las cargas de trabajo que se ejecutan en ese dispositivo sean fijas).
La capacidad de un sistema varía según los recursos de procesamiento en línea. Cambiar la frecuencia de la CPU o la GPU es el principal medio para cambiar la capacidad, pero hay otros, como cambiar la cantidad de núcleos de CPU en línea. En consecuencia, la capacidad de un sistema se corresponde con el consumo de energía: cambiar la capacidad siempre genera un cambio similar en el consumo de energía.
La capacidad requerida en un momento determinado está determinada en gran medida por la app en ejecución. Como resultado, la plataforma puede hacer poco para ajustar la capacidad requerida para una carga de trabajo determinada, y los medios para hacerlo se limitan a las mejoras en el tiempo de ejecución (framework de Android, ART, Bionic, compilador/controladores de GPU, kernel).
Jitter
Si bien la capacidad requerida para una carga de trabajo es fácil de ver, la fluctuación es un concepto más nebuloso. Para obtener una buena introducción a la fluctuación como impedimento para los sistemas rápidos, te recomendamos que leas el documento titulado The Case of the Missing Supercomputer Performance: Achieving Optimal Performance on the 8,192 processors of ASCI Q. (Es una investigación sobre por qué la supercomputadora ASCI Q no alcanzó el rendimiento esperado y es una excelente introducción a la optimización de sistemas grandes).
En esta página, se usa el término fluctuación para describir lo que el documento de ASCI Q denomina ruido. La fluctuación es el comportamiento aleatorio del sistema que impide que se ejecute el trabajo perceptible. A menudo, es trabajo que se debe ejecutar, pero es posible que no tenga requisitos de sincronización estrictos que hagan que se ejecute en un momento determinado. Debido a que es aleatorio, es extremadamente difícil refutar la existencia de fluctuaciones para una carga de trabajo determinada. También es muy difícil demostrar que una fuente conocida de fluctuaciones fue la causa de un problema de rendimiento en particular. Las herramientas que se usan con mayor frecuencia para diagnosticar las causas de la fluctuación (como el registro o el seguimiento) pueden introducir su propia fluctuación.
Las fuentes de fluctuaciones que se experimentan en las implementaciones del mundo real de Android incluyen las siguientes:
- Retraso del programador
- Controladores de interrupciones
- El código del controlador se ejecuta durante demasiado tiempo con la preferencia o las interrupciones inhabilitadas
- Softirqs de larga duración
- Contención de bloqueo (app, framework, controlador del kernel, bloqueo de Binder, bloqueo de mmap)
- Contención del descriptor de archivos en la que un subproceso de baja prioridad mantiene el bloqueo en un archivo, lo que impide que se ejecute un subproceso de alta prioridad
- Ejecutar código crítico para la IU en workqueues en las que podría retrasarse
- Transiciones de inactividad de la CPU
- Registro
- Demoras de E/S
- Creación de procesos innecesarios (por ejemplo, transmisiones de
CONNECTIVITY_CHANGE
) - El intercambio excesivo de la caché de páginas se debe a la falta de memoria libre.
La cantidad de tiempo requerida para un período determinado de fluctuación puede disminuir o no a medida que aumenta la capacidad. Por ejemplo, si un controlador deja las interrupciones inhabilitadas mientras espera una lectura a través de un bus I²C, tardará una cantidad fija de tiempo, independientemente de si la CPU está a 384 MHz o a 2 GHz. Aumentar la capacidad no es una solución factible para mejorar el rendimiento cuando hay fluctuaciones. Como resultado, los procesadores más rápidos no suelen mejorar el rendimiento en situaciones con restricciones de fluctuación.
Por último, a diferencia de la capacidad, la fluctuación se encuentra casi por completo dentro del dominio del proveedor del sistema.
Consumo de memoria
Tradicionalmente, se culpa al consumo de memoria por el bajo rendimiento. Si bien el consumo en sí no es un problema de rendimiento, puede causar fluctuaciones a través de la sobrecarga de lowmemorykiller, los reinicios de servicios y el thrashing de la caché de páginas. Reducir el consumo de memoria puede evitar las causas directas del bajo rendimiento, pero puede haber otras mejoras específicas que también eviten esas causas (por ejemplo, fijar el framework para evitar que se pagine cuando se paginará poco después).
Analiza el rendimiento inicial del dispositivo
Comenzar con un sistema funcional, pero con un rendimiento deficiente, y tratar de corregir su comportamiento analizando casos individuales de rendimiento deficiente visible para el usuario no es una estrategia sólida. Dado que el rendimiento deficiente no suele ser fácil de reproducir (es decir, fluctuaciones) ni un problema de la app, demasiadas variables en el sistema completo impiden que esta estrategia sea eficaz. Como resultado, es muy fácil identificar erróneamente las causas y realizar mejoras menores sin aprovechar las oportunidades sistémicas para corregir el rendimiento en todo el sistema.
En su lugar, usa el siguiente enfoque general cuando pongas en funcionamiento un dispositivo nuevo:
- Haz que el sistema se inicie en la IU con todos los controladores en ejecución y algunos parámetros de configuración básicos del gobernador de frecuencia (si cambias la configuración del gobernador de frecuencia, repite todos los pasos que se indican a continuación).
- Asegúrate de que el kernel admita el punto de seguimiento
sched_blocked_reason
, así como otros puntos de seguimiento en la canalización de la pantalla que indiquen cuándo se entrega el fotograma a la pantalla. - Toma registros largos de toda la canalización de la IU (desde la recepción de la entrada a través de una IRQ hasta el escaneo final) mientras ejecutas una carga de trabajo ligera y coherente (por ejemplo, UiBench o la prueba de la pelota en TouchLatency).
- Corrige las pérdidas de fotogramas detectadas en la carga de trabajo ligera y coherente.
- Repite los pasos 3 y 4 hasta que puedas correr sin pérdida de fotogramas durante más de 20 segundos seguidos.
- Continúa con otras fuentes de tirones visibles para el usuario.
Otras cosas simples que puedes hacer al principio de la puesta en marcha del dispositivo incluyen las siguientes:
- Asegúrate de que tu kernel tenga el parche de puntos de seguimiento sched_blocked_reason. Este punto de seguimiento se habilita con la categoría de seguimiento sched en systrace y proporciona la función responsable de la suspensión cuando ese subproceso entra en suspensión no interrumpible. Es fundamental para el análisis del rendimiento, ya que el sueño ininterrumpido es un indicador muy común de la fluctuación.
- Asegúrate de tener suficiente registro para las canalizaciones de GPU y pantalla. En los SOC de Qualcomm recientes, los puntos de seguimiento se habilitan con el siguiente comando:
adb shell "echo 1 > /d/tracing/events/kgsl/enable"
adb shell "echo 1 > /d/tracing/events/mdss/enable"
Estos eventos permanecen habilitados cuando ejecutas systrace, por lo que puedes ver información adicional en el registro sobre la canalización de pantalla (MDSS) en la sección mdss_fb0
. En los SoC de Qualcomm, no verás información adicional sobre la GPU en la vista estándar de systrace, pero los resultados están presentes en el registro (para obtener más detalles, consulta Cómo comprender systrace).
Lo que deseas obtener de este tipo de registro de pantalla es un solo evento que indique directamente que se entregó un fotograma a la pantalla. Desde allí, puedes determinar si alcanzaste el tiempo de fotograma correctamente. Si el evento Xn ocurre menos de 16.7 ms después del evento Xn-1 (suponiendo una pantalla de 60 Hz), sabrás que no hubo tirones. Si tu SOC no proporciona esos indicadores, trabaja con tu proveedor para obtenerlos. Depurar el Jitter es extremadamente difícil sin un indicador definitivo de la finalización del fotograma.
Usa comparativas sintéticas
Las comparativas sintéticas son útiles para garantizar que la funcionalidad básica de un dispositivo esté presente. Sin embargo, no es útil tratar las comparativas como un proxy del rendimiento percibido del dispositivo.
Según la experiencia con los SoC, las diferencias en el rendimiento de las comparativas sintéticas entre los SoC no se correlacionan con una diferencia similar en el rendimiento perceptible de la IU (cantidad de fotogramas descartados, tiempo de fotogramas del percentil 99, etcétera). Las comparativas sintéticas son comparativas solo de capacidad. La fluctuación afecta el rendimiento medido de estas comparativas solo al quitar tiempo de la operación masiva de la comparativa. Por lo tanto, las puntuaciones de las comparativas sintéticas son, en su mayoría, irrelevantes como métrica del rendimiento percibido por el usuario.
Considera dos SoC que ejecutan Benchmark X, que renderiza 1,000 fotogramas de la IU y registra el tiempo total de renderización (cuanto menor sea la puntuación, mejor).
- SOC 1 renderiza cada fotograma de Benchmark X en 10 ms y obtiene una puntuación de 10,000.
- El SOC 2 renderiza el 99% de los fotogramas en 1 ms, pero el 1% de los fotogramas en 100 ms, y obtiene una puntuación de 19,900, que es mucho mejor.
Si la comparativa es indicativa del rendimiento real de la IU, SOC 2 sería inutilizable. Si se supone una frecuencia de actualización de 60 Hz, SOC 2 tendría un fotograma con interrupciones cada 1.5 s de funcionamiento. Mientras tanto, SOC 1 (el SOC más lento según Benchmark X) sería perfectamente fluido.
Cómo usar los informes de errores
A veces, los informes de errores son útiles para el análisis del rendimiento, pero, debido a que son tan pesados, rara vez son útiles para depurar problemas de tirones esporádicos. Pueden proporcionar algunas pistas sobre lo que estaba haciendo el sistema en un momento determinado, en especial si el jank se produjo durante una transición de la app (que se registra en un informe de errores). Los informes de errores también pueden indicar cuándo algo está mal en general con el sistema, lo que podría reducir su capacidad efectiva (como la regulación térmica o la fragmentación de la memoria).
Cómo usar TouchLatency
Varios ejemplos de mal comportamiento provienen de TouchLatency, que es la carga de trabajo periódica preferida que se usa para el Pixel y el Pixel XL. Está disponible en frameworks/base/tests/TouchLatency
y tiene dos modos: latencia táctil y pelota que rebota (para cambiar de modo, haz clic en el botón de la esquina superior derecha).
La prueba de la pelota que rebota es tan simple como parece: una pelota rebota por la pantalla sin parar, independientemente de la entrada del usuario. Por lo general, también es con diferencia la prueba más difícil de ejecutar a la perfección, pero cuanto más se acerque a ejecutarse sin fotogramas descartados, mejor será tu dispositivo. La prueba de la pelota que rebota es difícil porque es una carga de trabajo trivial, pero perfectamente coherente, que se ejecuta a una velocidad de reloj muy baja (esto supone que el dispositivo tiene un regulador de frecuencia; si el dispositivo se ejecuta con relojes fijos, reduce la velocidad de la CPU/GPU a cerca del mínimo cuando ejecutes la prueba de la pelota que rebota por primera vez). A medida que el sistema se detiene y los relojes se acercan al estado de inactividad, aumenta el tiempo de CPU/GPU requerido por fotograma. Puedes mirar la pelota y ver cómo se producen tirones, y también podrás ver los fotogramas perdidos en systrace.
Debido a que la carga de trabajo es tan constante, puedes identificar la mayoría de las fuentes de fluctuación con mucha más facilidad que en la mayoría de las cargas de trabajo visibles para el usuario, ya que puedes hacer un seguimiento de lo que se ejecuta exactamente en el sistema durante cada fotograma perdido en lugar de la canalización de la IU. Los relojes más bajos amplifican los efectos de la fluctuación, ya que aumentan la probabilidad de que cualquier fluctuación provoque una pérdida de fotogramas. Como resultado, cuanto más cerca esté TouchLatency de 60 FPS, es menos probable que tengas comportamientos incorrectos del sistema que causen tirones esporádicos y difíciles de reproducir en apps más grandes.
Dado que la fluctuación a menudo (pero no siempre) es independiente de la velocidad del reloj, usa una prueba que se ejecute a velocidades muy bajas para diagnosticar la fluctuación por los siguientes motivos:
- No todas las fluctuaciones son invariantes a la velocidad de reloj; muchas fuentes solo consumen tiempo de CPU.
- El gobernador debe acercar el tiempo promedio de fotogramas a la fecha límite reduciendo la velocidad del reloj, de modo que el tiempo dedicado a ejecutar el trabajo que no es de la IU pueda llevarlo al límite y provocar la pérdida de un fotograma.