Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo mejorar el rendimiento de tu juego

Los jugadores disfrutan más de los juegos cuando tienen tiempos de carga breves, una velocidad de fotogramas constante y respuesta de entrada confiable.

Si tienes experiencia en el desarrollo de juegos para computadoras o consolas, es posible que te sorprendas al ver la gran diferencia que hay entre estos dispositivos y los móviles en cuanto a tamaño de GPU y rendimiento de la memoria flash. Esta diferencia de estructura del sistema puede hacer que te resulte difícil predecir el rendimiento de tu juego en Android.

Esta guía te ayudará a optimizar tu juego para que su rendimiento sea lo más confiable posible en la variedad de dispositivos Android en los que se ejecuta. En particular, en esta guía, se explica cómo configurar el registro del sistema de un juego para Android. Luego, se explica cómo puedes usar el informe de resultados de un registro del sistema para ayudarte a tener en cuenta aspectos específicos del rendimiento de tu juego.

Configura un registro del sistema basado en juegos

La herramienta Systrace, que está disponible como programa de línea de comandos y un servicio en el dispositivo, captura un perfil de CPU y subproceso de tu app durante un breve período. Puedes usar los resultados que aparecen en un informe de Systrace para comprender mejor el rendimiento de tu juego en Android y también identificar la mejor manera de optimizar su eficiencia y capacidad de respuesta.

Systrace es una herramienta de bajo nivel que ofrece los siguientes beneficios:

  • Proporciona verdades fundamentales. Systrace captura los resultados directamente del kernel, por lo que las métricas que obtiene son prácticamente idénticas a las que informarían una serie de llamadas al sistema.
  • Consume pocos recursos. Systrace presenta una sobrecarga muy baja para el dispositivo (por lo general, inferior al 1%) debido a que transmite datos dentro de un búfer de la memoria.

Configuración óptima

Independientemente de la manera en que captures el registro del sistema, es importante brindar a la herramienta un conjunto razonable de argumentos, como los siguientes:

  • Categorías: El mejor conjunto de categorías que permitirá realizar un registro del sistema basado en el juego es el siguiente: {sched, freq, idle, am, wm, gfx, view, sync, binder_driver, hal, dalvik}.
  • Tamaño del búfer: Como regla general, un tamaño del búfer de 10 MB por núcleo de CPU permite un registro de aproximadamente 20 segundos de duración. Por ejemplo, si un dispositivo tiene dos CPU con cuatro núcleos (8 núcleos en total), un valor adecuado para pasar al programa systrace sería 80,000 KB (80 MB).

    Sin embargo, si tu juego realiza una gran cantidad de cambios de contexto, deberías aumentar el búfer a 15 MB por núcleo de CPU.

  • Eventos personalizados: Si defines eventos personalizados para capturarlos en tus juegos, habilita la marca -a, que permite a Systrace incluir estos eventos personalizados en el informe de resultados.

Si usas el programa de línea de comandos systrace, usa el siguiente comando para capturar un registro del sistema que aplique prácticas recomendadas para el conjunto de categorías, el tamaño del búfer y los eventos personalizados:

    python systrace.py -a com.example.myapp -b 80000 -o my_systrace_report.html \
      sched freq idle am wm gfx view sync binder_driver hal dalvik
    

Si usas la app del sistema de Systrace en un dispositivo, completa los siguientes pasos para capturar un registro del sistema que aplique prácticas recomendadas para el conjunto de categorías, el tamaño del búfer y los eventos personalizados:

  1. Habilita la opción Registrar aplicaciones depurables.
  2. En Tamaño de búfer, selecciona 65,536 (aproximadamente 64 MB). Ten en cuenta que, para usar esta opción, el dispositivo debe tener 256 MB o 512 MB disponibles (dependiendo de si la CPU tiene 4 u 8 núcleos), y cada porción de memoria de 64 MB debe estar disponible como fragmento continuo.
  3. Elige Categorías y habilita las categorías de la siguiente lista:

    • am: administrador de actividades
    • binder_driver: controlador del kernel de Binder
    • dalvik: máquina virtual Dalvik
    • freq: frecuencia de CPU
    • gfx: gráficos
    • hal: módulos de hardware
    • idle: CPU inactiva
    • sched: programación de CPU
    • sync: sincronización
    • view: sistema de vistas
    • wm: administrador de ventanas
  4. Habilita la opción de seguimiento de registros.

  5. Carga tu juego.

  6. Realiza las interacciones de tu juego que correspondan al rendimiento del dispositivo que quieres medir.

  7. Después de encontrar el comportamiento no deseado en tu juego, desactiva el registro del sistema. Ahora que ya obtuviste las estadísticas de rendimiento, tendrás que analizar el problema en profundidad.

