Partager via


Isoler un problème de performances (C#, Visual Basic, F#)

Dans cet article, vous allez apprendre comment utiliser des outils de profilage pour examiner les problèmes de performances et isoler les domaines problématiques.

Au lieu de fournir des instructions pas à pas, notre intention est de vous montrer comment utiliser efficacement les outils de profilage et comment interpréter les données. Comme l’outil Utilisation de l’UC, l’outil Compteurs .NET constitue également un bon point de départ pour un examen des performances. Une fois que vous avez identifié des données intéressantes, vous pouvez utiliser d’autres outils de profilage pour examiner plus en détail. Pour comparer les outils, consultez Quel outil choisir ?

À propos de l’exemple d’application

Les captures d’écran présentées dans cet article sont basées sur une application ASP.NET qui exécute des requêtes sur une base de données simulée. L’exemple est basé sur l’Exemple Diagnostics.

Démarrer un examen

  • Démarrez votre examen en regardant les indicateurs de compteur .NET lors de la collecte des données de performances.
  • Ensuite, pour obtenir des informations supplémentaires pour isoler les problèmes, envisagez de collecter une trace à l’aide de l’un des autres outils de profilage, tels que l’outil Utilisation de l’UC, l’outil Instrumentation et autres.

La collecte de données nécessite les étapes suivantes (non affichées dans cet article) :

  • Définir votre application sur une build de mise en production.
  • Sélectionnez l’outil Compteurs .NET dans le Profileur de performances (Alt+F2). (Les étapes ultérieures impliquent l’outil Instrumentation.)
  • À partir du Profileur de performances, démarrez l’application.

Vérifier les compteurs de performances

Lors de l’exécution de l’application, affichez les compteurs dans l’outil Compteurs .NET. Pour les examens initiaux, quelques indicateurs clés à surveiller comprennent :

  • CPU Usage. Regardez ce compteur pour déterminer si un problème de performances se produit avec une utilisation élevée ou faible de l’UC. Il peut s’agir d’un indice de types spécifiques de problèmes de performances. Par exemple :
    • Avec une utilisation élevée de l’UC, utilisez l’outil Utilisation de l’UC pour identifier les endroits où vous pouvez optimiser le code. Pour suivre un didacticiel sur ce sujet, consultez le Guide du débutant pour optimiser le code.
    • Avec une faible utilisation de l’UC, utilisez l’outil Instrumentation pour identifier les nombres d’appels et le temps de fonction moyen en fonction de l’heure d’horloge murale. Cela peut vous aider à identifier des problèmes tels que la contention ou la privation de pool de threads.
  • Allocation Rate. Pour une application web qui sert des requêtes, le taux doit être assez stable.
  • GC Heap Size. Regardez ce compteur pour voir si l’utilisation de la mémoire augmente continuellement et fuite potentiellement. Si elle semble élevée, vous pouvez utiliser l’un des outils d’utilisation de la mémoire.
  • Threadpool Thread Count. Pour une application web qui sert des requêtes, regardez ce compteur pour voir si le nombre de threads est stable ou augmente à un rythme régulier.

Voici un exemple montrant comment la valeur CPU Usage est faible, tandis que le valeur ThreadPool Thread Count est relativement élevée.

Capture d’écran des compteurs affichés dans l’outil Compteurs .NET.

Une augmentation constante du nombre de threads avec une faible utilisation de l’UC peut être un indicateur de privation du pool de threads. Le pool de threads est forcé de continuer à faire tourner de nouveaux threads. La privation de pool de threads se produit lorsque le pool n’a pas de threads disponibles pour traiter de nouveaux éléments de travail et entraîne souvent lenteur de réponse des applications.

En fonction de l’utilisation faible de l’UC et du nombre de threads relativement élevés, et en travaillant sur la théorie d’un cas possible de privation de pool de threads, basculez vers l’utilisation de l’outil Instrumentation.

Examiner les nombres d’appels et les données temporelles

Examinons une trace de l’outil Instrumentation pour voir si nous pouvons essayer d’en savoir plus sur ce qui se passe au niveau des threads.

Lorsque les données de diagnostic se chargent, tout d’abord vérifiez la page de rapport .diagsession initiale qui affiche Insights supérieurs et le chemin chaud. Dans la trace Instrumentation, le chemin chaud affiche le chemin du code avec les temps de fonction les plus longs dans votre application. Ces sections peuvent fournir des conseils pour vous aider à identifier rapidement les problèmes de performances que vous pouvez améliorer.

Dans la trace collectée, utilisez le lien Ouvrir les détails dans le rapport, puis sélectionnez Graphique en flamme.

Capture d’écran du graphique en flamme dans l’outil Instrumentation.

La visualisation avec le graphique en flamme nous montre que la fonction QueryCustomerDB est responsable d’une partie importante du temps d’exécution de l’application.

Cliquez avec le bouton droit sur la fonction QueryCustomerDB et choisissez Affichage dans l’arborescence des appels.

Capture d’écran de l’arborescence des appels dans l’outil Instrumentation.

Dans l’arborescence des appels, vous voyez que le chemin chaud (icône de flamme) inclut la fonction QueryCustomerDB, qui pointe vers un problème potentiel de performances.

Par rapport au temps passé dans d’autres fonctions, les valeurs Self et Avg Self pour la fonction QueryCustomerDB sont très élevées. Contrairement à Total et Avg Total, les valeurs Self excluent le temps passé dans d’autres fonctions. Il s’agit donc d’un bon endroit pour rechercher le goulot d’étranglement de performances.

Conseil

Si les valeurs Self étaient relativement basses au lieu d’être élevées, vous aurez probablement intérêt à examiner les requêtes réelles appelées par la fonction QueryCustomerDB.

Double-cliquez sur la fonction QueryCustomerDB pour afficher le code source de la fonction.

public ActionResult<string> QueryCustomerDB()
{

    Task dbTask = QueryCustomerFromDbAsync("Dana");
    return "success:tasksleepwait";
}

Avec une petite recherche, on découvre que ce code appelle une API asynchrone sans utiliser await. Il s’agit du modèle de code sync-over-async, est une cause de privation de pool de threads et êut bloquer les threads.

Pour résoudre ce problème, utilisez await.

public async Task<ActionResult<string>> TaskAsyncWait()
{
    Customer c = await PretendQueryCustomerFromDbAsync("Dana");
    return "success:taskasyncwait";
}

Si vous constatez des problèmes de performances liés aux requêtes de base de données, vous pouvez utiliser l’outil Base de données pour déterminer si certains appels sont plus lents. Ces données peuvent indiquer une opportunité d’optimisation des requêtes. Pour obtenir un didacticiel qui montre comment utiliser l’outil Base de données pour examiner un problème de performances, consultez le Guide du débutant pour optimiser le code. L’outil Base de données prend en charge .NET Core avec ADO.NET ou Entity Framework Core.

Pour obtenir des visualisations dans Visual Studio d’un comportement de thread individuel, vous pouvez utiliser la fenêtre Piles parallèles lors du débogage. Cette fenêtre affiche les threads individuels, ainsi que des informations sur les threads qui attendent, les threads qu’ils attendent et les blocages.

Pour plus d’informations sur la privation de pool de threads, consultez Détection de la privation de pool de threads.

Étapes suivantes

Les articles et billets de blog suivants fournissent plus d’informations pour vous aider à apprendre à utiliser efficacement les outils de performances Visual Studio.