Supervisión de aplicaciones .NET

.NET es un tiempo de ejecución administrado . Esto significa que contiene funciones de alto nivel que controlan su programa por usted (de Introducción al Common Language Runtime (CLR), 2007 ):


El tiempo de ejecución proporciona muchas funciones, por lo que es conveniente dividirlas en las siguientes categorías:

  1. Las funciones principales que afectan el dispositivo de los demás. Estos incluyen:
    1. recolección de basura;
    2. asegurar el acceso a la memoria y la seguridad del sistema de tipos;
    3. Soporte de alto nivel para lenguajes de programación.
  2. Funciones adicionales : trabaje sobre la base de las principales. Muchos programas útiles lo hacen sin ellos. Estas funciones incluyen:
    1. Aislar aplicaciones usando AppDomains
    2. Protección de aplicaciones y aislamiento de cajas de arena.
  3. Todos los tiempos de ejecución necesitan otras funciones , pero no utilizan las funciones básicas de CLR. Tales características reflejan el deseo de crear un entorno de programación completo. Estos incluyen:
    1. control de versiones;
    2. depuración / perfilado;
    3. asegurando la interacción.

Se puede ver que, aunque la depuración y la creación de perfiles no son las funciones principales o adicionales, están en la lista debido al " deseo de crear un entorno de programación completo ".



El resto de la publicación describe qué características de monitoreo , observabilidad e introspección existen en el Core CLR, por qué son útiles y cómo las proporciona el entorno.


Diagnósticos


Primero, eche un vistazo a la información de diagnóstico que nos proporciona el CLR. Tradicionalmente, el seguimiento de eventos para Windows (ETW) se ha utilizado para esto.
Hay muchos eventos sobre los cuales el CLR proporciona información. Están asociados con:


  • recolección de basura (GC);
  • Compilación JIT;
  • módulos y dominios de aplicación;
  • trabajar con hilos y conflictos al bloquear;
  • así como muchos otros

Por ejemplo, aquí se produce un evento durante la carga en AppDomain , aquí el evento se asocia con una excepción y aquí con el ciclo de asignación de memoria del recolector de basura .


Vista Perf


Si desea ver los eventos en el sistema de rastreo (ETW) relacionados con sus aplicaciones .NET, le recomiendo usar la excelente herramienta PerfView y comenzar con estos videos de capacitación o esta presentación de PerfView: la herramienta de rendimiento .NET definitiva . PerfView ha sido ampliamente reconocido por proporcionar información invaluable. Por ejemplo, los ingenieros de Microsoft lo usan regularmente para analizar el rendimiento .


Infraestructura común


Si de repente el nombre no está claro, el seguimiento de eventos en ETW está disponible solo en Windows, lo que no encaja muy bien con el mundo multiplataforma de .NET Core. Puede usar PerfView para analizar el rendimiento en Linux (usando LTTng). Sin embargo, esta herramienta de línea de comandos, llamada PerfCollect, solo recopila datos. Las capacidades de análisis y una rica interfaz de usuario (incluidas las gráficas de fuego ) actualmente solo están disponibles en las soluciones de Windows.


Pero si aún desea analizar el rendimiento de .NET en Linux, existen otros enfoques:



El segundo enlace anterior conduce a una discusión sobre la nueva infraestructura EventPipe , en la que se está trabajando en .NET Core (además de EventSources y EventListeners). Sus objetivos de desarrollo se pueden encontrar en el documento Diseño de monitoreo de rendimiento multiplataforma . A un alto nivel, esta infraestructura creará un solo lugar donde el CLR enviará eventos relacionados con el diagnóstico y el rendimiento. Luego, estos eventos serán redirigidos a uno o más registradores, que, por ejemplo, pueden incluir ETW, LTTng y BPF. El registrador necesario se determinará según el sistema operativo o la plataforma en la que se ejecuta el CLR. Para obtener una explicación detallada de los pros y los contras de varias tecnologías de registro, consulte el Diseño de eventos y rendimiento de .NET Cross-Plat .