Para ahorrar espacio en el disco, los registros del sistema del dispositivo se guardan en un formato de registro comprimido (*.ctrace). Para descomprimir el archivo al generar un informe, usa el programa de línea de comandos y agrega la opción --from-file:

    python systrace.py --from-file=/data/local/traces/my_game_trace.ctrace \
      -o my_systrace_report.html
    

Mejora áreas de rendimiento específicas

En esta sección, se destacan varias cuestiones de rendimiento comunes de los juegos para dispositivos móviles y se describe cómo identificar y mejorar esos aspectos en tu juego.

Velocidad de carga

Los jugadores quieren meterse en la acción del juego lo antes posible, por eso, es importante que mejores los tiempos de carga de tu juego tanto como puedas. Por lo general, las siguientes medidas ayudan a hacerlo:

  • Realiza una carga diferida. Si usas los mismos elementos en escenas o niveles consecutivos de tu juego, cárgalos solo una vez.
  • Reduce el tamaño de tus elementos. De esa forma, puedes empaquetar versiones sin comprimir de estos elementos con el APK del juego.
  • Usa un método de compresión que haga un uso eficiente del espacio del disco. Por ejemplo, zlib.
  • Usa IL2CPP en lugar de mono. (Solo se aplica si utilizas Unity). IL2CPP ofrece un mejor rendimiento de ejecución para tus secuencias de comandos C#.
  • Haz que tu juego sea multiproceso. Para obtener información detallada, consulta la sección de constancia de la velocidad de fotogramas.

Constancia de la velocidad de fotogramas

Uno de los aspectos más importantes de la experiencia de juego es lograr una velocidad de fotogramas constante. A fin de lograrlo, sigue las técnicas de optimización que se mencionan en esta sección.

Multiproceso

Al desarrollar juegos para varias plataformas, es normal colocar toda la actividad del juego en un solo proceso. Si bien este método de ejecución es fácil de implementar en muchos motores de juegos, no resulta óptimo al ejecutar los juegos en dispositivos Android. Como resultado, los juegos de un solo proceso suelen cargarse lentamente y no tienen una velocidad de fotogramas constante.

El informe de Systrace que se muestra en la figura 1 muestra el comportamiento típico de un juego que se ejecuta en una sola CPU a la vez:

Diagrama de subprocesos dentro de un registro del sistema

Figura 1: Informe de Systrace para un juego de un solo proceso

Para mejorar el rendimiento de tu juego, asegúrate de que tu juego sea multiproceso. Por lo general, el mejor modelo de dos subprocesos:

  • Un subproceso de juego, que contenga los módulos principales del juego y envíe comandos de procesamiento.
  • Un subproceso de procesamiento, que reciba los comandos de procesamiento y los traduzca en comandos de gráfico que una GPU del dispositivo puede usar para mostrar una escena.

La API de Vulkan amplía este modelo gracias a su capacidad de actualizar dos búferes comunes en paralelo. Con esta función, puedes distribuir los subprocesos de procesamiento en varias CPU, lo que mejora el tiempo de procesamiento de una escena.

También puedes realizar los siguientes cambios específicos del motor a fin de mejorar el rendimiento multiproceso:

  • Si vas a desarrollar tu juego con el motor Unity, habilita las opciones Multithreaded Rendering y GPU Skinning.
  • Si usas un motor de procesamiento personalizado, asegúrate de que la canalización de comandos de procesamiento y la canalización de comandos de gráficos estén alineadas correctamente, de lo contrario, podrían producirse retrasos en la visualización de las escenas del juego.

Después de aplicar los cambios, deberías ver que tu juego ocupa al menos 2 CPU en simultáneo, como se muestra en la figura 2.

Diagrama de subprocesos dentro de un registro del sistema

Figura 2: Informe de Systrace para juego multiproceso

Carga de elementos de IU

Diagrama de pila de fotogramas dentro de un registro del sistema
Figura 3: Informe de Systrace para un juego que procesa decenas de elementos de IU al mismo tiempo

Al crear un juego con muchas funciones, resulta tentador mostrar varias opciones y acciones al jugador al mismo tiempo. A fin de mantener la velocidad de fotogramas, es importante tener en cuenta el tamaño pequeño de las pantallas de los dispositivos móviles y crear una IU lo más simple posible.

El informe de Systrace que se muestra en la figura 3 es un ejemplo de fotograma de IU que intenta procesar demasiados elementos para la capacidad de un dispositivo móvil.

