Desarrollo de Diablo IV en Blizzard y depuración de volcados de memoria de Linux en Visual Studio

El blog de Microsoft presentó recientemente un artículo escrito por Bill Randolph, ingeniero de software senior de Blizzard que trabaja en Diablo IV. Este artículo cubre algunos de los aspectos específicos del trabajo en Diablo IV y, en particular, describe cómo usar Visual Studio para depurar código basado en Linux. Hoy les traemos a su atención una traducción de este material.





Introducción



Cuando trabajamos en Diablo IV, escribimos todo el código en Windows y luego lo compilamos para diferentes plataformas. Esto también se aplica a nuestros servidores que ejecutan Linux. (El código incluye directivas de compilación condicional y, cuando es necesario, contiene fragmentos escritos específicamente para una plataforma específica). Nuestro trabajo está organizado de esta manera por muchas razones. Para empezar, las habilidades profesionales clave de nuestro equipo son Windows. Incluso nuestros programadores de servidores están más familiarizados con el desarrollo de Windows. Apreciamos la capacidad de utilizar las mismas herramientas y la misma base de conocimientos de todos los programadores de nuestro equipo.



Otra razón más importante por la que desarrollamos en Windows es la capacidad de aprovechar el conjunto de herramientas altamente funcionales y confiables que nos brinda Visual Studio. E incluso si estuviéramos desarrollando algo en Linux, entonces puedo decir que no hay nada en el mundo de Linux que se pueda comparar con Visual Studio.



Es cierto que, debido a esto, nos enfrentamos a algunas dificultades que surgen cuando el servidor se bloquea y necesitamos depurar un volcado de memoria. Tenemos la capacidad de iniciar sesión de forma remota en una máquina virtual (o, más precisamente, en un contenedor) que falló, podemos ejecutar gdb para averiguar las razones de lo que sucedió. Pero este enfoque tiene muchas desventajas. Por ejemplo, no implementamos binarios junto con el código fuente, como resultado, cuando se trabaja con una máquina virtual o con un contenedor, el código fuente no está disponible en la sesión de gdb.



Otra complicación radica en el propio gdb. El hecho es que si no usamos esta herramienta constantemente, de forma regular, no se puede dominar al nivel que nos convenga. En pocas palabras, nuestros desarrolladores estarían mucho más dispuestos a utilizar herramientas familiares para depurar código. Dado que solo 2-3 de nuestros desarrolladores conocen muy bien gdb, cuando algo sale mal, ellos son los que buscan el problema. Y esto no se puede llamar la distribución óptima de la carga de trabajo para los programadores.



Siempre hemos querido encontrar una forma intuitiva de depurar el código de Linux. ¡Es por eso que estamos tan emocionados de poder utilizar la nueva función de Visual Studio que nos permite resolver exactamente este problema en un entorno familiar! Y no sería exagerado decir que gracias a esto nuestro sueño se ha hecho realidad.





Acerca de nuestro proceso de depuración de código



La depuración del código de Linux en Visual Studio solo es posible si el Subsistema de Windows para Linux (WSL) está instalado en el sistema o si la conexión a Linux está configurada en Connection Manager . Todos nuestros desarrolladores de backend han instalado WSL utilizando la distribución en la que implementamos nuestro proyecto. Ejecutamos un script que escribí que instala todas las herramientas de desarrollo y las bibliotecas de soporte necesarias para construir nuestro servidor en WSL.



(Me desviaré de nuestro tema principal por un momento. Me gustaría enfatizar que hemos llegado a la conclusión de que WSL es el mejor entorno existente que permite a los desarrolladores probar cambios en las compilaciones de Linux. Este esquema de trabajo parece extremadamente conveniente: cambiar a WSL, usar el comando cd



para ir a un directorio de código compartido y construir el proyecto directamente desde allí. Esta es una solución mucho mejor que usar una máquina virtual o incluso un contenedor. Si crea proyectos con CMake, también puede usar el soporte de Visual Studio integrado para WSL ).



Te contaré un poco sobre nuestras asambleas. Desarrollamos el código en Windows y tenemos una versión de Windows de nuestro servidor diseñada para funcionar en este sistema operativo. Esto es útil para nosotros cuando trabajamos en las capacidades habituales del proyecto. Pero estamos implementando nuestro código del lado del servidor en Linux, que requiere compilaciones en Linux. Los ensamblados de Linux se crean en una granja de compilación. Utiliza un sistema de compilación que se ejecuta en una computadora con Linux. Con su ayuda se ensambla nuestro proyecto de servidor y el contenedor correspondiente, que luego se despliega. Los binarios de Linux se implementan solo en contenedores. Por lo general, los desarrolladores no tienen acceso a estos contenedores.



