Valoramos tu privacidad. Usamos cookies para mejorar tu experiencia en nuestro sitio. Al usar este sitio, aceptas nuestra Política de Privacidad.

Cómo Perfilamos Aplicaciones WebXR/WebGL

Cómo Perfilamos Aplicaciones WebXR/WebGL

Este artículo cubre métodos para perfilar aplicaciones WebXR y WebGL (independientemente del framework subyacente). El perfilado es el primer paso para optimizar tu aplicación. Optimizar sin perfilar es un esfuerzo desperdiciado, como se describe en Cuellos de Botella.

Ten en cuenta que este post no aborda cómo solucionar los problemas de rendimiento encontrados. Hay muchos posts de blog y charlas dirigidas a cuellos de botella específicos, pero una vez que sepas cuál es el problema, encontrarás recursos para ello.

Las métricas que vamos a perfilar son el tiempo de CPU, tiempo de GPU, memoria heap de JavaScript, y tiempo de carga de la aplicación. El objetivo es proporcionar la colección más completa de información sobre perfilado gratis. Y no: “conteo de polígonos” no es una métrica que nos importe.

Contenidos 

Cuellos de Botella 

Sin encontrar el cuello de botella de tu aplicación, tus esfuerzos de optimización no serán efectivos.

Ejemplo 

Imagina que estás renderizando una gran escena con muchos objetos. Tu aplicación apenas alcanza los 60 fps. Puedes optimizar el conteo de vértices de cada objeto y aún así permanecer en 60 fps.

El CPU es responsable de enviar al GPU el comando para renderizar cada objeto (“Draw Call”). En este caso, es mucho más probable que el CPU esté sobrecargado con el trabajo de enviar las llamadas de dibujo, mientras que el GPU sólo espera más trabajo del CPU.

Pero no lo sabemos… hasta que medimos. Eso es para lo que sirve el Perfilado.

Tipos de Cuellos de Botella 

Cualquier parte de una aplicación puede provocar un cuello de botella. Aquí tienes algunos ejemplos de cuellos de botella comunes en orden de frecuencia:

CPU Draw Calls: Demasiadas llamadas al controlador generan un gran overhead.

Basura: La aplicación funciona bien, pero genera basura que causa ralentizaciones a intervalos regulares o irregulares.

Lógica del CPU: Tu aplicación no puede generar suficiente trabajo para el GPU rápidamente. A menudo causado por simulaciones físicas intensas o rayos lanzados.

Sombreado de Fragmentos de GPU: El costo de rendimiento por fragmento es muy alto.

Procesamiento de Vértices de GPU: El requerimiento de procesamiento por vértice es muy alto.

Resolución de GPU: Causado por post-procesamiento en GPUs móviles.

Extracción de Vértices de GPU: La memoria para los vértices no se lee lo suficientemente rápido.

Cada uno podría tener sub-cuellos de botella.

Métricas 

Las métricas que vamos a perfilar son:

Tiempo de CPU 

El trabajo para cualquier aplicación XR se divide entre CPU y GPU. El CPU es responsable de preparar el trabajo gráfico para que el GPU lo renderice y ejecutar la lógica de tu aplicación.

Cualquier código JavaScript se ejecutará en el CPU para preparar las llamadas de dibujo, realizar carga de recursos, simular física, renderizar audio y calcular transformaciones del grafo de escena.

Tiempo de GPU 

El GPU es responsable del trabajo gráfico pesado. Mientras que el CPU envía una llamada de dibujo con algo como “dibujar malla X con shader Y con textura Z y parámetros de material W”, el GPU realiza la rasterización real y las transformaciones por vértice para producir los píxeles en la pantalla.

El GPU también se encarga de enviar la imagen final a la pantalla, esperando “V-Sync” que sincroniza la tasa de refresco de la pantalla con la de la aplicación.

Tasa de Fotogramas y V-Sync 