Un buen objetivo es reducir el tiempo de actualización de IU a 2 o 3 milisegundos. Para lograr una actualización tan rápida, puedes realizar optimizaciones como las siguientes:

  • Actualiza solo los elementos en pantalla que se hayan movido.
  • Limita la cantidad de texturas y capas de IU. Considera combinar llamadas de gráficos, como sombreadores y texturas, que usan el mismo material.
  • Difiere las operaciones de animación de elementos a la GPU.
  • Realiza un frustum y aprovechamiento de oclusión más pronunciados.
  • Si es posible, realiza operaciones de dibujo con la API de Vulkan. La sobrecarga de llamada de dibujo es más baja en Vulkan.

Consumo de energía

Incluso después de realizar las optimizaciones mencionadas en la sección anterior, es posible que observes que la velocidad de fotogramas de tu juego se deteriora en el transcurso de los primeros 45 o 50 minutos de juego. Además, el dispositivo podría comenzar a recalentarse y consumir más batería con el tiempo.

En muchos casos, este conjunto de aumento de temperatura y consumo de energía está relacionado con la manera en que se distribuye la carga de trabajo del juego en la CPU del dispositivo. Para aumentar la eficiencia de consumo de energía de tu juego, aplica las prácticas recomendadas que aparecen en las siguientes secciones.

Mantén los subprocesos que consumen mucha memoria en una CPU

En muchos dispositivos móviles, las caché L1 residen en CPU específicas y las caché L2 residen en un conjunto de CPU que comparten un reloj. A fin de maximizar los aciertos de caché L1, recomendamos que mantengas el subproceso principal de tu juego, junto con los subprocesos que consumen mucha memoria, ejecutándose en una sola CPU.

Difiere el trabajo de poca duración a CPU con poco consumo de energía

La mayoría de los motores de juegos, incluido Unity, saben diferir las operaciones de subprocesos de trabajo a diferentes CPU en cuanto al subproceso principal del juego. Sin embargo, el motor no conoce la arquitectura específica del dispositivo y no puede anticipar la carga de trabajo de tu juego tan bien como tú.

La mayoría de los dispositivos con sistema en chip tienen al menos 2 relojes compartidos, uno para las CPU rápidas y otro para las CPU lentas del dispositivo. Una consecuencia de esta arquitectura es que, si una CPU rápida necesita operar a máxima velocidad, todas las demás CPU operan a máxima velocidad.

El informe de ejemplo de la figura 4 muestra un juego que aprovecha las CPU rápidas. Sin embargo, este alto nivel de actividad genera un alto consumo de energía y hace que el dispositivo recaliente.

Diagrama de subprocesos dentro de un registro del sistema

Figura 4: Informe de Systrace que informa una asignación por debajo del nivel óptimo de subprocesos a las CPU del dispositivo

Para reducir el consumo general de energía, se recomienda sugerir al programador que se difiera el trabajo de menor duración, como la carga de audio, la ejecución de los subprocesos de trabajo y la ejecución del coreógrafo, al conjunto de CPU lentas del dispositivo. Transfiere tanta carga como sea posible a las CPU lentas a fin de mantener la velocidad de fotogramas deseada.

La mayoría de los dispositivos muestran las CPU lentas antes que las rápidas, pero no puedes asumir que el SoC de tu dispositivo las usa en ese orden. Para comprobarlo, ejecuta comandos similares a los que se muestran en este código de descubrimiento de topología de CPU en GitHub.

Después de saber cuáles son las CPU lentas de tu dispositivo, puedes declarar afinidades para tus subprocesos de menor duración y el programador del dispositivo las seguirá. Para ello, agrega el siguiente código a cada subproceso:

    &num;include <sched.h>
    &num;include <sys/types.h>
    &num;include <unistd.h>

    pid_t my_pid; // PID of the process containing your thread.

    // Assumes that cpu0, cpu1, cpu2, and cpu3 are the "slow CPUs".
    cpu_set_t my_cpu_set;
    CPU_ZERO(&my_cpu_set);
    CPU_SET(0, &my_cpu_set);
    CPU_SET(1, &my_cpu_set);
    CPU_SET(2, &my_cpu_set);
    CPU_SET(3, &my_cpu_set);
    sched_setaffinity(my_pid, sizeof(cpu_set_t), &my_cpu_set);
    

Latencia de la opción tocar para ver

Los juegos que procesan fotogramas lo más rápido posible crean una situación de vinculación con la GPU, en la que el búfer de fotogramas se sobrecarga. La CPU debe esperar a la GPU, lo que provoca un notorio retraso cuando el jugador realiza una entrada y esta surte efecto en la pantalla.