Cuando uno de los servidores de nuestra infraestructura falla, se nos notifica mediante un script especial, después de lo cual los archivos de volcado se escriben en una carpeta de red compartida. Para depurar estos archivos, ya sea en Linux o Visual Studio, necesita un programa que funcione. Al depurar, es útil usar exactamente las mismas bibliotecas compartidas que se usan en el contenedor implementado. Usamos un script diferente para obtener estos archivos. Primero, copiamos el volcado a la máquina local y luego ejecutamos el script y le pasamos información sobre este volcado. El script descarga el contenedor de Docker que fue construido para la versión probada del código, extrae de él los archivos ejecutables de nuestro servidor, así como ciertas bibliotecas de tiempo de ejecución comunes. Todo esto es necesario para gdb. (Esto, al trabajar con gdb, evita los problemas de compatibilidad que pueden surgir sisi la versión WSL del sistema no es exactamente la misma que la versión de Linux implementada). El script, configurando una sesión de depuración, escribe datos en ~/.gdbinit



, lo que indica que las bibliotecas compartidas son bibliotecas del sistema.



Luego vamos a Visual Studio, donde comienza la diversión. Estamos descargando una solución de compilación para la versión de Windows de nuestros servidores. Luego abrimos un nuevo diálogo de depuración usando el comando Debug -> Other Debug Targets -> Debug Linux Core Dump with Native Only



. Marcamos la casilla Debug on WSL



e ingresamos las rutas a los archivos de volcado y los binarios del servidor (¡destinados a WSL!). Después de eso, simplemente presione el botón Debug



y observe lo que está sucediendo.





Al iniciar la depuración en Visual Studio,



Visual Studio inicia automáticamente gdb en WSL. Una vez que el sistema ha estado trabajando con el disco durante algún tiempo, se muestra la pila de llamadas del programa que falló y el puntero de instrucción se establece en la línea de código correspondiente. ¡Este es realmente un mundo feliz!



A continuación, nos ocupamos de la identificación del fallo en sí. Tenemos un manejador de fallas que intercepta el evento apropiado para ejecutar algunos procedimientos de servicio. Por lo tanto, la información sobre la falla en sí se encuentra, en un servidor de un solo subproceso, más profundo en la pila de llamadas. Pero algunos de nuestros servidores son multiproceso. Y el bloqueo puede ocurrir en cualquiera de sus hilos. El manejador de fallas registra información sobre el código del archivo defectuoso y sobre el número de línea. Por lo tanto, examinar estos datos nos da la primera pista. Estamos buscando el lugar en la pila de llamadas que corresponde a la ejecución de este código.



En los viejos tiempos, es decir, hace unas semanas, habríamos usado gdb para rastrear todos los subprocesos, y luego escanear la lista resultante para encontrar el subproceso cuya pila de llamadas probablemente fallaba. Por ejemplo, si el hilo estaba inactivo, lo más probable es que no se bloquee. Necesitamos una pila que tenga más de unos pocos marcos e información de que estamos tratando con un hilo inactivo. A continuación, debemos examinar el código para comprender cuál es el problema. Si es algo simple, puede verlo directamente en el código. Si nos enfrentamos a un problema más complicado, tendremos que recurrir a las capacidades de gdb para investigar el estado del proceso.



Pero Visual Studio nos brinda capacidades mucho más poderosas que las que teníamos antes. En entornos multiproceso, puede abrir una ventana en una sesión de depuración Threads



y hacer clic en los subprocesos para ver sus pilas. Sin embargo, esto es muy similar al enfoque utilizado en gdb. Por lo tanto, si necesita estudiar, digamos, 50 hilos, puede convertirse en una tarea bastante aburrida y que requiere mucho tiempo. Afortunadamente, Visual Studio tiene una herramienta que facilita mucho esta tarea. Esta es la ventana Parallel Stacks .



Lo admito, la mayoría de nosotros no sabíamos acerca de Parallel Stacks hasta que Erica Sweet y su equipo nos lo contaron. Si durante la sesión de depuración ejecute el comando Debug -> Windows -> Parallel Stacks



- Se abrirá una nueva ventana, que muestra información sobre la pila de llamadas de cada hilo en el proceso bajo investigación. Esto es algo así como una vista de pájaro de todo el espacio de proceso. Se puede hacer doble clic en cualquier marco de pila de cualquier hilo. Después de eso, Visual Studio saltará a este marco tanto en la ventana del código fuente como en la ventana de la pila de llamadas. Esto nos ayuda mucho a ahorrar tiempo.



Una vez que vemos el código cerca del sitio del accidente, podemos examinar las variables usando el mouse, usando QuickWatch o usando cualquiera de las muchas herramientas de Visual Studio. Por supuesto, en las versiones de lanzamiento, muchas variables están optimizadas, pero al mismo tiempo, ¡muchas no lo están! Nosotros, usando la interfaz de Visual Studio, podemos identificar el problema mucho más rápido que antes usando gdb.







Salir



Nuestro equipo está feliz de poder depurar volcados de Linux en Visual Studio, el entorno en el que estamos desarrollando. Para nosotros, esta es una mejora importante, ya que permite a muchos más desarrolladores que nunca diagnosticar problemas en la naturaleza. Esto nos permite a todos aprovechar las poderosas herramientas de depuración de Visual Studio. Una vez completada la preparación preliminar del entorno de trabajo, puede estar en una sesión de depuración de Visual Studio en, literalmente, cuestión de minutos. Esta característica aumenta enormemente la velocidad para encontrar problemas y la eficiencia de nuestro trabajo. Gracias a Erica y su equipo por su ayuda.



¿Qué le resulta más útil en Visual Studio?






All Articles