Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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 ejemplo proporcionado del repositorio de código fuente de la aplicación web ASP.NET Core, puede provocar un bloqueo intencionadamente. El extremo dejará de responder y experimentará la acumulación de hilos. Aprenderá a usar varias herramientas para diagnosticar este escenario con varios fragmentos clave de datos de diagnóstico.
En este tutorial, aprenderá a:
- Investigación del uso elevado de CPU
- Determinación del uso de CPU con dotnet-counters
- Uso de dotnet-trace para la generación de seguimiento
- Rendimiento del perfil en PerfView
- Diagnóstico y resolución de un uso excesivo de CPU
Prerrequisitos
En el tutorial se usa:
- SDK de .NET Core 3.1 o una versión posterior.
- Ejemplo de destino de depuración para activar el escenario.
- dotnet-trace para enumerar procesos y generar un perfil.
- dotnet-counters para supervisar el uso de cpu.
Contadores de CPU
Antes de intentar este tutorial, instale la versión más reciente de dotnet-counters:
dotnet tool install --global dotnet-counters
Si la aplicación ejecuta una versión de .NET anterior a .NET 9, la interfaz de usuario de salida de dotnet-counters tendrá un aspecto ligeramente diferente; consulte dotnet-counters para obtener más información.
Antes de intentar recopilar datos de diagnóstico, debe observar un estado de alto uso de CPU. Ejecute la aplicación de ejemplo mediante el siguiente comando desde el directorio raíz del proyecto.
dotnet run
Para comprobar el uso actual de la CPU, use el comando dotnet-counters tool:
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
La salida debe ser similar a la siguiente:
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.109 0
user 0.453 0
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
Al enfocar los Last Delta valores de dotnet.process.cpu.time, se indica cuántos segundos la CPU ha estado activa durante el período de actualización (actualmente establecido en 1 s por defecto). Con la aplicación web en ejecución, inmediatamente después del inicio, la CPU no está siendo consumida en absoluto, y estas diferencias son 0. Vaya a la api/diagscenario/highcpu ruta con 60000 como parámetro de ruta:
https://localhost:5001/api/diagscenario/highcpu/60000
Ahora, vuelva a ejecutar el comando dotnet-counters .
dotnet-counters monitor -n DiagnosticScenarios --showDeltas
Debería ver un aumento en el uso de CPU, como se muestra a continuación (en función del equipo host, espere un uso de CPU variable):
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value Last Delta
[System.Runtime]
dotnet.assembly.count ({assembly}) 111 0
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 8 0
gen1 1 0
gen2 0 0
dotnet.gc.heap.total_allocated (By) 4,042,656 24,512
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 801,728 0
gen1 6,048 0
gen2 0 0
loh 0 0
poh 0 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,512 0
gen1 562,024 0
gen2 1,095,056 0
loh 98,384 0
poh 24,528 0
dotnet.gc.last_collection.memory.committed_size (By) 5,623,808 0
dotnet.gc.pause.time (s) 0.019 0
dotnet.jit.compilation.time (s) 0.582 0
dotnet.jit.compiled_il.size (By) 138,895 0
dotnet.jit.compiled_methods ({method}) 1,470 0
dotnet.monitor.lock_contentions ({contention}) 4 0
dotnet.process.cpu.count ({cpu}) 22 0
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344 0.013
user 14.203 0.963
dotnet.process.memory.working_set (By) 65,515,520 0
dotnet.thread_pool.queue.length ({work_item}) 0 0
dotnet.thread_pool.thread.count ({thread}) 0 0
dotnet.thread_pool.work_item.count ({work_item}) 6 0
dotnet.timer.count ({timer}) 0 0
A lo largo de la duración de la solicitud, el uso de la CPU se desplazará alrededor del valor aumentado.
Sugerencia
Para visualizar un uso de CPU aún mayor, puede ejercer este punto de conexión en varias pestañas del explorador simultáneamente.
En este punto, puede afirmar con seguridad que la CPU está funcionando a un nivel más alto de lo esperado. Identificar los efectos de un problema es clave para encontrar la causa. Usaremos el efecto del consumo elevado de CPU además de las herramientas de diagnóstico para encontrar la causa del problema.
Análisis de cpu alta con Profiler
Al analizar una aplicación con un uso elevado de CPU, use un generador de perfiles para comprender lo que hace el código.
dotnet-trace collect funciona en todos los sistemas operativos, pero el bias de punto seguro y las pilas de llamadas solo administradas lo limitan a información más general que un generador de perfiles con conocimiento de kernel, como ETW para Windows o perf para Linux. Según el sistema operativo y la versión de .NET, es posible que estén disponibles las funcionalidades de generación de perfiles mejoradas; consulte las pestañas específicas de la plataforma que siguen para obtener instrucciones detalladas.
Use dotnet-trace collect-linux (.NET 10+)
En .NET 10 y versiones posteriores, dotnet-trace collect-linux es el enfoque de generación de perfiles recomendado en Linux. Combina EventPipe con perf_events de nivel de sistema operativo para generar un único seguimiento unificado que incluya pila de llamadas administradas y nativas, todo ello sin necesidad de reiniciar el proceso. Esto requiere permisos de root y el kernel de Linux 6.4+ con CONFIG_USER_EVENTS=y. Consulte requisitos previos de collect-linux para conocer los requisitos completos.
Asegúrese de que el destino de depuración de ejemplo esté configurado para .NET 10 o posterior, luego ejecútelo y pruebe de nuevo el punto de conexión de alto consumo de CPU (https://localhost:5001/api/diagscenario/highcpu/60000). Mientras se ejecuta dentro de la solicitud de 1 minuto, ejecute dotnet-trace collect-linux para capturar un registro de todo el equipo:
sudo dotnet-trace collect-linux
Deje que se ejecute durante unos 20-30 segundos y presione Ctrl+C o Entrar para detener la colección. El resultado es un .nettrace archivo que incluye tanto las pilas de llamadas administradas como nativas.
Abra el .nettrace con PerfView y use la vista Pilas de CPU para identificar los métodos que consumen más tiempo de procesamiento.
Para obtener información sobre cómo resolver símbolos nativos en tiempo de ejecución en el seguimiento, consulte Obtener símbolos para marcos de tiempo de ejecución nativos.
Utilice perf
La perf herramienta también se puede usar para generar perfiles de aplicación de .NET Core. Salga de la instancia anterior del objetivo de depuración de muestra.
Establezca la DOTNET_PerfMapEnabled variable de entorno para que la aplicación .NET cree un map archivo en el /tmp directorio. Este map archivo lo usa perf para asignar direcciones de CPU a funciones generadas por JIT por nombre. Para obtener más información, consulte Exportación de mapas de rendimiento y volcados JIT.
Ejecute el destino de depuración de ejemplo en la misma sesión de terminal.
export DOTNET_PerfMapEnabled=1
dotnet run
Vuelva a utilizar el punto de conexión de alto uso de CPU de la API (https://localhost:5001/api/diagscenario/highcpu/60000). Mientras se lleva a cabo la solicitud de 1 minuto, ejecute el comando junto con su identificador de proceso perf:
sudo perf record -p 2266 -g
El perf comando inicia el proceso de recopilación de rendimiento. Deje que se ejecute durante unos 20-30 segundos y presione Ctrl+C para salir del proceso de recopilación. Puede usar el mismo perf comando para ver la salida del seguimiento.
sudo perf report -f
También puede generar un gráfico de llamas mediante los siguientes comandos:
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 flamegraph.svg que puede ver en el explorador para investigar el problema de rendimiento:
Análisis de datos de CPU elevados 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 de los demás documentos necesarios, a una máquina Windows y, a continuación, abra el archivo *.nettrace en Visual Studio. Para obtener más información, consulte Análisis de datos de uso de CPU.
Consulte también
- dotnet-trace para enumerar procesos
- dotnet-counters para comprobar el uso de memoria administrada
- dotnet-dump para recopilar y analizar un archivo de volcado de memoria
- dotnet/diagnostics