El progreso de EventPipes se monitorea a través del proyecto de Monitoreo de rendimiento y problemas relacionados con 'EventPipe' .


Planes futuros


Finalmente, hay planes para crear un controlador de perfiles de rendimiento , que tiene las siguientes tareas:


El controlador debe administrar la infraestructura de creación de perfiles y presentar los datos de rendimiento generados por los componentes .NET responsables del diagnóstico de rendimiento de una manera simple y multiplataforma.


Según el plan, el controlador debe proporcionar la siguiente funcionalidad a través del servidor HTTP , recibiendo todos los datos necesarios de la infraestructura de EventPipes:


API REST


  • Principio 1: perfil simple: perfile el tiempo de ejecución en el período de tiempo X y devuelva la traza.
  • Principio 1: perfil avanzado: inicio de seguimiento (junto con la configuración)
  • Principio 1: perfil avanzado: seguimiento completo (la respuesta a esta llamada será el seguimiento en sí).
  • Principio 2: Obtenga estadísticas asociadas con todos los EventCounters o un EventCounter específico.

Páginas navegables HTML


  • Principio 1: una representación textual de todas las pilas de código administrado en un proceso.
    • Crea instantáneas de procesos en ejecución para usar como un informe de diagnóstico simple.
  • Principio 2: mostrar el estado actual (posiblemente con un historial) de los contadores EventCounters.
    • Proporciona una visión general de los contadores existentes y sus valores.
    • PROBLEMA NO RESUELTO: No creo que haya API públicas necesarias para contar EventCounters.

Realmente quiero ver qué sucede con el controlador de perfiles de rendimiento (PPC). Creo que si está integrado en el CLR, traerá muchos beneficios a .NET. Dicha funcionalidad existe en otros tiempos de ejecución .


Perfilado


Otra herramienta efectiva que tiene el CLR es una API de creación de perfiles. Es utilizado (principalmente) por herramientas de terceros para conectarse al tiempo de ejecución en un nivel bajo. Puede obtener más información sobre la API de esta revisión , pero a un alto nivel, puede usarla para realizar devoluciones de llamada que se activan si:


  • eventos relacionados con el recolector de basura;
  • se lanzan excepciones;
  • los ensambles se cargan / descargan;
  • y mucho mas

Imagen de la página de API de creación de perfiles BOTR: descripción general


Además, tiene otras características efectivas. Primero, puede configurar controladores que se invocan cada vez que se ejecuta el método .NET, ya sea en el entorno mismo o desde el código de usuario. Estas devoluciones de llamada se conocen como controladores de entrada / salida. Aquí hay un buen ejemplo de cómo usarlos. Sin embargo, para esto necesita comprender las convenciones de llamadas para diferentes arquitecturas de SO y CPU , lo que no siempre es fácil . Además, recuerde que la API de creación de perfiles es un componente COM al que solo se puede acceder desde el código C / C ++, pero no desde C # / F # / VB.NET.


En segundo lugar, el generador de perfiles puede reescribir el código IL de cualquier método .NET antes de la compilación JIT utilizando la API SetILFunctionBody () . Esta API es realmente eficiente. Es la base de muchas herramientas APM .NET . Puede obtener más información sobre su uso en mi publicación Cómo burlarse de las clases selladas y los métodos estáticos y el código relacionado.


API ICorProfiler


Resulta que la API de creación de perfiles funcionó, debería haber todo tipo de trucos en el entorno de tiempo de ejecución. Simplemente mire la discusión en la página Permitir rejit en adjuntar (vea ReJIT: Una guía de procedimientos para obtener más información sobre ReJIT).


Puede encontrar una definición completa de todas las interfaces API y devoluciones de llamada en \ vm \ inc \ corprof.idl (consulte Lenguaje de descripción de interfaz ). Se divide en 2 partes lógicas. Una parte es la interfaz Profiler -> Runtime Environment (EE) , conocida como ICorProfilerInfo :


 //  ,    ICorProfilerInfo*,  //     .  ,  DLL   //          ,     //    . 