Para determinar si podrías mejorar el ritmo de velocidad de fotogramas de tu juego, completa los siguientes pasos:

  1. Genera un informe de Systrace que incluya las categorías gfx y input. Estas categorías comprenden medidas que resultan particularmente útiles para determinar la latencia de la función tocar para ver.
  2. Revisa la sección SurfaceView de un informe Systrace. Un búfer sobrecargado hace que la cantidad de dibujos de búfer pendientes oscile entre 1 y 2, como se muestra en la figura 5.

    Diagrama de la cola de búfer dentro de un registro del sistema

    Figura 5: Informe de Systrace que muestra un búfer sobrecargado que suele estar demasiado lleno como para aceptar comandos de dibujo

Para mitigar esta falta de constancia en el ritmo de fotogramas, completa las acciones que se describen en las siguientes secciones:

Integra la API de ritmo de fotogramas de Android a tu juego

La API de ritmo de fotogramas te ayuda a realizar intercambios de fotogramas y definir un intervalo de intercambio para que tu juego mantenga una velocidad de fotogramas más constante.

Reduce la resolución de los elementos que no son IU de tu juego

Las pantallas de los dispositivos modernos contienen muchos más píxeles de los que puede procesar un jugador, por lo que está bien reducir el muestreo de manera que una ejecución de 5 o 10 píxeles contenga un color. Debido a la estructura de la mayoría de las caché, se recomienda reducir la resolución junto con una dimensión solamente.

Sin embargo, no debes reducir la resolución de los elementos de IU de tu juego. Es importante conservar el espesor de las líneas de esos elementos a fin de mantener un tamaño objetivo del elemento táctil lo suficientemente grande para todos tus jugadores.

Suavidad de procesamiento

Cuando SurfaceFlinger se conecta a un búfer de pantalla para mostrar una escena de tu juego, la actividad de CPU aumenta temporalmente. Si estos picos de actividad de CPU no se producen de manera pareja, es posible que veas trabas en tu juego. El diagrama de la figura 6 muestra el motivo.

Diagrama de fotogramas al que le falta una ventana de Vsync porque comenzó a procesar demasiado tarde

Figura 6: Informe de Systrace que muestra la manera en que un fotograma puede perder un Vsync

Si un fotograma comienza a dibujarse demasiado tarde, incluso por unos milisegundos, podría perderse la siguiente ventana de visualización. Entonces, el fotograma debe esperar a que se muestre el próximo Vsync (33 milisegundos al ejecutar un juego a 30 FPS), lo que produce un notable retraso desde la perspectiva del jugador.

Para resolver esta situación, usa la API de ritmo de fotogramas de Android, que siempre presenta un nuevo fotograma en una fuente de onda de Vsync.

Estado de la memoria

Al ejecutar tu juego por un período de tiempo prolongado, es posible que el dispositivo tenga errores de falta de memoria.

Es esa situación, comprueba la actividad de CPU en un informe de Systrace y consulta la frecuencia con la que el sistema realiza llamadas al daemon kswapd. Si hay muchas llamadas durante la ejecución del juego, te recomendamos observar la manera en que tu juego administra y limpia la memoria.

Para obtener más información, consulta Cómo administrar de manera eficaz la memoria en juegos.

Estado de subprocesos

Cuando navegas por los elementos típicos de un informe de Systrace, puedes ver la cantidad de tiempo que un subproceso determinado dedica en cada posible estado del subproceso. Para ello, selecciona el subproceso en el informe, como se muestra en la figura 7.

Diagrana de un informe de Systrace

Figura 7: Informe de Systrace que muestra cómo la selección de un subproceso hace que el informe muestre un resumen de estado para ese subproceso

Como se muestra en la figura 7, es posible que veas que los subprocesos de tu juego no se encuentran en estado "en ejecución" o "ejecutable" con la frecuencia que deberían. En la siguiente lista, se muestran varios motivos comunes acerca de por qué un subproceso determinado podría pasar en forma periódica a un estado inusual:

  • Si un subproceso se encuentra inactivo durante mucho tiempo, es posible que esté experimentando una competencia de bloqueo o esperando a la actividad de GPU.
  • Si un subproceso está bloqueado constantemente en I/O, quiere decir que estás leyendo demasiados datos de un disco al mismo tiempo o que la paginación del juego es excesiva.

Recursos adicionales

Para obtener más información sobre cómo mejorar el rendimiento de tu juego, consulta los siguientes recursos adicionales:

Videos