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 :

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 :

Flame graph SVG image

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

Étapes suivantes