Nosotros no utilizamos la tasa de fotogramas (fps) para perfilar nuestra aplicación.

Esta métrica solo se menciona para explicar la complejidad de entender cómo el rendimiento interactúa con V-Sync. Es demasiado básica para hacer juicios útiles.

Considera V-Sync como plazos fijos: 60, 72, 90 o más plazos por segundo (la tasa de fotogramas). Nos referiremos a “hacer V-Sync” como haber renderizado y enviado el cuadro a tiempo para cumplir el plazo.

Cuando no cumples el plazo, todo tu trabajo se descarta y debes intentar alcanzar el próximo plazo. En entornos con tasa de fotogramas flexible, esto puede significar que tus controladores te reduzcan a la mitad de la tasa de fotogramas.

Si tu aplicación es apenas lo suficientemente lenta, esto significa que estarías viendo por ejemplo 30 fps en lugar de 59 fps, contando una historia completamente diferente. Tal vez tu aplicación esté funcionando decentemente con 3 ms de CPU y 3 ms de GPU, pero porque el trabajo empieza tarde, te pierdes la V-Sync para tu tasa de fotogramas objetivo, lo que reduce tu tasa de fotogramas efectiva a la mitad. Ningún conteo de vértices, llamada de dibujo u optimización clásica te ayudará aquí.

Latencia 

La latencia, el tiempo entre la entrada (por ejemplo, el movimiento de la cabeza) y el cuadro terminado, es especialmente importante para VR. Generalmente, las implementaciones de WebXR se encargan de esto por nosotros y podrían programar los callbacks de cuadro un poco más tarde, si no usamos nuestro presupuesto de fotogramas, para reducir la latencia. Tenemos un control limitado sobre esto desde WebXR y, por lo tanto, no lo cubriremos en esta publicación.

Recolección de Basura 

JavaScript incluye gestión de memoria que te permite manejar las asignaciones de manera despreocupada y sin preocupación. Por ello, es común hacer esto.

Sin la necesidad de administrar la memoria, pierdes el control para especificar cuándo deseas que tu memoria sea gestionada. Este proceso se llama “Recolección de Basura” y ocurrirá en momentos aleatorios en el ciclo de vida de tu aplicación, por ejemplo, cuando acabas de cumplir con V-Sync y estabas a punto de enviar tu cuadro.

La recolección de basura puede tomar de 0.1 a 10 ms. Dado que el presupuesto habitual de fotograma para VR es de 11 ms, absolutamente no quieres que esto suceda en momentos aleatorios.

Entonces, ¿cómo lo evitamos? La única forma es evitar cualquier basura que requiera limpieza. Cuanto menos produzcas, más pequeñas y raras serán las interrupciones de la recolección de basura.

Tiempo de Carga de la Aplicación 

Al igual que con la carga de sitios web, el compromiso del usuario con tu aplicación disminuye con cada segundo que pasa esperando. Dado que las aplicaciones WebXR son bastante grandes, podría haber un poco más de buena voluntad aquí comparado con un sitio web, pero no hay necesidad de ello.

Iniciando la aplicación temprano y cargando recursos que no se necesitan inmediatamente más tarde, podemos reducir el tiempo de carga percibido.

Al optimizar los assets y asegurarnos de que la configuración de nuestro servidor sea óptima, podemos reducir el tiempo de carga en general.

Y usando formatos que requieren menos análisis, podemos reducir la cantidad de trabajo que el CPU necesita hacer tras descargar los recursos.

Herramientas 

En este post, cubriremos las siguientes herramientas:

Chrome Profiler 

El profiler integrado de Chrome te permitirá perfilar tu tiempo de CPU de JavaScript, Recolección de Basura, y de manera muy aproximada tu tiempo de cuadro de GPU.