Esto se implementa en los siguientes archivos:



La otra parte principal es callbacks Runtime -> Profiler, que se agrupan bajo la interfaz ICorProfilerCallback :


 //       //  ICorProfilerCallaback* .       // ,     EEToProfInterfaceImpl. 

Estas devoluciones de llamada se implementan en los siguientes archivos:



Finalmente, vale la pena señalar que las API de creación de perfiles pueden no funcionar en todos los sistemas operativos y arquitecturas que ejecutan .NET Core. Aquí hay un ejemplo: problemas de código auxiliar de llamada ELT en Linux . Consulte el estado de las API de CoreCLR Profiler para obtener más información.


Perfilado v. Depuración


Como una pequeña digresión, debo decir que los perfiles y la depuración todavía se superponen un poco. Por lo tanto, es útil comprender qué proporcionan las diferentes API en el contexto de .NET Runtime (tomado de CLR Debugging vs. CLR Profiling ).


La diferencia entre depurar y perfilar en el CLR


DepuraciónPerfilado
Diseñado para encontrar problemas con la corrección del código.Diseñado para diagnosticar y solucionar problemas de rendimiento.
Puede tener un nivel muy alto de interferencia.Generalmente tiene un bajo nivel de intervención. Aunque el generador de perfiles admite la modificación del código IL o la instalación de controladores de entrada / salida, todo esto es para instrumentación, no para cambios radicales en el código.
La tarea principal es el control completo del objetivo. Esto incluye inspección, control de ejecución (por ejemplo, el comando set-next-Statement) y modificaciones (función Editar y continuar).La tarea principal es inspeccionar el objetivo. Para hacer esto, se proporciona instrumentación (cambio del código IL, instalación de controladores de entrada / salida)
Amplia API y un modelo de objeto grueso lleno de abstracciones.Una pequeña API. Hay pocas o ninguna abstracción.
Alto nivel de interactividad: las acciones del depurador son controladas por el usuario (o algoritmo). De hecho, los editores y depuradores a menudo están integrados (IDE).Sin interactividad: los datos generalmente se recopilan sin la intervención del usuario y luego se analizan.
Una pequeña cantidad de cambios críticos si se necesita compatibilidad con versiones anteriores. Creemos que la migración de la versión 1.1 a la versión 2.0 del generador de perfiles será una tarea simple o no muy difícil.Una gran cantidad de cambios críticos si se necesita compatibilidad con versiones anteriores. Creemos que migrar de la versión 1.1 a la versión 2.0 del generador de perfiles será una tarea difícil, idéntica a reescribirlo por completo.

Depuración


Los desarrolladores entienden de manera diferente qué es la depuración. Por ejemplo, pregunté en Twitter "cómo depurar los programas .NET" y obtuve muchas respuestas diferentes . Al mismo tiempo, las respuestas contenían una buena lista de herramientas y métodos, por lo que recomiendo mirarlos. Gracias, #LazyWeb


Creo que lo mejor de todo es que la esencia de la depuración refleja este mensaje:



El CLR proporciona una extensa lista de características relacionadas con la depuración. Sin embargo, ¿por qué se necesitan estos fondos? Se mencionan al menos tres razones en esta gran publicación ¿Por qué la depuración administrada es diferente de la depuración nativa? :


  1. La depuración de código no administrado puede abstraerse a nivel de hardware, pero la depuración de código administrado debe abstraerse a nivel de código IL.
  2. La depuración de código administrado requiere mucha información que no está disponible antes de la ejecución.
  3. El depurador de código administrado debe coordinarse con el recolector de basura (GC)

Por lo tanto, para facilitar su uso, el CLR debe proporcionar una API de depuración de alto nivel conocida como ICorDebug . Se muestra en la figura siguiente que muestra un escenario de depuración general (fuente: BOTR):


