Déboguer une utilisation élevée du processeur dans .NET Core
Cet article s’applique à : ✔️ SDK .NET Core 3.1 et versions ultérieures
Dans ce didacticiel, vous apprendrez à déboguer un scénario d’utilisation excessive du processeur. À l’aide de l’exemple fourni de référentiel de code source d’application web ASP.NET Core web app, vous pouvez provoquer un blocage intentionnellement. Le point de terminaison cesse de répondre et rencontre l’accumulation de threads. Vous découvrirez comment utiliser différents outils pour diagnostiquer ce scénario avec plusieurs éléments clés de données de diagnostic.
Durant ce tutoriel, vous allez effectuer les opérations suivantes :
- Examiner l’utilisation élevée du processeur
- Déterminer l’utilisation du processeur avec dotnet-counters
- Utiliser dotnet-trace pour la génération de traces
- Performances des profils dans PerfView
- Diagnostiquer et résoudre une utilisation excessive du processeur
Prérequis
Le didacticiel utilise :
- SDK .NET Core 3.1 ou une version ultérieure.
- Échantillon de cible de débogage pour déclencher le scénario.
- dotnet-trace pour répertorier les processus et générer un profil.
- dotnet-counters pour surveiller l’utilisation du processeur.
Compteurs UC
Avant d’essayer de collecter des données de diagnostic, vous devez observer une condition de processeur élevée. Exécutez l’échantillon d’application à l’aide de la commande suivante, à partir du répertoire racine du projet.
dotnet run
Pour rechercher l’ID de processus, utilisez la commande suivante :
dotnet-trace ps
Prenez note de l’ID de processus à partir de la sortie de votre commande. Notre ID de processus était 22884
, mais le vôtre sera différent. Pour vérifier l’utilisation actuelle du processeur, utilisez la commande de l’outil dotnet-counters :
dotnet-counters monitor --refresh-interval 1 -p 22884
refresh-interval
est le nombre de secondes entre les valeurs du processeur d’interrogation du compteur. La sortie doit ressembler à ce qui suit :
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
Une fois l’application web en cours d’exécution, immédiatement après le démarrage, le processeur n’est pas consommé du tout et est signalé à 0%
. Accédez à l’itinéraire api/diagscenario/highcpu
avec 60000
comme paramètre d’itinéraire :
https://localhost:5001/api/diagscenario/highcpu/60000
À présent, réexécutez la commande dotnet-counters . Si vous souhaitez surveiller uniquement le compteur cpu-usage
, ajoutez « ----counters System.Runtime[cpu-usage] » à la commande précédente. Nous ne sommes pas certains que le processeur soit consommé. Nous allons donc surveiller la même liste de compteurs que ci-dessus pour vérifier que les valeurs des compteurs se trouvent dans la plage attendue pour notre application.
dotnet-counters monitor -p 22884 --refresh-interval 1
Vous devez voir une augmentation de l’utilisation du processeur comme indiqué ci-dessous (en fonction de l’ordinateur hôte, attendez-vous à une utilisation variable du processeur) :
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
Pendant toute la durée de la demande, l’utilisation du processeur oscille autour du pourcentage augmenté.
Conseil
Pour visualiser une utilisation encore plus élevée du processeur, vous pouvez employer ce point de terminaison dans plusieurs onglets de navigateur simultanément.
À ce stade, on peut affirmer que le processeur s’exécute de manière plus élevée que prévu. L’identification des effets d’un problème est essentielle pour en trouver la cause. Nous allons utiliser l’effet de la consommation élevée du processeur en plus des outils de diagnostic pour trouver la cause du problème.
Analyser un processeur élevé avec Profiler
Lors de l’analyse d’une application avec une utilisation élevée du processeur, vous avez besoin d’un outil de diagnostic qui peut fournir des informations sur ce que fait le code. Le choix habituel est un profileur, et il existe différentes options de profileur parmi lesquelles choisir. dotnet-trace
peut être utilisé sur tous les systèmes d’exploitation, cependant, ses limitations de biais de safe-point et les piles d’appels gérées uniquement aboutissent à des informations plus générales par rapport à un profileur prenant en charge le noyau comme « perf » pour Linux ou ETW pour Windows. Si votre investigation des performances implique uniquement du code managé, elle sera généralement dotnet-trace
suffisante.
L’outil perf
peut être utilisé pour générer des profils d’application .NET Core. Nous allons illustrer cet outil, bien que dotnet-trace puisse également être utilisé. Quittez l’instance précédente de l’échantillon de cible de débogage.
Définissez la variable d’environnement DOTNET_PerfMapEnabled
pour que l’application .NET crée un fichier map
dans le répertoire /tmp
. Ce fichier map
est utilisé par perf
pour mapper les adresses du processeur aux fonctions générées par JIT par nom. Pour obtenir plus d’informations, consultez Exporter des mappages de perf et des vidages jit.
Remarque
.NET 6 se normalise sur le préfixe DOTNET_
au lieu de COMPlus_
pour les variables d’environnement qui configurent le comportement au moment de l’exécution de .NET. Toutefois, le préfixe COMPlus_
continuera à fonctionner. Si vous utilisez une version précédente du runtime .NET, vous devez tout de même utiliser le préfixe COMPlus_
.
Exécutez l’échantillon de cible de débogage dans la même session de terminal.
export DOTNET_PerfMapEnabled=1
dotnet run
Exercez à nouveau le point de terminaison d’API de processeur élevé (https://localhost:5001/api/diagscenario/highcpu/60000
). Pendant qu’il s’exécute pendant la requête de 1 minute, exécutez la commande perf
avec votre ID de processus :
sudo perf record -p 2266 -g
La commande perf
démarre le processus de collection des performances. Laissez-le s’exécuter pendant environ 20 à 30 secondes, puis appuyez sur Ctrl+C pour quitter le processus de collection. Vous pouvez utiliser la même commande perf
pour voir la sortie de la trace.
sudo perf report -f
Vous pouvez également générer un graphique de flamme à l’aide des commandes suivantes :
git clone --depth=1 https://github.com/BrendanGregg/FlameGraph
sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
Cette commande génère un flamegraph.svg
que vous pouvez afficher dans le navigateur pour examiner le problème de performances :
Analyse de données de processeur élevée avec Visual Studio
Tous les fichiers *.nettrace peuvent être analysés dans Visual Studio. Pour analyser un fichier *.nettrace Linux dans Visual Studio, transférez le fichier *.nettrace, en plus des autres documents nécessaires, vers un ordinateur Windows, puis ouvrez le fichier *.nettrace dans Visual Studio. Pour plus d’informations, consultez Analyser les d’utilisation du processeur.
Voir aussi
- dotnet-trace pour répertorier les processus
- dotnet-counters pour vérifier l’utilisation de la mémoire managée
- dotnet-dump pour collecter et analyser un fichier image mémoire
- dotnet/diagnostics