Configuration d'un environnement de profilage
Mise à jour : novembre 2007
Le fonctionnement de l'application et du profileur pendant leur exécution a fait l'objet d'une description dans les précédentes rubriques. Mais comment une connexion est-elle établie entre les deux au démarrage d'une application ? Le Common Language Runtime (CLR) établit la connexion pendant son initialisation dans chaque processus. Il décide de se connecter à un profileur ou non. S'il décide s'y connecter, il localise le profileur en vérifiant la valeur de deux variables d'environnement dans l'ordre suivant :
COR_ENABLE_PROFILING : le CLR ne se connecte à un profileur que si cette variable d'environnement existe et a la valeur 1.
COR_PROFILER : en cas de réussite de la vérification de COR_ENABLE_PROFILING, le CLR se connecte au profileur qui a ce CLSID ou ce ProgID qui a dû être préalablement stocké dans le Registre. La variable d'environnement COR_PROFILER est définie en tant que chaîne, comme indiqué dans les deux exemples suivants.
set COR_PROFILER={32E2F4DA-1BEA-47ea-88F9-C5DAF691C94A} set COR_PROFILER="MyProfiler"
Pour profiler une application du CLR, vous devez par conséquent définir les variables d'environnement COR_ENABLE_PROFILING et COR_PROFILER avant de lancer l'application. Vous devez par ailleurs vous assurer que la DLL du profileur est enregistrée.
Portée des variables d'environnement
La façon dont vous définissez les variables d'environnement COR_ENABLE_PROFILING et COR_PROFILER déterminent leur champ d'influence. Vous pouvez définir ces variables de l'une des manières suivantes :
Si vous définissez les variables dans un appel ICorDebug::CreateProcess, elles ne s'appliquent alors qu'à l'application en cours d'exécution. (Elles s'appliquent également aux autres applications démarrées par cette application qui héritent de l'environnement.).
Si vous définissez les variables dans une fenêtre d'invite de commandes, elles s'appliquent à toutes les applications qui sont démarrées à partir de cette fenêtre.
Si vous définissez les variables au niveau de l'utilisateur, elles s'appliquent à toutes les applications que vous démarrez avec l'Explorateur Windows. Lorsque vous ouvrez une fenêtre d'invite de commandes après avoir défini les variables, cette fenêtre possède ces paramètres d'environnement, tout comme les applications que vous démarrez à partir de cette fenêtre. Pour définir des variables d'environnement au niveau de l'utilisateur, cliquez avec le bouton droit sur Poste de travail, cliquez sur Propriétés, sur l'onglet Avancé, sur Variables d'environnement et ajoutez les variables à la liste Variables utilisateur.
Si vous définissez les variables au niveau de l'ordinateur, elles s'appliquent à toutes les applications qui sont démarrées sur cet ordinateur. Lorsque vous ouvrez une fenêtre d'invite de commandes sur cet ordinateur, cette fenêtre possède ces paramètres d'environnement, tout comme les applications que vous démarrez à partir de cette fenêtre. En d'autres termes, chaque processus managé sur cet ordinateur va démarrer avec votre profileur. Pour définir des variables d'environnement au niveau de l'ordinateur, cliquez avec le bouton droit sur Poste de travail, cliquez sur Propriétés, sur l'onglet Avancé, sur Variables d'environnement, ajoutez les variables à la liste Variables système et redémarrez l'ordinateur. Une fois redémarré, les variables sont disponibles à l'échelle du système.
Lorsque vous profilez un service Windows, vous devez redémarrer l'ordinateur après avoir défini les variables d'environnement et vous devez enregistrer la DLL du profileur. Pour plus d'informations à ce sujet, consultez Profilage d'un service Windows.
Considérations supplémentaires
La classe du profileur implémente les interfaces ICorProfilerCallback et ICorProfilerCallback2. Dans la version 2.0 du .NET Framework, un profileur doit implémenter ICorProfilerCallback2. Dans le cas contraire, ICorProfilerCallback2 n'est pas chargé.
Un seul profileur peut profiler un processus à un moment donné dans un environnement donné. Vous pouvez enregistrer deux profileurs différents dans des environnements différents, mais chacun doit profiler des processus distincts. Le profileur doit être implémenté en tant que DLL de serveur COM in-process mappée au même espace d'adressage que le processus en cours de profilage. En d'autres termes, le profileur s'exécute in-process. Le .NET Framework ne prend pas en charge tout autre type de serveur COM. Par exemple, si un profileur souhaite surveiller des applications à partir d'un ordinateur distant, il doit implémenter des agents de collecteur sur chaque ordinateur. Ces agents traitent les résultats et les communiquent à l'ordinateur de collecte de données central.
Comme le profileur est un objet COM qui est instancié in-process, chaque application profilée possède sa propre copie du profileur. Une seule instance de profileur n'a par conséquent pas à gérer des données issues de plusieurs applications. Vous devez toutefois ajouter une logique au code d'enregistrement du profileur pour empêcher le remplacement du fichier journal par d'autres applications profilées.
Initialisation du profileur
En cas de réussite de la vérification des deux variables d'environnement, le CLR crée une instance du profileur un peu à la manière de la fonction CoCreateInstance COM. Le profileur ne se charge pas via un appel direct à CoCreateInstance. Un appel à CoInitialize, qui requiert la définition du modèle de thread, est ainsi évité. Le CLR appelle ensuite la méthode ICorProfilerCallback::Initialize dans le profileur. La signature de cette méthode est la suivante.
HRESULT Initialize(IUnknown *pICorProfilerInfoUnk)
Le profileur doit interroger pICorProfilerInfoUnk pour un pointeur d'interface ICorProfilerInfo ou ICorProfilerInfo2 et l'enregistrer afin qu'il puisse demander par la suite plus d'informations pendant le profilage.
Définition des notifications d'événements
Le profileur appelle ensuite la méthode ICorProfilerInfo::SetEventMask pour spécifier les catégories de notifications qui l'intéressent. Par exemple, si le profileur est uniquement intéressé par les notifications d'entrée et de sortie de fonction et les notifications de garbage collection, il spécifie alors les éléments suivants.
ICorProfilerInfo* pInfo;
pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (void**)&pInfo);
pInfo->SetEventMask(COR_PRF_MONITOR_ENTERLEAVE | COR_PRF_MONITOR_GC)
En définissant de cette manière le masque de notifications, le profileur peut limiter les notifications qu'il reçoit. Cela permet à l'utilisateur de générer un profileur simple ou à but spécifique. Cela réduit également le temps processeur qui serait gaspillé par l'envoi de notifications qui seraient ignorées par le profileur.
Certains événements de profileur sont immuables. En d'autres termes, dès que ces événements sont définis dans le rappel ICorProfilerCallback::Initialize, ils ne peuvent pas être désactivés et de nouveaux événements ne peuvent pas être activés. Toute tentative de modification d'un événement immuable provoque un ICorProfilerInfo::SetEventMask qui retourne un HRESULT d'échec.