Puedes encontrar la pestaña Rendimiento navegando a cualquier sitio web y presionando Ctrl + Shift + C (Command + Shift + C en MacOS). Encuentra “Rendimiento” allí. Para grabar una sesión de perfil, pulsa el botón de grabar en la parte superior izquierda (Ctrl/Command + E). 3-5 segundos suelen ser completamente suficientes ya que generalmente nos interesan cuadros individuales.

Esto también funciona cuando se realiza Depuración Remota en Dispositivos Android como Meta Quest o tu smartphone.

Safari tiene un profiler similar para dispositivos Mac, iOS y el Apple Vision PRO (por ejemplo, con Safari ejecutándose en el simulador de Apple Vision PRO).

Banner de Perfilado WebXR.

Chrome Memory Profiler 

En Recolección de Basura describimos las interrupciones en aplicaciones que de otro modo funcionan sin problemas.

Para encontrar ese cuello de botella, los navegadores proporcionan una forma de muestrear el Heap de JavaScript. Así es como lo habilitas en Chrome desde el Chrome Profiler descrito anteriormente:

Cómo Perfilamos Aplicaciones WebXR/WebGL

Ejemplo 

A continuación, se muestra un perfil en Meta Quest 2 de Elysian, basado en Three.js:

Cómo Perfilamos Aplicaciones WebXR/WebGL

Puedes ver que el “JS Heap” fluctúa entre 14.1 MB y 23.3 MB.

Allí donde la memoria cae repentinamente, encontramos que ocurre la Recolección de Basura. En este caso, el GC es tan grande que retrasa el inicio del siguiente cuadro, haciendo que se pierda un cuadro:

Cómo Perfilamos Aplicaciones WebXR/WebGL

Como resultado, debemos esperar que el cuadro perdido sea reproyectado desde el último cuadro, de lo contrario, ocurrirá un tartamudeo significativo. Dado que las animaciones no pueden ser reproyectadas, habrá algo de tartamudez de cualquier manera.

Pestaña de Red 

La pestaña de red de cualquier navegador es una excelente herramienta para perfilar el tiempo de carga de tu aplicación.

Puedes encontrar la pestaña de Red navegando a cualquier sitio web y presionando Ctrl + Shift + C (Command + Shift + C en MacOS). Encuentra “Red” allí. Para grabar la actividad de red, recarga la página mientras tienes la pestaña abierta.

Descargas Bloqueadas 

Si un recurso no se necesita inmediatamente al inicio de la aplicación, debe cargarse más tarde, ya que los navegadores solo realizarán solicitudes paralelas limitadas a la vez (por ejemplo, 6 para Chrome).

Cómo Perfilamos Aplicaciones WebXR/WebGL

Meta Quest Performance HUD 

Al perfilar la representación VR en el Meta Quest, puedes usar el Performance HUD.

Se instala más fácilmente a través del Meta Quest Developer Hub.

Esto es especialmente útil para depurar problemas de rendimiento dependientes de la vista, ya que puedes usar el casco mientras obtienes retroalimentación continua sobre el rendimiento.

Ejemplo 

En el siguiente ejemplo, Ayushman Johri muestra el excelente rendimiento de su “Vintage Study Room” basado en Wonderland Engine utilizando el Meta Quest Performance HUD:

OVR GPU Profiler 

Si te encuentras con cuellos de botella de sombreado de vértices o fragmentos, apreciarás una comprensión más clara de qué toma más tiempo en tus shaders.

El ovrgpuprofiler es una herramienta muy precisa. Si tienes alguna comprensión sobre la memoria del GPU y su arquitectura, te proporciona mucha perspectiva.

Se ejecuta instalándolo en tu casco Meta Quest a través de adb y ejecutándolo mediante adb shell:

 1    47 métricas soportadas:
 2    1       Relojes / Segundo
 3    2       % GPU Bus Ocupado
 4    3       % Estancamiento de Extracción de Vértices
 5    4       % Estancamiento de Extracción de Textura
 6    5       Fallos de Caché de Textura L1 por Píxel
 7    6       % Fallo de L1 de Textura
 8    7       % Fallo de L2 de Textura
 9    8       % Estancado en Memoria del Sistema
