El camino recorrido hasta ahora
Hace un año, Chrome anunció la compatibilidad inicial para la depuración nativa de WebAssembly en las Herramientas para desarrolladores de Chrome.
Demostramos apoyo básico para dar pasos y hablamos sobre oportunidades el uso de información DWARF en lugar de los mapas de origen estarán disponibles para nosotros en el futuro:
- Resuelve nombres de variables
- Tipos de impresión con formato estilístico
- Evaluar expresiones en idiomas de origen
- ...y mucho más
Hoy nos complace mostrar cómo cobran vida las funciones prometidas. y el progreso que lograron los equipos de Emscripten y Chrome DevTools con los este año, en particular, para las apps de C y C++.
Antes de comenzar, ten en cuenta que esta todavía es una versión beta de la nueva experiencia, debes usar la versión más reciente de todas las herramientas bajo tu propio riesgo y, si tienes algún problema, infórmalo a https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Empecemos con el mismo ejemplo de C simple de la última vez:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Para compilarlo, usamos la versión más reciente de Emscripten y pasamos una marca -g
, al igual que en la publicación original, para incluir información de depuración:
emcc -g temp.c -o temp.html
Ahora podemos entregar la página generada desde un servidor HTTP localhost (para ejemplo, con serve) ábrelo en la versión más reciente de Chrome Canary.
Esta vez, también necesitaremos una extensión de ayuda que se integre con Chrome. las Herramientas para desarrolladores y le ayuda a comprender toda la información de depuración codificadas en el archivo WebAssembly. Para instalarla, ve a este vínculo: goo.gle/wasm-debugging-extension
También querrás habilitar la depuración de WebAssembly en las Herramientas para desarrolladores Experimentos. Abre las Herramientas para desarrolladores de Chrome y haz clic en el ícono de ajustes (⚙) en la esquina superior derecha del panel de Herramientas para desarrolladores, ve al panel Experimentos (Experiments). y marca WebAssembly Debugging: Enable DWARF support.
Cuando cierres Settings, las Herramientas para desarrolladores te sugerirán que se vuelvan a cargar para aplicar la configuración, así que hagámoslo. Eso es todo por una sola vez configuración.
Ahora, podemos volver al panel Sources, habilitar Pause on excepciones (⏸), luego marca Pausar en excepciones detectadas y vuelve a cargar la página. Deberías ver DevTools detenido en una excepción:
De forma predeterminada, se detiene en un código de adhesión generado por Emscripten, pero en la
derecha, podrás ver una vista de Call Stack que representa el seguimiento de pila de
el error, y navegar a la línea C original que invocó
abort
:
Ahora, si miras en la vista Alcance, puedes ver los nombres originales.
y valores de variables en el código C/C++, y ya no tendrás que determinar
qué significan los nombres alterados como $localN
y cómo se relacionan con
el código fuente que escribiste.
Esto se aplica no solo a valores primitivos como números enteros, como estructuras, clases, arrays, etc.
Compatibilidad con tipos enriquecidos
Veamos un ejemplo más complicado para mostrarlas. Esta dibujaremos un fractal de Mandelbrot con el siguiente código C++:
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
Puedes ver que esta aplicación sigue siendo bastante pequeña (es un solo archivo que contiene 50 líneas de código), pero esta vez también uso algunas APIs externas, como la biblioteca SDL para gráficos, así como números complejos de la biblioteca estándar de C++.
Lo compilaré con la misma marca -g
que está más arriba para incluirla
información de depuración. Además, le pediré a Emscripten que proporcione el SDL2
y permiten una memoria de tamaño arbitrario:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Cuando visito la página generada en el navegador, puedo ver la hermosa forma fractal con algunos colores aleatorios:
Cuando abro Herramientas para desarrolladores, una vez más, puedo ver el archivo C++ original. Esta Sin embargo, no hay errores en el código (¡Uf!), así que algún punto de interrupción al principio del código.
Cuando volvamos a cargar la página, el depurador se detendrá dentro de nuestra fuente de C++:
Ya podemos ver todas nuestras variables a la derecha, pero solo width
y height
están inicializadas en este momento, por lo que no hay mucho que inspeccionar.
Establezcamos otro punto de interrupción dentro del bucle principal de Mandelbrot y reanudemos ejecución se adelanta un poco.
En este punto, nuestro palette
se llenó con algunos colores aleatorios,
y podemos expandir tanto la matriz en sí, como
SDL_Color
e inspecciona sus componentes para verificar lo siguiente:
todo se ve bien (por ejemplo, ese canal "alfa" siempre está configurado
a la opacidad completa). Del mismo modo, podemos expandir y verificar los valores reales
partes imaginarias del número complejo almacenadas en la variable center
.
Si quieres acceder a una propiedad profundamente anidada que es difícil de navega a través de la vista Alcance, puedes usar la consola y la evaluación de los resultados. Sin embargo, ten en cuenta que las expresiones C++ más complejas no son todavía es compatible.
Reanudamos la ejecución algunas veces y veamos cómo está el x
interno
cambiando mirando de nuevo la vista Scope y agregando
el nombre de la variable a la lista de observación, evaluándola en la consola o
Coloca el cursor sobre la variable en el código fuente:
A partir de aquí, podemos recorrer o pasar instrucciones C++ y observar cómo otras variables también están cambiando:
Todo esto funciona muy bien cuando hay información de depuración disponible, ¿qué sucede si queremos depurar un código que no se compiló con el opciones?
Depuración de WebAssembly sin procesar
Por ejemplo, le pedimos a Emscripten que proporcione una biblioteca SDL compilada previamente para
en lugar de compilarlos nosotros mismos desde la fuente, por lo que, al menos,
actualmente, no hay forma de que el depurador encuentre fuentes asociadas.
Regresemos a SDL_RenderDrawColor
:
Volvemos a la experiencia de depuración de WebAssembly sin procesar.
Se ve un poco aterrador y no es algo que la mayoría de los desarrolladores web necesitas manejar, pero es posible que, en ocasiones, quieras depurar un compilada sin información de depuración, ya sea porque es un de terceros sobre la que no tienes control o porque uno de esos errores, que solo ocurre en producción.
Para ayudar en esos casos, hemos realizado algunas mejoras en la versión básica de depuración.
En primer lugar, si antes usaste la depuración de WebAssembly sin procesar,
Observa que todo el desensamblado ahora se muestra en un solo archivo
más para adivinar a qué función corresponde una entrada de Sources wasm-53834e3e/
wasm-53834e3e-7
Nuevo esquema de generación de nombres
También mejoramos los nombres en la vista de desensamblado. Anteriormente, verías solo índices numéricos o, en el caso de funciones, ningún nombre.
Ahora, generamos nombres de forma similar a otras herramientas de desensamblado, ya que
con las sugerencias de la sección de nombres de WebAssembly
las rutas de importación y exportación y, por último, si todo lo demás falla,
según el tipo y el índice del elemento, como $func123
. Puedes
Observa cómo, en la captura de pantalla anterior, esto ya ayuda a obtener
seguimientos de pila y desensamblado más legibles.
Cuando no hay información disponible sobre el tipo, puede ser difícil inspeccionar cualquier valor además de las primitivas. Por ejemplo, se mostrarán punteros como números enteros regulares, sin forma de saber qué se almacena detrás de ellos memoria.
Inspección de memoria
Anteriormente, solo podías expandir el objeto de memoria de WebAssembly, representado por env.memory
en la vista Scope para buscar.
bytes individuales. Esto funcionó en algunas situaciones triviales, pero no fue
particularmente conveniente para expandir y no permitían reinterpretar los datos
en formatos que no sean valores de bytes. Agregamos una función nueva para ayudarte
con esto: un inspector de memoria lineal.
Si haces clic con el botón derecho en env.memory
, ahora deberías ver un nuevo elemento
opción llamada Inspeccionar memoria:
Una vez que hagas clic, aparecerá un Inspector de memoria, en el que puedes inspeccionar la memoria de WebAssembly en vistas hexadecimales y ASCII, navegar a direcciones específicas y, además, interpretar los datos en diferentes formatos:
Situaciones avanzadas y advertencias
Crea perfiles del código de WebAssembly
Cuando abres Herramientas para desarrolladores, el código de WebAssembly “disminuye de nivel” a una
una versión no optimizada para habilitar la depuración. Esta versión es mucho más lenta,
lo que significa que no puedes confiar en console.time
, performance.now
y otros métodos para medir la velocidad de tu código.
abiertos, ya que los números que obtenga no representarán el rendimiento real
en absoluto.
En su lugar, debes usar el panel de rendimiento de Herramientas para desarrolladores. que ejecutará el código a máxima velocidad y te proporcionará desglose detallado del tiempo dedicado a diferentes funciones:
Como alternativa, puedes ejecutar tu aplicación con Herramientas para desarrolladores cerrada y ábrelo cuando termines para inspeccionar la consola.
Mejoraremos las situaciones de generación de perfiles en el futuro, pero, por ahora, ten en cuenta esta advertencia. Si quieres obtener más información sobre WebAssembly situaciones de niveles, consulta nuestros documentos sobre canalización de compilación de WebAssembly.
Compilación y depuración en diferentes máquinas (incluidos Docker y host)
Cuando compilas en Docker, en una máquina virtual o en un servidor de compilación remoto, es probable que te encuentres con situaciones en las que las rutas a los archivos fuente usadas durante la compilación no coinciden con las rutas de tu propio sistema de archivos donde se estén ejecutando las Herramientas para desarrolladores de Chrome. En este caso, los archivos aparecerán en el Sources, pero no se pudo cargar.
Para solucionar este problema, implementamos una funcionalidad de asignación de rutas en las opciones de extensión C/C++. Puedes usarlo para reasignar rutas arbitrarias y ayudar a las Herramientas para desarrolladores a encontrar fuentes.
Por ejemplo, si el proyecto en tu máquina anfitrión se encuentra en una ruta de acceso
C:\src\my_project
, pero se compiló dentro de un contenedor de Docker en el que
esa ruta se representó como /mnt/c/src/my_project
, puedes reasignar
durante la depuración, especificando esas rutas como prefijos:
El primer prefijo coincidente “gana”. Si conoces otros tipos de lenguaje
depuradores, esta opción es similar al comando set substitute-path
en GDB o una configuración target.source-map
en LLDB.
Cómo depurar compilaciones optimizadas
Al igual que con cualquier otro lenguaje, la depuración funciona mejor si las optimizaciones son inhabilitado. Las optimizaciones pueden intercalar funciones una a otra, reordenar código o quitar partes de él por completo, y todo esto tiene un la posibilidad de confundir al depurador y, en consecuencia, a ti como usuario.
Si no te importa tener una experiencia de depuración más limitada y aún quieres
depurar una compilación optimizada, la mayoría de las optimizaciones funcionarán como
se espera, excepto la inserción de funciones. Planeamos abordar las restantes
problemas en el futuro, pero, por ahora, usa -fno-inline
para
inhabilítala cuando realices compilaciones con cualquier optimización de nivel -O
, p.ej.:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Separa la información de depuración
La información de depuración conserva muchos detalles sobre tu código, definidos tipos, variables, funciones, alcances y ubicaciones: cualquier cosa que pueda serán útiles para el depurador. Por eso, suele ser más grande código en sí mismo.
Para acelerar la carga y la compilación del módulo de WebAssembly, te recomendamos que dividas esta información de depuración en un archivo WebAssembly independiente. Para hacerlo en Emscripten, pasa una marca -gseparate-dwarf=…
con
el nombre de archivo deseado:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
En este caso, la aplicación principal solo almacenará el nombre de archivo
temp.debug.wasm
y la extensión auxiliar podrá localizar y
y cargarlo cuando abras Herramientas para desarrolladores.
Cuando se combina con optimizaciones como las descritas anteriormente, esta función puede usarse para enviar compilaciones de producción casi optimizadas de tu y, luego, depurarlas con un archivo lateral local. En este caso, además, necesitaremos anular la URL almacenada para que la extensión busca el archivo lateral, por ejemplo:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
Continuará...
¡Uf! Eso fue mucha información sobre las funciones nuevas.
Con todas esas nuevas integraciones, las Herramientas para desarrolladores de Chrome potente y depurador no solo para JavaScript, sino también para apps de C y C++, por lo que es más fácil que nunca tomar apps, ya que están integradas en una variedad y llevarlas a una Web compartida multiplataforma.
Sin embargo, nuestro recorrido aún no ha terminado. Algunas de las funciones trabajando a partir de aquí:
- Se corrigieron los problemas de la experiencia de depuración.
- Se agregó compatibilidad con formateadores de tipos personalizados.
- Se están realizando mejoras en la generación de perfiles para apps de WebAssembly.
- Agregamos compatibilidad con la cobertura de código para que sea más fácil de encontrar código sin usar.
- Se mejoró la compatibilidad con expresiones en la evaluación de la consola.
- Se agregó compatibilidad con más idiomas.
- …y mucho más
Mientras tanto, ayúdanos probando la versión beta actual en tu propio código e informando los hallazgos problemas a https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Descarga los canales de vista previa
Considera usar Chrome Canary, Dev o Beta como tu navegador de desarrollo predeterminado. Estos canales de vista previa te brindan acceso a las funciones más recientes de Herramientas para desarrolladores, prueban API de plataformas web de vanguardia y detectan problemas en tu sitio antes que los usuarios.
Comunicarse con el equipo de Herramientas para desarrolladores de Chrome
Usa las siguientes opciones para analizar las nuevas funciones y los cambios en la publicación, o cualquier otro tema relacionado con DevTools.
- Envíanos una sugerencia o comentarios a través de crbug.com.
- Informa un problema en Herramientas para desarrolladores con Más opciones > Ayuda > Informa problemas de Herramientas para desarrolladores en Herramientas para desarrolladores.
- Twittea a @ChromeDevTools.
- Deja comentarios en nuestros videos de YouTube de Herramientas para desarrolladores o en videos de YouTube de las Sugerencias de las Herramientas para desarrolladores.