Depuración del uso elevado de CPU en .NET Core
Este artículo se aplica a: ✔️ SDK de .NET Core 3.1 y versiones posteriores
En este tutorial, aprenderá a depurar un escenario de uso excesivo de CPU. Con el repositorio de código fuente de ejemplo proporcionado, Aplicación web de ASP.NET Core, puede provocar un interbloqueo de forma intencionada. El punto de conexión dejará de responder y experimentará una acumulación de subprocesos. Aprenderá a usar diversas herramientas para diagnosticar este escenario con varios elementos clave de datos de diagnóstico.
En este tutorial va a:
- Investigar el uso elevado de CPU
- Determinar el uso de CPU con dotnet-counters
- Usar dotnet-trace para la generación de seguimiento
- Realizar perfiles de rendimiento en PerfView
- Diagnosticar y resolver el uso excesivo de CPU
Requisitos previos
En el tutorial se usa:
- SDK de .NET Core 3.1 o una versión posterior
- Destino de depuración de ejemplo para desencadenar el escenario
- dotnet-trace para enumerar los procesos y generar un perfil
- dotnet-counters para supervisar el uso de la CPU
Contadores de CPU
Antes de intentar recopilar datos de diagnóstico, debe observar una condición de CPU alta. Ejecute la aplicación de ejemplo mediante el siguiente comando desde el directorio raíz del proyecto.
dotnet run
Para encontrar el identificador de proceso, use el comando siguiente:
dotnet-trace ps
Anote el identificador de proceso de la salida del comando. El identificador de proceso era 22884
, pero el suyo será diferente. Para comprobar el uso de CPU actual, use el comando de la herramienta dotnet-counters:
dotnet-counters monitor --refresh-interval 1 -p 22884
refresh-interval
es el número de segundos entre los valores de CPU de sondeo de contador. La salida debe ser similar a la siguiente:
Press p to pause, r to resume, q to quit.
Status: Running
[System.Runtime]
% Time in GC since last GC (%) 0
Allocation Rate / 1 sec (B) 0
CPU Usage (%) 0
Exception Count / 1 sec 0
GC Heap Size (MB) 4
Gen 0 GC Count / 60 sec 0
Gen 0 Size (B) 0
Gen 1 GC Count / 60 sec 0
Gen 1 Size (B) 0
Gen 2 GC Count / 60 sec 0
Gen 2 Size (B) 0
LOH Size (B) 0
Monitor Lock Contention Count / 1 sec 0
Number of Active Timers 1
Number of Assemblies Loaded 140
ThreadPool Completed Work Item Count / 1 sec 3
ThreadPool Queue Length 0
ThreadPool Thread Count 7
Working Set (MB) 63
Con la aplicación web en ejecución, inmediatamente después del inicio, no se consume CPU en absoluto y se muestra 0%
. Vaya a la ruta api/diagscenario/highcpu
con 60000
como parámetro de ruta:
https://localhost:5001/api/diagscenario/highcpu/60000
Ahora, vuelva a ejecutar el comando dotnet-counters. Si solo está interesado en supervisar el contador cpu-usage
, agregue "--counters System.Runtime[cpu-usage]" al comando anterior. No estamos seguros de si se consume la CPU, por lo que supervisaremos la misma lista de contadores que ha aparecido antes para comprobar que los valores de contador están en el intervalo esperado para nuestra aplicación.
dotnet-counters monitor -p 22884 --refresh-interval 1
Debería ver un aumento en el uso de la CPU, como se muestra a continuación (según el equipo host, espere un uso variable de la CPU):
Press p to pause, r to resume, q to quit.
Status: Running
[System.Runtime]
% Time in GC since last GC (%) 0
Allocation Rate / 1 sec (B) 0
CPU Usage (%) 25
Exception Count / 1 sec 0
GC Heap Size (MB) 4
Gen 0 GC Count / 60 sec 0
Gen 0 Size (B) 0
Gen 1 GC Count / 60 sec 0
Gen 1 Size (B) 0
Gen 2 GC Count / 60 sec 0
Gen 2 Size (B) 0
LOH Size (B) 0
Monitor Lock Contention Count / 1 sec 0
Number of Active Timers 1
Number of Assemblies Loaded 140
ThreadPool Completed Work Item Count / 1 sec 3
ThreadPool Queue Length 0
ThreadPool Thread Count 7
Working Set (MB) 63
Durante toda la solicitud, el uso de la CPU rondará en torno al porcentaje aumentado.
Sugerencia
Para visualizar un uso de CPU incluso mayor, puede ejecutar este punto de conexión simultáneamente en varias pestañas del explorador.
En este momento, puede afirmar con seguridad que el uso de CPU es mayor del esperado. Identificar los efectos de un problema es clave para encontrar la causa. Usaremos el efecto del alto consumo de CPU, además de las herramientas de diagnóstico, para encontrar la causa del problema.
Análisis de CPU elevada con Profiler
Al analizar una aplicación con un uso elevado de la CPU, necesita una herramienta de diagnóstico que pueda proporcionar información sobre lo que hace el código. Lo habitual es optar por un generador de perfiles. Existen diferentes opciones de generador de perfiles entre las que elegir. dotnet-trace
se puede usar en todos los sistemas operativos, sin embargo, sus limitaciones de sesgo de punto seguro y de pilas de llamadas que son solo administradas dan lugar a una información más general, en comparación con un generador de perfiles compatible con kernels, como "perf" para Linux o ETW para Windows. Si la investigación de rendimiento solo implica código administrado, por lo general dotnet-trace
será suficiente.
La herramienta perf
se puede usar para generar perfiles de aplicaciones .NET Core. Vamos a mostrar esta herramienta, aunque también se podría usar dotnet-trace. Salga de la instancia anterior del destino de depuración de ejemplo.
Establezca la variable de entorno DOTNET_PerfMapEnabled
para que la aplicación .NET cree un archivo map
en el directorio /tmp
. perf
usa este archivo map
para asignar, según el nombre, las direcciones de CPU a las funciones generadas con JIT. Para obtener más información, consulte Exportación de mapas de rendimiento y volcados de JIT.
Nota:
.NET 6 estandariza en el prefijo DOTNET_
en lugar de en COMPlus_
para las variables de entorno que configuran el comportamiento en tiempo de ejecución de .NET. Sin embargo, el prefijo COMPlus_
seguirá funcionando. Si usa una versión anterior del runtime de .NET, debe seguir usando el prefijo COMPlus_
para las variables de entorno.
Ejecute el destino de depuración de ejemplo en la misma sesión de terminal.
export DOTNET_PerfMapEnabled=1
dotnet run
Ejecute de nuevo el punto de conexión de la API de uso elevado de CPU (https://localhost:5001/api/diagscenario/highcpu/60000
). Mientras se ejecuta en la solicitud de 1 minuto, ejecute el comando perf
con el identificador de proceso:
sudo perf record -p 2266 -g
El comando perf
inicia el proceso de recopilación de rendimiento. Deje que se ejecute durante unos 20 o 30 segundos y, luego, presione Ctrl+C para salir del proceso de recopilación. Puede usar el mismo comando perf
para ver la salida del seguimiento.
sudo perf report -f
También puede generar un gráfico de llamas mediante los comandos siguientes:
git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
Este comando genera un archivo flamegraph.svg
que puede ver en el explorador para investigar el problema de rendimiento:
Análisis de datos de CPU elevada con Visual Studio
Todos los archivos *.nettrace se pueden analizar en Visual Studio. Para analizar un archivo *.nettrace de Linux en Visual Studio, transfiera el archivo *.nettrace, además del resto de documentos necesarios, a una máquina Windows, y después abra el archivo *.nettrace en Visual Studio. Para más información, consulte Análisis de datos de uso de la CPU.
Consulte también
- dotnet-trace para mostrar procesos
- dotnet-counters para comprobar el uso de memoria administrada
- dotnet-dump para recopilar y analizar un archivo de volcado de memoria
- dotnet/diagnostics