10    9       Polígonos Pre-recortados/Segundo
11    10      % Prims Rechazados Trivialmente
12    11      % Prims Recortados

(Fuente: developer.oculus.com)

El ejemplo de salida se verá de la siguiente manera:

 1$ adb shell ovrgpuprofiler -r"4,5,6"
 2
 3% Estancamiento de Extracción de Textura         :           2.449
 4Fallos de Caché de Textura L1 por Píxel          :           0.124
 5% Fallo de L1 de Textura                         :          20.338
 6
 7% Estancamiento de Extracción de Textura         :           2.369
 8Fallos de Caché de Textura L1 por Píxel          :           0.122
 9% Fallo de L1 de Textura                         :          20.130
10
11% Estancamiento de Extracción de Textura         :           2.580
12Fallos de Caché de Textura L1 por Píxel          :           0.127
13% Fallo de L1 de Textura
14
15...

(Modificado de: developer.oculus.com)

Leerás con frecuencia que las operaciones de lectura y escritura en memoria son generalmente las más costosas en un programa de shader. Sin embargo, si esto es cierto, depende de qué tan amigables con el caché sean tus operaciones de memoria.

La memoria de caché L1 (“Nivel 1”) es increíblemente rápida. Para asegurarte de que la estás utilizando, asegúrate de obedecer el principio de localidad: accede a memoria que está cerca de la memoria que accesaste previamente.

Spector.js 

Spector.js es una extensión del navegador para Chrome y Firefox que permite capturar trazas de cuadros de WebGL. La herramienta puede mostrar la lista completa de comandos y resumir estadísticas como conteo de vértices y llamadas de dibujo.

Instálala desde la Tienda de Extensiones de Chrome o la Biblioteca de Complementos de Firefox. También puedes integrar la herramienta mediante una etiqueta HTML para navegadores sin soporte de plugins.

Cómo Perfilamos Aplicaciones WebXR/WebGL

Primero habilita la herramienta a través del botón de complementos en la parte superior, luego graba un cuadro haciendo clic en el botón rojo de grabar.

Cómo Perfilamos Aplicaciones WebXR/WebGL

Puedes ver que Wonderland Engine está dibujando muchos objetos en un total de 11 llamadas de dibujo aquí. Para cualquier otro framework, este número será de 10 a 100 veces más alto.

Disjoint Timer Query 

La extensión EXT_disjoint_timer_query es una extensión de WebGL que permite medir el tiempo de GPU de un conjunto de comandos WebGL. Solo es bien soportado en Chrome [agosto de 2023] y si se habilita la opción “Extensiones de Depuración de WebGL” en Chrome.

Dado que todos los comandos se ejecutan de forma asíncrona en el GPU, las mediciones de tiempo también deben programarse asíncronamente.

Profiler del Editor de Wonderland 

El Editor de Wonderland viene con una herramienta de perfilado incorporada que ayuda a entender dónde podría estar sufriendo el rendimiento de tu aplicación WebXR.

Cómo Perfilamos Aplicaciones WebXR/WebGL

Palabras Finales 

Cada framework tiene sus propias características de rendimiento. La mayoría están limitados por llamadas de dibujo antes que cualquier otra cosa, y luego ligados a fragmentos, ¡no hay necesidad de bajar polígonos si no alcanzas los 90 fps!

Diseñamos Wonderland Engine desde cero para evitar la mayoría de los cuellos de botella mencionados– es gratis hasta 120k USD en ingresos por año. Contáctanos aquí para Licencias Empresariales y Soporte.

Prueba Wonderland Engine ahora y comienza a ahorrar tiempo optimizando.

Cómo Perfilamos Aplicaciones WebXR/WebGL
Last Update: March 28, 2025

Mantente al día.