Identifier précisément les lenteurs avec PerfView et dotnet-trace — Introduction pratique à l'analyse des performances .NET
· Go Komura · PerfView, dotnet-trace, ETW, Analyse des performances, .NET, CSharp, Enquête de bogue, Développement Windows, Conseil technique
L’article précédent, « Introduction au journal des événements Windows et à ETW », présentait ETW et la définition d’événements personnalisés avec EventSource, mais laissait l’analyse avec PerfView hors de son périmètre. Cet article reprend là où il s’arrêtait. Il explique comment utiliser PerfView et dotnet-trace pour identifier la fonction exacte responsable lorsqu’une application métier est « lente », « sature le CPU » ou « se fige parfois ».
Le sujet principal est l’enquête sur le CPU et le temps de réponse. L’analyse d’une mémoire qui augmente continuellement est traitée dans « Telling GC Pauses Apart from Memory Leaks in .NET », et les plantages dans « Reading Crash Dumps with WinDbg + SOS ».
1. L’essentiel d’abord
- Il existe deux sortes de « lenteur ». Celle où le CPU est saturé (CPU bound), et celle où le CPU est inactif mais l’application attend (blocked). La première exige l’échantillonnage CPU, la seconde une collecte ThreadTime (changements de contexte) : la collecte CPU par défaut ne révèle pas la cause de la seconde. 1
- En cas de doute, commencez par dotnet-trace. C’est un outil multiplateforme basé sur EventPipe et vous pouvez collecter sans privilèges administrateur, à condition d’être l’utilisateur ayant lancé le processus cible. 2 Ses fichiers
.nettraces’ouvrent dans PerfView ou Visual Studio. 3 - PerfView devient nécessaire lorsqu’il faut voir toute la machine, du code natif ou du temps bloqué. Sa base ETW lui permet de traiter aussi les événements noyau et les piles natives ; démarrer une session ETW nécessite en contrepartie des privilèges administrateur. 3
- L’échantillonnage CPU est par défaut effectué une fois par milliseconde (par processeur). Considérez chaque échantillon comme environ 1 ms de temps CPU et attendez au moins 1 000 échantillons, idéalement environ 5 000, avant de conclure : avec peu d’échantillons, les fonctions en tête peuvent n’être qu’un effet du hasard. 1
- L’interprétation commence par la différence entre inclusive (la fonction + tout ce qu’elle appelle) et exclusive (la fonction seule). Une valeur exclusive élevée signale un endroit qui consomme réellement du CPU ; une valeur inclusive élevée signale qu’un élément plus bas dans l’arbre est lourd.
- Avant de mesurer, définissez exactement une opération qui est « lente ». Une collecte alors que l’application est seulement « globalement lente » est difficile à lire. Fixez l’opération et le moment — par exemple « ce rapport prend 40 secondes à générer » — avant de collecter. La démarche de comparaison avant/après dans « How to Correctly Compare Program Speed Across Versions on Windows » est également utile.
Voici une table de décision pour choisir par où commencer selon le symptôme.
| Symptôme | Outil à essayer d’abord | Ce qu’il faut regarder |
|---|---|---|
| Le CPU reste durablement saturé | dotnet-trace collect / CPU Stacks de PerfView | Fonctions avec de grandes valeurs exclusives |
| Le CPU est faible mais le traitement est lent ou se fige | PerfView (collecte ThreadTime) | Quel thread est bloqué, à attendre quoi |
| C’est lent, mais vous voulez d’abord une tendance générale | dotnet-counters | Utilisation CPU, fréquence GC, accumulation de la file ThreadPool |
| Vous suspectez trop de GC | dotnet-counters → dotnet-trace (événements GC) | Nombre et durée des pauses GC, origine de la plupart des allocations |
| Vous voulez savoir où une opération métier précise est lente | Événements EventSource personnalisés + les outils ci-dessus | Temps écoulé entre les événements personnalisés et pile pendant cette fenêtre |
2. Comprendre la relation entre les outils — ETW et EventPipe
Il semble y avoir beaucoup d’outils, mais il n’y a en réalité que deux fondations.
- ETW (Event Tracing for Windows) : infrastructure de trace couvrant tout le système d’exploitation. Elle peut enregistrer noyau et application sur la même ligne de temps, mais démarrer ou arrêter une session nécessite les droits administrateur et elle est réservée à Windows. 3
- EventPipe : mécanisme de trace intégré au runtime .NET. Il ne nécessite pas les droits administrateur et se comporte de la même manière sur tous les systèmes d’exploitation, mais il est limité au code managé et au runtime : il ne capture ni les événements noyau ni les piles natives. 2
| dotnet-trace (EventPipe) | PerfView (ETW) | |
|---|---|---|
| Privilèges administrateur | Non requis (pour un processus appartenant au même utilisateur) | Requis |
| Cible | Un processus .NET indiqué | Toute la machine (tous les processus + le noyau) |
| Piles natives | Impossible à capturer | Peut les capturer |
| Temps bloqué (changements de contexte) | Impossible à capturer | Peut être capturé avec ThreadTime |
| Systèmes pris en charge | Windows / Linux / macOS | Windows uniquement |
Une fois cette correspondance assimilée, le flux naturel devient évident : commencer par une collecte légère avec dotnet-trace, puis recourir à la collecte ETW complète de PerfView si cela ne suffit pas.
3. Avant de collecter une trace — passez 10 minutes avec dotnet-counters
Avant de lancer directement une collecte de trace, il est souvent plus rapide de jeter un œil aux métriques clés du runtime avec dotnet-counters. 4
dotnet tool install --global dotnet-counters
dotnet-counters ps
dotnet-counters monitor --process-id <PID> --counters System.Runtime
Observez l’utilisation CPU, la taille du tas GC et le nombre de GC, la longueur de file et le nombre de threads du ThreadPool, ainsi que le nombre d’exceptions. Si vous voyez déjà une tendance — « le GC s’exécute plusieurs fois par seconde », « la file ThreadPool augmente constamment » — cela indique le type de trace à collecter ensuite, orientée allocations ou blocages. La lecture des tendances mémoire est détaillée dans « Telling GC Pauses Apart from Memory Leaks in .NET ».
4. Collecter une trace avec dotnet-trace
dotnet-trace est un outil de collecte basé sur EventPipe. 5 Son installation et la collecte de base sont les suivantes.
dotnet tool install --global dotnet-trace
dotnet-trace ps
dotnet-trace collect --process-id <PID> --duration 00:00:00:30
Sans option, il collecte avec le profil par défaut, qui comprend les événements essentiels du runtime et l’échantillonnage de threads. L’ancien profil cpu-sampling a été retiré ; le profil actuel par défaut combine dotnet-common et dotnet-sampled-thread-time. 5 Selon le besoin, vous pouvez aussi choisir --profile gc-verbose (GC et échantillonnage des allocations d’objets) ou --profile gc-collect (enregistre seulement les occurrences de GC, avec peu de surcharge).
Pour collecter, en plus du reste, le fournisseur EventSource personnalisé créé dans l’article précédent, ajoutez --providers.
dotnet-trace collect --process-id <PID> --providers KomuraSoft-OrderService
Le résultat est un fichier .nettrace. Il peut être ouvert dans Visual Studio ou PerfView, ou converti au format speedscope pour être vu dans un navigateur. 5
dotnet-trace convert trace.nettrace --format Speedscope
Le format speedscope est un graphique de flammes léger, visible sur speedscope.app, utile pour voir intuitivement « où le temps est passé et sous l’arbre d’appels de quelle fonction ». Pour une enquête plus rigoureuse jusqu’à la fonction précise, le visualiseur de piles de PerfView est plus puissant.
5. Enquêter sur le CPU avec PerfView — lire le Stack Viewer
PerfView est un outil gratuit d’enquête sur les performances publié par Microsoft ; il s’exécute dès que le fichier unique PerfView.exe est téléchargé depuis la page des versions GitHub, sans installation. 6
5.1 Collecte
Dans l’interface graphique, ouvrez « Collect > Collect », cliquez sur Start Collection, reproduisez l’opération cible, puis cliquez sur Stop Collection. En ligne de commande, exécutez ceci en administrateur car une session ETW doit être démarrée 3.
PerfView collect /nogui /acceptEULA /maxCollectSec:30
La collecte par défaut comprend un échantillon CPU de 1 ms, avec pile d’appels, sur chaque processeur, ainsi que les événements CLR essentiels. 1 La surcharge est généralement signalée comme étant de quelques pour cent avec la configuration par défaut. 7
5.2 Lire CPU Stacks
Ouvrez le résultat (.etl.zip), sélectionnez le processus cible dans « CPU Stacks » et le visualiseur de piles s’ouvre. Regardez d’abord deux colonnes de l’onglet By Name.
- Exc (exclusive) : nombre d’échantillons où cette fonction elle-même s’exécutait. L’endroit qui consomme réellement le CPU.
- Inc (inclusive) : total des échantillons pour cette fonction et tout ce qu’elle appelle. Indique qu’un élément plus bas dans l’arbre d’appels est lourd.
La méthode standard est de trier par Exc et de distinguer, depuis le haut, « est-ce mon code ou le runtime/une bibliothèque ? ». Si votre code est haut dans Exc, l’algorithme ou la boucle de cette fonction est la cible directe. Si des internes de System.String ou un sérialiseur JSON sont hauts dans Exc, remontez par l’onglet Callers avec Inc afin d’identifier où votre code appelle cette fonction si intensément.
Vérifiez aussi le nombre d’échantillons lui-même. Puisqu’un échantillon CPU est une statistique à intervalle de 1 ms, un faible nombre laisse le résultat au hasard. Avant de conclure, recueillez au moins 1 000 échantillons au total, idéalement environ 5 000 ; si cela ne suffit pas, prolongez la collecte en répétant l’opération cible. 1
Enfin, si le nom d’une fonction de votre module n’apparaît que comme une adresse, ses symboles (PDB) ne sont pas résolus. Conserver les PDB des artefacts de build est ce qui rend l’enquête possible. Voir « What Is a PDB (Program Database)? ».
6. « Lent même lorsque le CPU est inactif » — enquêter sur le temps bloqué avec ThreadTime
Plus de la moitié des lenteurs réelles ne concernent pas du tout le CPU, mais l’attente : attente d’un verrou, d’une réponse DB ou HTTP, d’E/S de fichier, ou attente proche d’un interblocage via Task.Result. Dans un échantillon CPU, cela apparaît comme du temps où le CPU n’était pas utilisé, donc la collecte par défaut ne révèle pas la cause.
Dans PerfView, activer l’option Thread Time pendant la collecte enregistre également les événements de changement de contexte et permet de suivre, dans une même vue, le temps qu’un thread a passé à « utiliser le CPU » ou à être « bloqué ». 1
PerfView collect /nogui /acceptEULA /threadTime /maxCollectSec:30
Pour l’analyse, ouvrez « Thread Time Stacks ». C’est le même visualiseur que CPU Stacks, mais les échantillons comprennent désormais BLOCKED_TIME (temps bloqué) en plus du temps CPU. Limitez la plage temporelle à l’opération lente et regardez quelle pile, quelle attente, accumule le BLOCKED_TIME du thread ayant traité le travail ; vous obtenez par exemple « 35 des 40 secondes totales ont été passées à attendre cet appel HTTP ».
Lorsqu’une interface se fige, le cœur du problème est presque toujours le blocage du thread UI. Après avoir identifié ce qui bloque ce thread avec ThreadTime, la correction durable consiste à reconcevoir l’attente synchrone en attente asynchrone. Pour l’aspect conception, consultez « A One-Page Cheat Sheet for async and the UI Thread in WPF/WinForms ».
Attention : ThreadTime enregistre un événement pour chaque changement de contexte. Le volume de données est donc nettement plus important que celui de la collecte par défaut. Gardez la fenêtre de collecte courte et évitez les longues collectes ThreadTime en production.
7. Associer EventSource — découper « quelle partie est lente » en termes métier
CPU Stacks et Thread Time sont agrégés pour tout le processus. Pour découper une seule opération métier, par exemple « où part le temps dans ce traitement de commande », utilisez les événements Start/Stop EventSource de l’article précédent.
- Côté application, instrumentez des événements tels que
OrderProcessingStart/OrderProcessingStop(voir l’article précédent pour l’implémentation) - Vérifiez le moment de l’événement dans la vue « Events » de PerfView, puis limitez la plage de temps du visualiseur de piles (filtre Start/End) à cette fenêtre
- Lisez la répartition CPU / temps bloqué dans cette plage restreinte
Ainsi, vous analysez isolément « cette seule exécution lente », sans qu’elle soit noyée dans le bruit du fonctionnement normal. Les événements personnalisés se collectant aussi avec dotnet-trace, une fois l’instrumentation ajoutée, la même technique fonctionne sur une machine de développement et en production. En pratique, la difficulté d’une enquête de performances dépend moins de la maîtrise des outils que de la présence de points d’observation intégrés à l’application.
Résumé
- Le point de départ est de séparer une lenteur CPU-bound d’une lenteur bloquée. La première n’apparaît qu’avec l’échantillonnage CPU (1 échantillon ≈ 1 ms), la seconde avec ThreadTime.
- La répartition de base est dotnet-trace d’abord, puisqu’il ne requiert pas les droits administrateur, puis PerfView lorsqu’il faut la machine entière, le code natif ou le temps bloqué. Collecter avec dotnet-trace puis lire le résultat dans PerfView est également une combinaison standard.
- La lecture du visualiseur de piles repose sur la distinction exclusive/inclusive ; vérifiez toujours que le nombre d’échantillons est suffisant.
- Des événements EventSource personnalisés marquant les limites d’une opération métier augmentent encore la précision de l’enquête.
Komura Software LLC prend en charge l’enquête sur les problèmes de performances des applications métier Windows — « lente », « figée », « CPU saturé » — ainsi que le conseil sur l’instrumentation et la conception qui rendent une application mesurable. Avec une procédure de reproduction et un fichier de trace, nous pouvons aussi assurer l’analyse seule.
Articles connexes
- Introduction au journal des événements Windows et à ETW — intégrer les journaux d’une application métier aux mécanismes standard de l’OS
- Telling GC Pauses Apart from Memory Leaks in .NET — Practical Steps for Observing, Comparing, and Proving Growing Memory
- Reading Crash Dumps with WinDbg + SOS — A Practical Introduction to Analysis After Collection
- An Introduction to Collecting Windows Crash Dumps — WER/ProcDump/WinDbg
- What Is a PDB (Program Database)? — Understanding Debug Info, Symbols, and Source Link
- How to Correctly Compare Program Speed Across Versions on Windows
- A One-Page Cheat Sheet for async and the UI Thread in WPF/WinForms
Domaines de conseil associés
- Analyse de dysfonctionnements et des causes racines
- Développement d’applications Windows
- Conseil technique et revue de conception
- Contact
Références
-
GitHub, PerfView User’s Guide. La collecte par défaut réalise un échantillon CPU avec pile d’appels toutes les 1 ms par processeur, environ 1 000 à 5 000 échantillons sont souhaitables pour conclure, et l’option Thread Time collecte les changements de contexte pour analyser aussi le temps bloqué. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, EventPipe Overview. EventPipe permet de tracer des applications .NET sans composant à hauts privilèges tel que les droits administrateur, mais se limite au code managé et au runtime et ne capture ni événements noyau ni piles natives. ↩ ↩2
-
Microsoft Learn, Collect and View EventSource Traces. La collecte ETW exige toujours les droits administrateur et Visual Studio comme PerfView peuvent ouvrir les fichiers .nettrace. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, dotnet-counters diagnostic tool. Surveillance des métriques CPU, GC, ThreadPool et autres d’un processus actif par les compteurs System.Runtime. ↩
-
Microsoft Learn, dotnet-trace diagnostic tool. Utilisation de collect, profils activés par défaut (dotnet-common / dotnet-sampled-thread-time), retrait de cpu-sampling, profils gc-verbose / gc-collect et conversion vers Speedscope / Chromium. ↩ ↩2 ↩3
-
GitHub, microsoft/perfview. PerfView est un outil gratuit d’analyse des performances pour les problèmes CPU et mémoire, et l’exécutable peut être obtenu directement depuis la page des versions. ↩
-
GitHub, microsoft/perfview Issue #598. Un responsable de PerfView indique une surcharge de la collecte par défaut d’environ 3 %, et la charge peut être réduite en ajustant l’intervalle avec /CpuSampleMSec. ↩
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Introduction au journal des événements Windows et à ETW — placer les journaux de votre application métier sur les mécanismes standard de l'OS
Votre application métier Windows repose-t-elle seulement sur les journaux de fichiers ? Le journal des événements et ETW sont visibles à ...
Impression et sortie PDF dans les applications métier Windows — choisir entre System.Drawing.Printing, WPF et bibliothèques de rapports
Organise l'impression WinForms avec PrintDocument, l'impression WPF FlowDocument/FixedDocument et les options de sortie PDF dans une tabl...
Au-delà de appsettings.json — guide pratique de la gestion de configuration dans les applications métier Windows (environnements, secrets et emplacements d'écriture)
Guide pratique de la configuration des applications métier Windows : superposition de appsettings.json, choix entre IConfiguration et IOp...
Lancer Google Ads avec un petit budget BtoB — concevoir et exploiter une routine hebdomadaire efficace avec quelques dizaines de milliers de yens par mois
Guide pratique de Google Ads pour les entreprises BtoB souhaitant démarrer avec seulement quelques dizaines de milliers de yens par mois....
Faire apparaître son site pour les recherches par nom de zone — guide pratique du SEO local pour les PME (pages de zone et Google Business Profile)
Pour les PME dont le site n'apparaît pas sur une recherche « nom de zone + secteur ». Cet article présente l'ordre de correction du SEO l...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Analyse de bugs et incidents de longue durée
Pannes intermittentes, diagnostic des communications, crashs après longue exécution et tests des chemins d'échec.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Analyse des bugs et des causes
Identifier la cause d'un comportement « lent » ou « figé » est en soi une enquête de bogue liée aux performances.
Développement d'applications Windows
Concevoir une application facile à mesurer — par exemple l'instrumenter avec EventSource — relève du conseil en développement d'applications Windows.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Dois-je utiliser PerfView ou dotnet-trace ?
- Commencez par dotnet-trace. Il fonctionne sans privilèges administrateur, permet de cibler uniquement le processus qui vous intéresse et s'utilise avec une seule ligne de commande. En revanche, si vous devez voir les piles de code natif, l'état de toute la machine — l'influence d'autres processus ou du noyau — ou suivre le temps bloqué au niveau des changements de contexte, il faut PerfView, basé sur ETW. Il est aussi courant de collecter avec dotnet-trace puis d'ouvrir le fichier .nettrace obtenu dans PerfView pour l'analyser.
- Quel est le lien avec le profileur de Visual Studio ?
- Si le problème se reproduit sur une machine de développement, l'outil CPU Usage et les outils mémoire de Visual Studio sont plus pratiques et suffisent généralement. PerfView et dotnet-trace deviennent utiles lorsque la collecte doit se faire sur une machine de test ou de production où Visual Studio ne peut pas être installé, lorsque vous voulez séparer collecte et analyse sur deux machines, ou lorsque vous devez voir des événements ETW, y compris des événements EventSource personnalisés ou du noyau. Visual Studio peut aussi ouvrir les fichiers .nettrace produits par dotnet-trace.
- Peut-on les exécuter sans risque sur un serveur de production ?
- Les deux outils sont pensés pour des collectes courtes en production, mais cela n'est pas inconditionnel. Limitez la durée à quelques dizaines de secondes ou quelques minutes, essayez d'abord la même commande en préproduction pour vérifier la surcharge et la taille du fichier, et confirmez l'espace disque libre. La collecte ThreadTime (changement de contexte) et le traçage des allocations produisent particulièrement beaucoup d'événements. Une trace peut aussi contenir des informations telles que des arguments de ligne de commande : traitez le fichier obtenu avec la même prudence que tout artefact sensible.
- Comment se situent WPR/WPA dans cet ensemble ?
- WPR (Windows Performance Recorder) et WPA (Windows Performance Analyzer) sont des outils d'investigation davantage orientés système d'exploitation, construits sur la même base ETW. Pour une analyse détaillée de toute la machine — E/S disque, alimentation, démarrage, etc. — WPR/WPA est le meilleur choix. Pour enquêter sur le CPU, le GC et le temps bloqué d'une application .NET, PerfView est plus facile à lire, car son affichage est optimisé pour le code managé. Pour une application métier, PerfView et dotnet-trace couvrent la grande majorité des cas.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics