Eseguire il debug dell'utilizzo elevato della CPU in .NET Core

Questo articolo si applica a: ✔️ .NET Core 3.1 SDK e versioni successive

In questa esercitazione si apprenderà come eseguire il debug di uno scenario di utilizzo eccessivo della CPU. Usando l'esempio fornito nel repository del codice sorgente dell'app Web ASP.NET Core, è possibile causare intenzionalmente un deadlock. L'endpoint smetterà di rispondere e si verificherà un accumulo di thread. Si apprenderà come usare vari strumenti per diagnosticare questo scenario con diversi dati di diagnostica chiave.

Questa esercitazione illustra come:

  • Analizzare l'utilizzo elevato della CPU
  • Determinare l'utilizzo della CPU con dotnet-counters
  • Usare dotnet-trace per la generazione di tracce
  • Profilare le prestazioni in PerfView
  • Diagnosticare e risolvere un utilizzo eccessivo della CPU

Prerequisiti

L'esercitazione usa:

Contatori CPU

Prima di tentare di raccogliere i dati di diagnostica, è necessario osservare una condizione di utilizzo elevato della CPU. Eseguire l'applicazione di esempio con il comando seguente dalla directory radice del progetto.

dotnet run

Per trovare l'ID del processo, usare il comando seguente:

dotnet-trace ps

Prendere nota dell'ID del processo dall'output del comando. L'ID del processo nell'esempio era 22884, ma sarà diverso in altre condizioni. Per controllare l'utilizzo corrente della CPU, usare il comando dello strumento dotnet-counters:

dotnet-counters monitor --refresh-interval 1 -p 22884

refresh-interval è il numero di secondi che intercorre tra i polling del contatore per il recupero dei valori della CPU. L'output avrà un aspetto analogo al seguente:

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 l'app Web in esecuzione, subito dopo l'avvio, la CPU non viene affatto usata e l'utilizzo segnalato è 0%. Passare alla route api/diagscenario/highcpu con 60000 come parametro di route:

https://localhost:5001/api/diagscenario/highcpu/60000

A questo punto, eseguire di nuovo il comando dotnet-counters. Se si è interessati al monitoraggio solo del contatore cpu-usage, aggiungere '--counters System.Runtime[cpu-usage]' al comando precedente. Non si è certi che la CPU sia in uso, quindi verrà monitorato lo stesso elenco di contatori precedente per verificare che i valori dei contatori siano compresi nell'intervallo previsto per l'applicazione.

dotnet-counters monitor -p 22884 --refresh-interval 1

Si dovrebbe notare un aumento dell'utilizzo della CPU, come illustrato di seguito (a seconda del computer host, prevedere un utilizzo diverso della 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

Per tutta la durata della richiesta, l'utilizzo della CPU si attesterà intorno alla percentuale aumentata.

Suggerimento

Per visualizzare un utilizzo ancora più elevato della CPU, è possibile eseguire questo endpoint in più schede del browser contemporaneamente.

A questo punto, è possibile affermare senza dubbio che l'utilizzo della CPU è più alto del previsto. Identificare gli effetti di un problema è fondamentale per trovare la causa. Si userà l'effetto dell'utilizzo elevato della CPU oltre agli strumenti di diagnostica per individuare la causa del problema.

Analizzare l'utilizzo elevato della CPU con un profiler

Quando si analizza un'app con un utilizzo elevato della CPU, è necessario uno strumento di diagnostica in grado di fornire informazioni dettagliate sulle operazioni eseguite dal codice. La scelta abituale è un profiler e sono disponibili diverse opzioni tra cui scegliere. dotnet-trace può essere usato in tutti i sistemi operativi, tuttavia, le sue limitazioni per la distorsione del punto sicuro e gli stack di chiamate solo per codice gestito generano informazioni più generali rispetto a un profiler in grado di riconoscere il kernel come 'perf' per Linux o ETW per Windows. Se l'analisi delle prestazioni prevede solo codice gestito, in genere dotnet-trace sarà sufficiente.

Lo strumento perf può essere usato per generare profili di app .NET Core. Verrà proposta una dimostrazione di questo strumento, anche se si potrebbe usare anche dotnet-trace. Uscire dall'istanza precedente della destinazione di debug di esempio.

Impostare la variabile di ambiente DOTNET_PerfMapEnabled per fare in modo che l'app .NET crei un file map nella directory /tmp. Questo file map viene usato da perf per eseguire il mapping degli indirizzi della CPU alle funzioni generate da JIT in base al nome. Per altre informazioni, vedere Esportare mappe delle prestazioni e dump jit.

Nota

.NET 6 usa come standard il prefisso DOTNET_ anziché COMPlus_ per le variabili di ambiente che configurano il comportamento di runtime di .NET. Tuttavia, il prefisso COMPlus_ continuerà a funzionare. Se si usa una versione precedente del runtime .NET, è comunque consigliabile usare il prefisso COMPlus_ per le variabili di ambiente.

Eseguire la destinazione di debug di esempio nella stessa sessione del terminale.

export DOTNET_PerfMapEnabled=1
dotnet run

Eseguire di nuovo l'endpoint dell'API di uitlizzo della CPU elevato (https://localhost:5001/api/diagscenario/highcpu/60000). Mentre è in esecuzione all'interno della richiesta di 1 minuto, eseguire il comando perf con l'ID del processo:

sudo perf record -p 2266 -g

Il comando perf avvia il processo di raccolta delle prestazioni. Lasciarlo in esecuzione per circa 20-30 secondi, quindi premere CTRL+C per uscire dal processo di raccolta. È possibile usare lo stesso comando perf per visualizzare l'output della traccia.

sudo perf report -f

È anche possibile generare un Flame Graph usando i comandi seguenti:

git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg

Questo comando genera un flamegraph.svg che è possibile visualizzare nel browser per analizzare il problema di prestazioni:

Flame graph SVG image

Analisi dei dati di utilizzo elevato della CPU con Visual Studio

Tutti i file *.nettrace possono essere analizzati in Visual Studio. Per analizzare un file *.nettrace Linux in Visual Studio, trasferire il file *.nettrace, oltre agli altri documenti necessari, in un computer Windows e quindi aprire il file *.nettrace in Visual Studio. Per altre informazioni, vedere Analizzare i dati di utilizzo della CPU.

Vedi anche

Passaggi successivi