API ICorDebug


El principio de implementación y la descripción de los diversos componentes se toma de la depuración de CLR, una breve introducción :


Todo el soporte de depuración en .Net se implementa en la parte superior de la biblioteca dll, que llamamos The Dac. Este archivo (generalmente llamado mscordacwks.dll ) es un elemento estructural tanto para nuestra API de depuración pública ( ICorDebug ) como para dos API de depuración privadas: SOS-Dac API y IXCLR.
En un mundo ideal, todos usarían ICorDebug , nuestra API pública. Sin embargo, ICorDebug carece de muchas de las características que necesitan los desarrolladores de herramientas. Este es el problema que estamos tratando de solucionar donde podemos. Sin embargo, estas mejoras solo están presentes en CL.v.next, pero no en versiones anteriores de CLR. De hecho, el soporte de depuración de volcado por caída apareció en la API ICorDebug solo con el lanzamiento de CLR v4. Todos los que usan volcados de memoria para la depuración en CLR v2 no podrán aplicar ICorDebug en absoluto.

(Ver SOS e ICorDebug para más información)


De hecho, la API ICorDebug está dividida en más de 70 interfaces. No les daré todos, pero mostraré por qué categorías se pueden dividir. Para obtener más información, consulte la partición de ICorDebug, donde se ha publicado esta lista.


  • Nivel superior : ICorDebug + ICorDebug2: interfaces de nivel superior que sirven perfectamente como una colección de objetos ICorDebugProcess.
  • Callbacks : los eventos de depuración de código administrado se envían mediante métodos al objeto de devolución de llamada implementado por el depurador.
  • Proceso : este conjunto de interfaces representa el código de trabajo e incluye API relacionadas con eventos.
  • Inspección de código / tipo : funciona principalmente con imágenes PE estáticas, pero existen métodos convenientes para datos reales.
  • Control de ejecución : capacidad para monitorear el progreso del hilo. En la práctica, esto significa la capacidad de establecer puntos de interrupción (F9) y recorrer el código (entrada de código F11, omisión de código F10, salida de código S + F11). La función de control de ejecución ICorDebug solo funciona en código administrado.
  • Subprocesos + pilas de llamadas : las pilas de llamadas son la base de las funciones de inspección implementadas por el depurador. El trabajo con la pila de llamadas se lleva a cabo utilizando las siguientes interfaces. ICorDebug solo admite la depuración de código administrado y, en consecuencia, puede rastrear la pila de solo código administrado.
  • Inspección de objetos : la inspección de objetos es parte de la API que le permite ver los valores de las variables en el código depurado. Para cada interfaz, doy el método MVP, que, me parece, debería describir brevemente el propósito de esta interfaz.

Al igual que con las API de creación de perfiles, los niveles de soporte de API de depuración varían según el sistema operativo y la arquitectura del procesador. Por ejemplo, a partir de agosto de 2018, todavía no existe una solución ARM de Linux para diagnosticar y depurar código administrado. Para obtener más información sobre la compatibilidad con Linux, consulte la publicación Depuración de .NET Core en Linux con LLDB y el repositorio de Diagnósticos de Microsoft, cuyo objetivo es facilitar la depuración de programas .NET para Linux.


Finalmente, si desea ver cómo se ve la API ICorDebug en C #, eche un vistazo a los contenedores en la biblioteca CLRMD, incluidas todas las devoluciones de llamada disponibles (más adelante en esta publicación se discutirá más sobre CLRMD).


SOS y DAC


El componente de acceso a datos (DAC) se analiza en detalle en la página BOTR . Esencialmente, proporciona acceso fuera del proceso a las estructuras de datos CLR para que la información dentro de ellas pueda leerse desde otro proceso. Por lo tanto, el depurador (a través de ICorDebug ) o la extensión 'Son of Strike' (SOS) puede acceder a la instancia CLR en ejecución o al volcado de memoria y encontrar, por ejemplo:


  • todos los hilos en ejecución;
  • objetos gestionados del montón
  • información completa sobre el método, incluido el código de máquina;
  • rastro actual de la pila.

