Depurar o alto uso de CPU no .NET Core
Este artigo se aplica a: ✔️ SDK do .NET Core 3.1 e versões posteriores
Neste tutorial, você aprenderá a depurar um cenário de uso excessivo de CPU. Usando o repositório de código-fonte do aplicativo Web ASP.NET Core de exemplo fornecido, você pode causar um deadlock intencionalmente. O ponto de extremidade interromperá a resposta e experimentará o acúmulo de threads. Você aprenderá a usar várias ferramentas para diagnosticar esse cenário com várias partes importantes dos dados de diagnóstico.
Neste tutorial, você irá:
- Investigar o alto uso da CPU
- Determinar o uso da CPU com dotnet-counters
- Usar o dotnet-trace para geração de rastreamento
- Desempenho de perfil no PerfView
- Diagnosticar e resolver o uso excessivo de CPU
Pré-requisitos
O tutorial usa:
- O SDK do .NET Core 3.1 ou uma versão posterior.
- Exemplo de destino de depuração para disparar o cenário.
- dotnet-trace para listar processos e gerar um perfil.
- dotnet-counters para monitorar o uso da CPU.
Contadores de CPU
Antes de tentar coletar dados de diagnóstico, você precisa observar uma condição de CPU alta. Execute o aplicativo de exemplo usando o comando a seguir no diretório raiz do projeto.
dotnet run
Para localizar a ID do processo, use o seguinte comando:
dotnet-trace ps
Anote a ID do processo da saída do comando. Nossa ID do processo era 22884
, mas a sua será diferente. Para verificar o uso atual da CPU, use o comando da ferramenta dotnet-counters:
dotnet-counters monitor --refresh-interval 1 -p 22884
refresh-interval
é o número de segundos entre os valores de CPU de sondagem do contador. A saída deve ser semelhante ao seguinte:
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
Com o aplicativo Web em execução, imediatamente após a inicialização, a CPU não está sendo consumida e é relatada em 0%
. Navegue até a rota api/diagscenario/highcpu
com 60000
como o parâmetro de rota:
https://localhost:5001/api/diagscenario/highcpu/60000
Agora, execute novamente o comando dotnet-counters. Se você quiser monitorar apenas o contador cpu-usage
, adicione '--counters System.Runtime[cpu-usage]` ao comando anterior. Não temos certeza se a CPU está sendo consumida, portanto, vamos monitorar a mesma lista de contadores acima para verificar se os valores de contadores estão dentro do intervalo esperado para o aplicativo.
dotnet-counters monitor -p 22884 --refresh-interval 1
Você deve ver um aumento no uso da CPU, conforme mostrado abaixo (dependendo do computador host, o uso da CPU pode variar):
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 todo o período da solicitação, o uso da CPU ficará em torno do percentual aumentado.
Dica
Para visualizar um uso ainda maior da CPU, você pode executar esse ponto de extremidade em várias guias do navegador simultaneamente.
Neste ponto, você pode dizer com segurança que a CPU está com uma execução maior do que a esperada. A identificação dos efeitos de um problema é fundamental para localizar a causa. Usaremos o efeito do alto consumo de CPU além das ferramentas de diagnóstico para encontrar a causa do problema.
Analisar o alto uso de CPU com um criador de perfil
Ao analisar um aplicativo com alto uso de CPU, você precisa de uma ferramenta de diagnóstico que forneça insights sobre o que o código está fazendo. A escolha usual é um criador de perfil e há diferentes opções de criador de perfil para escolher. O dotnet-trace
pode ser usado em todos os sistemas operacionais, no entanto, suas limitações de desvio de ponto seguro e as pilhas de chamadas somente gerenciadas resultam em informações mais gerais em comparação com um criador de perfil com reconhecimento de kernel, como o 'perf' para Linux ou o ETW para Windows. Se a investigação de desempenho envolver apenas o código gerenciado, geralmente dotnet-trace
será suficiente.
A ferramenta perf
pode ser usada para gerar perfis de aplicativo .NET Core. Demonstraremos essa ferramenta, embora o dotnet-trace também possa ser usado. Saia da instância anterior do destino de depuração de exemplo.
Defina a variável de ambiente DOTNET_PerfMapEnabled
para fazer com que o aplicativo .NET crie um arquivo map
no diretório /tmp
. Esse arquivo map
é usado para perf
mapear endereços de CPU para funções geradas de modo JIT por nome. Para obter mais informações, confira Exportar mapas de desempenho e despejos JIT.
Observação
O .NET 6 usa o prefixo DOTNET_
como padrão em vez de COMPlus_
para variáveis de ambiente que configuram o comportamento de tempo de execução do .NET. No entanto, o prefixo COMPlus_
continuará funcionando. Se você estiver usando uma versão anterior do runtime do .NET, continue usando o prefixo COMPlus_
para variáveis de ambiente.
Execute o destino de depuração de exemplo na mesma sessão de terminal.
export DOTNET_PerfMapEnabled=1
dotnet run
Execute o ponto de extremidade da API com alto uso de CPU (https://localhost:5001/api/diagscenario/highcpu/60000
) novamente. Durante a execução na solicitação de 1 minuto, execute o comando perf
com a ID do processo:
sudo perf record -p 2266 -g
O comando perf
inicia o processo de coleta de desempenho. Deixe-o em execução por cerca de 20 a 30 segundos e pressione Ctrl+C para sair do processo de coleta. Você pode usar o mesmo comando perf
para ver a saída do rastreamento.
sudo perf report -f
Você também pode gerar um gráfico de chamas usando os seguintes comandos:
git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
Esse comando gera um flamegraph.svg
que você pode ver no navegador para investigar o problema de desempenho:
Como analisar dados de alto uso de CPU com o Visual Studio
Todos os arquivos *.nettrace podem ser analisados no Visual Studio. Para analisar um arquivo *.nettrace do Linux no Visual Studio, transfira o arquivo *.nettrace, além dos outros documentos necessários, para um computador Windows e abra o arquivo *.nettrace no Visual Studio. Para obter mais informações, confira Como analisar dados de alto uso de CPU).
Confira também
- dotnet-trace para listar processos
- dotnet-counters para verificar o uso de memória gerenciada
- dotnet-dump para coletar e analisar um arquivo de despejo
- dotnet/diagnostics