Una pequeña digresión : si desea averiguar de dónde provienen estos nombres extraños y obtener una pequeña lección sobre el historial de .NET, consulte esta respuesta en Stack Overflow .


La lista completa de comandos SOS es impresionante . Si lo usa junto con WinDBG, puede averiguar qué está sucediendo dentro de su programa y el CLR a un nivel muy bajo. Para ver cómo se implementa todo, veamos el !HeapStat , que muestra una descripción de los tamaños de los diversos montones que utiliza .NET GC:


(Imagen tomada de SOS: La próxima versión tiene algunos comandos nuevos: HeapStat)


Aquí hay una secuencia de código que muestra cómo SOS y DAC trabajan juntos:


  • SOS Complete Team !HeapStat ( enlace )
  • Código SOS en el !HeapStat que funciona con Workstation GC (enlace)
  • Función SOS GCHeapUsageStats(..) , que realiza la parte más difícil del trabajo ( enlace )
  • DacpGcHeapDetails datos DacpGcHeapDetails compartida que contiene punteros a los datos principales en el montón de GC, como segmentos, máscaras de bits y generaciones individuales ( referencia ).
  • GetGCHeapStaticData DAC GetGCHeapStaticData que llena la estructura DacpGcHeapDetails ( enlace )
  • DacpHeapSegmentData datos DacpHeapSegmentData compartida que contiene información sobre un segmento de montón de GC individual ( enlace )
  • DAC GetHeapSegmentData(..) , que DacpHeapSegmentData estructura DacpHeapSegmentData ( enlace )

Depuradores de terceros


Desde que Microsoft publicó la API de depuración, los desarrolladores ICorDebug pudieron usar las interfaces ICorDebug . Aquí hay una lista de los que pude encontrar:



Volcados de memoria


De lo último que hablaremos es de los volcados de memoria, que se pueden obtener de un sistema de trabajo y analizar fuera de él. El tiempo de ejecución de .NET siempre ha admitido el volcado de memoria en Windows . Y ahora que .NET Core se ha convertido en multiplataforma, han aparecido herramientas que realizan la misma tarea en otros sistemas operativos.


Cuando se utilizan volcados de memoria, a veces es difícil obtener las versiones correctas y coincidentes de los archivos SOS y DAC. Afortunadamente, Microsoft lanzó recientemente la herramienta CLI de dotnet symbol dotnet, que:


puede descargar todos los archivos necesarios para la depuración (conjuntos de caracteres, módulos, archivos SOS y DAC para un módulo coreclr específico) para cualquier volcado de núcleo específico, minivolcado o archivos de cualquier plataforma compatible, incluidos ELF, MachO, DLL de Windows, PDB y portátiles PDB

Finalmente, si está analizando un poco los volcados de memoria, le recomiendo que eche un vistazo a la excelente biblioteca CLR MD que Microsoft lanzó hace varios años. Ya escribí sobre sus funciones. En resumen, con la biblioteca, puede trabajar con volcados de memoria a través de una API C # intuitiva que contiene clases que proporcionan acceso a ClrHeap, GC Roots, CLR Threads, Stack Frames y mucho más. De hecho, CLR MD puede implementar la mayoría (si no todos) de los comandos SOS.


Puedes averiguar cómo funciona en esta publicación :


La Biblioteca administrada de ClrMD es una envoltura alrededor de las API de depuración destinadas al uso interno solo en el CLR. A pesar de que estas API son muy efectivas para el diagnóstico, no las admitimos en forma de lanzamientos públicos y documentados, ya que su uso es complejo y está estrechamente relacionado con otras características de la implementación de CLR. ClrMD resuelve este problema al proporcionar un contenedor fácil de usar y manejable alrededor de estas API de depuración de bajo nivel.

Source: https://habr.com/ru/post/466097/


All Articles