Freigeben über


Übersicht über die Profilerstellung

Ein Profiler ist ein Tool, das die Ausführung einer anderen Anwendung überwacht. Ein Common Language Runtime (CLR)-Profiler ist eine Dynamic Link Library (DLL), die aus Funktionen besteht, die mithilfe der Profilerstellungs-API Meldungen von der CLR empfangen und an diese senden. Die Profiler-DLL wird zur Laufzeit von der CLR geladen.

Herkömmliche Profilerstellungstools dienen vorwiegend dazu, die Ausführung der Anwendung zu messen. Das bedeutet, dass sie die für jede Funktion aufgebrachte Zeit und die Speicherauslastung der Anwendung über einen bestimmten Zeitraum messen. Die Profilerstellungs-API zielt auf eine breitere Klasse von Diagnosetools ab, z. B. Dienstprogramme zur Codeabdeckung und sogar erweiterte Debughilfen. Diese Verwendungsmöglichkeiten sind ausnahmslos von diagnostischer Natur. Die Profilerstellungs-API misst nicht nur die Ausführung einer Anwendung, sondern überwacht sie auch. Aus diesem Grund sollte die Profilerstellungs-API nie von der Anwendung selbst verwendet werden, und die Ausführung der Anwendung sollte nicht vom Profiler abhängen (oder davon beeinflusst werden).

Die Profilerstellung für eine CLR-Anwendung erfordert eine weiter reichende Unterstützung als die Profilerstellung für Computercode, der auf herkömmliche Weise kompiliert wurde. Dies liegt darin begründet, dass von der CLR Konzepte wie Anwendungsdomänen, Garbage Collection, verwaltete Ausnahmenbehandlung, Just-In-Time (JIT)-Kompilierung von Code (die Konvertierung von Microsoft Intermediate Language- bzw. MSIL-Code in systemeigenen Computercode) und ähnliche Features eingeführt werden. Herkömmliche Profilerstellungsmechanismen können keine nützlichen Informationen über diese Features identifizieren oder bereitstellen. Die Profilerstellungs-API liefert diese fehlenden Informationen hingegen in effizienter Weise und mit minimalen Auswirkungen auf die Leistung der CLR und die Anwendung, für die das Profil erstellt wird.

Die JIT-Kompilierung zur Laufzeit bietet hervorragende Möglichkeiten zur Profilerstellung. Die Profilerstellungs-API ermöglicht einem Profiler, den speicherinternen MSIL-Codestream für eine Routine zu ändern, bevor er JIT-kompiliert wird. Auf diese Weise kann der Profiler bestimmten Routinen, die genauer überprüft werden müssen, Instrumentationscode dynamisch hinzufügen. Dieser Ansatz ist zwar auch in herkömmlichen Szenarios möglich, lässt sich aber für die CLR mit der Profilerstellungs-API wesentlich einfacher umsetzen.

Diese Übersicht enthält folgende Abschnitte:

  • Die Profilerstellungs-API

  • Unterstützte Funktionen

  • Benachrichtigungsthreads

  • Sicherheit

  • Kombination von verwaltetem und nicht verwaltetem Code in einem Codeprofiler

  • Profilerstellung für nicht verwalteten Code

  • Verwenden von COM

  • Aufruflisten

  • Rückrufe und Stapeltiefe

  • Verwandte Themen

Die Profilerstellungs-API

Normalerweise wird die Profilerstellungs-API verwendet, um einen Codeprofiler zu schreiben. Hierbei handelt es sich um ein Programm, mit dem die Ausführung einer verwalteten Anwendung überwacht wird.

Die Profilerstellungs-API wird von einer Profiler-DLL verwendet, die in den gleichen Prozess geladen wird wie die Anwendung, für die ein Profil erstellt wird. Die Profiler-DLL implementiert eine Rückrufschnittstelle (ICorProfilerCallback in .NET Framework, Version 1.0 und 1.1, und ICorProfilerCallback2 in Version 2.0 und höher). Die CLR ruft die Methoden in dieser Schnittstelle auf, um den Profiler über Ereignisse im profilierten Prozess zu benachrichtigen. Der Profiler kann mit den Methoden in der ICorProfilerInfo-Schnittstelle und in der ICorProfilerInfo2-Schnittstelle einen Rückruf in die Laufzeit durchführen, um Informationen über den Zustand der Anwendung abzurufen, für die ein Profil erstellt wird.

HinweisHinweis

Lediglich der zur Datenerfassung verwendete Teil der Profilerlösung sollte im gleichen Prozess ausgeführt werden wie die Anwendung, für die ein Profil erstellt wird.Alle Benutzeroberflächen- und Datenanalysevorgänge sollten in einem separaten Prozess ausgeführt werden.

Die folgende Abbildung zeigt, wie die Profiler-DLL mit der Anwendung, für die ein Profil erstellt wird, und der CLR interagiert.

Profilerstellungsarchitektur

Profilarchitektur

Die Benachrichtigungsschnittstellen

ICorProfilerCallback und ICorProfilerCallback2 können als Benachrichtigungsschnittstellen betrachtet werden. Diese Schnittstellen bestehen aus Methoden wie ClassLoadStarted, ClassLoadFinished und JITCompilationStarted. Jedes Mal, wenn die CLR eine Klasse lädt oder entlädt, eine Funktion kompiliert usw., ruft sie die entsprechende Methode in der ICorProfilerCallback-Schnittstelle oder in der ICorProfilerCallback2-Schnittstelle des Profilers auf.

Beispielsweise könnte ein Profiler die Codeleistung anhand von zwei Benachrichtigungsfunktionen messen: FunctionEnter2 und FunctionLeave2. Dazu versieht er lediglich jede Benachrichtigung mit einem Zeitstempel, sammelt Ergebnisse und gibt eine Liste aus, aus der ersichtlich ist, welche Funktionen während der Anwendungsausführung die meiste CPU- oder Realzeit in Anspruch genommen haben.

Die Datenabrufschnittstellen

Die anderen bei der Profilerstellung vorwiegend verwendeten Schnittstellen sind ICorProfilerInfo und ICorProfilerInfo2. Der Profiler ruft diese Schnittstellen nach Bedarf auf, um weitere Daten für seine Analysen abzurufen. Wenn die CLR beispielsweise die FunctionEnter2-Funktion aufruft, stellt sie einen Funktionsbezeichner bereit. Der Profiler kann weitere Daten über diese Funktion abrufen, indem er die ICorProfilerInfo2::GetFunctionInfo2-Methode aufruft, um die übergeordnete Klasse der Funktion, ihren Namen usw. zu erhalten.

Zurück nach oben

Unterstützte Funktionen

Die Profilerstellungs-API bietet Informationen über verschiedene Ereignisse und Aktionen in der Common Language Runtime. Sie können diese Informationen zum Überwachen der internen Funktionsweise von Prozessen und zum Analysieren der Leistung Ihrer .NET Framework-Anwendung verwenden.

Die Profilerstellungs-API ruft Informationen über die folgenden Aktionen und die Ereignisse ab, die in der CLR auftreten:

  • CLR-Ereignisse beim Starten und Herunterfahren.

  • Ereignisse bei der Anwendungsdomänenerstellung und beim Herunterfahren.

  • Ereignisse beim Laden und Entladen von Assemblys.

  • Ereignisse beim Laden und Entladen von Ereignissen.

  • Ereignisse beim Erstellen und Löschen von COM-vtable.

  • Ereignisse bei der JIT-Kompilierung (Just-In-Time) und beim Codepitching.

  • Ereignisse beim Laden und Entladen von Klassen.

  • Ereignisse beim Erstellen und Löschen von Threads.

  • Ereignisse beim Funktionseinstieg und Funktionsende.

  • Ausnahmen.

  • Übergänge zwischen verwalteter und nicht verwalteter Codeausführung.

  • Übergänge zwischen verschiedenen Laufzeitkontexten.

  • Informationen über Laufzeitunterbrechungen.

  • Informationen über den Laufzeitspeicherheap und die Garbage Collection-Aktivität.

Die Profilerstellungs-API kann von jeder (nicht verwalteten) COM-kompatiblen Sprache aufgerufen werden.

Die API ist im Hinblick auf die Prozessor- und Speicherauslastung effizient. Durch die Profilerstellung werden an der Anwendung mit Profil keine Änderungen durchgeführt, die so signifikant sind, dass es zu falschen Ergebnissen kommt.

Die Profilerstellungs-API ist sowohl für Samplingprofiler als auch für andere Profiler nützlich. Ein Samplingprofiler überprüft das Profil in regelmäßigen Teilstrichen, z. B. alle fünf Millisekunden. Ein Nicht-Samplingprofiler wird synchron mit dem Thread, der das Ereignis verursacht, über ein Ereignis informiert.

Nicht unterstützte Funktionalität

Die Profilerstellungs-API unterstützt die folgenden Funktionen nicht:

  • Nicht verwalteter Code, der mit konventionellen Win32-Methoden profiliert werden muss. Der CLR-Profiler umfasst jedoch Übergangsereignisse, um die Grenzen zwischen verwaltetem und nicht verwaltetem Code zu ermitteln.

  • Sich selbst ändernde Anwendungen, die ihren eigenen Code zu bestimmten Zwecken, beispielsweise bei der aspektorientierten Programmierung, selbsttätig ändern.

  • Grenzüberprüfung, da die Profilerstellungs-API diese Informationen nicht bereitstellt. Die CLR bietet systeminterne Unterstützung für die Überprüfung von Grenzen des gesamten verwalteten Codes.

  • Remoteprofilerstellung, die aus den folgenden Gründen nicht unterstützt wird:

    • Durch die Remoteprofilerstellung verlängert sich die Ausführungszeit. Bei der Verwendung der Profilerstellungsschnittstellen müssen Sie die Ausführungszeit minimieren, damit die Auswirkungen auf die Profilerstellungsergebnisse möglichst gering bleiben. Dies trifft insbesondere dann zu, wenn die Ausführungsleistung überwacht wird. Dabei stellt die Remoteprofilerstellung jedoch keine Einschränkung dar, wenn Profilerstellungsschnittstellen zum Überwachen der Speicherauslastung oder zum Abrufen von Laufzeitinformationen über Stapelrahmen, Objekte usw. verwendet werden.

    • Der CLR-Codeprofiler muss mindestens eine Rückrufschnittstelle bei der Laufzeit des lokalen Computers registrieren, auf dem die Anwendung mit Profil ausgeführt wird. Hierdurch wird die Möglichkeit eingeschränkt, einen Remotecodeprofiler zu erstellen.

  • Profilerstellung in Produktionsumgebungen, die eine hohe Verfügbarkeit erfordern. Die Profilerstellungs-API wurde erstellt, um die Diagnose bei der Entwicklung zu unterstützen. Sie wurde nicht den strengen Tests unterzogen, die für die Unterstützung einer Produktionsumgebung erforderlich sind.

Zurück nach oben

Benachrichtigungsthreads

In den meisten Fällen führt der Thread, der ein Ereignis generiert, auch Benachrichtigungen aus. Solche Benachrichtigungen (z. B. FunctionEnter und FunctionLeave) müssen die explizite ThreadID nicht angeben. Zudem kann der Profiler basierend auf der ThreadID des jeweiligen Threads entscheiden, seine Analyseblöcke im lokalen Threadspeicher zu speichern und zu aktualisieren, anstatt die Analyseblöcke im globalen Speicher zu indizieren.

Beachten Sie, dass diese Rückrufe nicht serialisiert werden. Benutzer müssen ihren Code schützen, indem sie threadsichere Datenstrukturen erstellen und den Profilercode ggf. sperren, um zu verhindern, dass mehrere Threads parallel darauf zugreifen. Deshalb kann es in bestimmten Fällen passieren, dass Sie eine ungewöhnliche Sequenz von Rückrufen erhalten. Nehmen Sie z. B. an, dass eine verwaltete Anwendung zwei Threads erzeugt, die identischen Code ausführen. In diesem Fall ist es möglich, dass Sie ein ICorProfilerCallback::JITCompilationStarted-Ereignis für eine Funktion von einem Thread und einen FunctionEnter-Rückruf von dem anderen Thread empfangen, bevor der ICorProfilerCallback::JITCompilationFinished-Rückruf eingeht. In diesem Fall erhält der Benutzer einen FunctionEnter-Rückruf für eine Funktion, für die möglicherweise noch keine vollständige JIT-Kompilierung (Just-In-Time) erfolgt ist.

Zurück nach oben

Sicherheit

Eine Profilerstellungs-DLL ist eine nicht verwaltete DLL, die als Teil des Common Language Runtime-Ausführungsmoduls ausgeführt wird. Daher gelten die Einschränkungen für die Sicherheit des Zugriffs auf verwalteten Code nicht für den Code in der Profilerstellungs-DLL. Für die Profilerstellungs-DLL gelten nur die Einschränkungen, die das Betriebssystem für den Benutzer erzwingt, der die Anwendung mit Profil ausführt.

Entwickler von Profilern sollten entsprechende Vorkehrungen treffen, um sicherheitsrelevante Probleme zu vermeiden. So sollte beispielsweise eine Profilerstellungs-DLL während der Installation in eine Zugriffssteuerungsliste (ACL) aufgenommen werden, damit sie nicht durch böswillige Benutzer geändert werden kann.

Zurück nach oben

Kombination von verwaltetem und nicht verwaltetem Code in einem Codeprofiler

Ein falsch geschriebener Profiler kann zirkuläre Verweise auf sich selbst verursachen und zu unvorhersehbarem Verhalten führen.

Bei näherer Betrachtung der Profilerstellungs-API kann der Eindruck entstehen, dass es möglich wäre, einen Profiler mit verwalteten und nicht verwalteten Komponenten zu schreiben, die sich gegenseitig über COM-Interop oder indirekte Aufrufe aufrufen.

Obwohl dies aus der Entwurfsperspektive möglich ist, unterstützt die Profilerstellungs-API keine verwalteten Komponenten. Ein CLR-Profiler darf keinerlei verwaltete Komponenten enthalten. Versuche, verwalteten und nicht verwalteten Code in einem CLR-Profiler zu kombinieren, können Regelverletzungen, Programmausfälle oder Deadlocks verursachen. Die verwalteten Komponenten des Profilers verweisen Ereignisse zurück an ihre nicht verwalteten Komponenten, die in der Folge erneut die verwalteten Komponenten aufrufen. Dies führt zu zirkulären Verweisen.

Der einzige Ort, an dem ein CLR-Profiler verwalteten Code sicher aufrufen kann, ist innerhalb des Texts einer Methode im MSIL-Code (Microsoft Intermediate Language). Bevor die JIT-Kompilierung (Just-In-Time) einer Funktion abgeschlossen ist, kann der Profiler verwaltete Aufrufe in den MSIL-Text einer Methode einfügen und diese dann mit der JIT-Kompilierung kompilieren (nähere Informationen dazu finden Sie unter der Methode ICorProfilerInfo::GetILFunctionBody). Diese Technik lässt sich erfolgreich für die selektive Instrumentation von verwaltetem Code oder für die Erfassung von Statistik- und Leistungsdaten für JIT verwenden.

Alternativ dazu kann ein Codeprofiler native Hooks in den MSIL-Text jeder verwalteten Funktion einfügen, die nicht verwalteten Code aufruft. Diese Technik kann für Instrumentation und Abdeckung verwendet werden. So kann beispielsweise ein Codeprofiler Instrumentationshooks nach jedem MSIL-Block einfügen, um sicherzustellen, dass der Block ausgeführt wurde. Bei der Modifikation des MSIL-Texts einer Methode muss sehr sorgfältig vorgegangen werden, und eine Vielzahl von Faktoren muss berücksichtigt werden.

Zurück nach oben

Profilerstellung für nicht verwalteten Code

Die Profilerstellungs-API der Common Language Runtime (CLR) bietet minimale Unterstützung zur Profilerstellung für nicht verwalteten Code. Die folgende Funktionalität wird bereitgestellt:

  • Enumeration von Stapelketten. Dieses Feature ermöglicht einem Codeprofiler, die Grenze zwischen verwaltetem und nicht verwaltetem Code zu bestimmen.

  • Feststellung, ob eine Stapelkette verwaltetem oder systemeigenem Code entspricht.

In .NET Framework, Version 1.0 und 1.1, sind diese Methoden über den prozessinternen Teil der Debug-API der CLR verfügbar. Sie sind in der Datei CorDebug.idl definiert und werden im Abschnitt Übersicht über das Debugging in der CLR erläutert.

In .NET Framework 2.0 und höher können Sie die ICorProfilerInfo2::DoStackSnapshot-Methode für diese Funktionalität verwenden.

Zurück nach oben

Verwenden von COM

Obwohl die Profilerstellungsschnittstellen als COM-Schnittstellen definiert sind, initialisiert die Common Language Runtime (CLR) COM tatsächlich nicht zur Verwendung dieser Schnittstellen. Der Grund hierfür ist, dass auf diese Weise das Festlegen des Threadingmodells durch Verwendung der CoInitialize-Funktion vermieden werden soll, bevor die verwaltete Anwendung die Möglichkeit hatte, das gewünschte Threadingmodell festzulegen. Ähnlich sollte auch der Profiler selbst CoInitialize, nicht aufrufen, da sonst ein Threadingmodell ausgewählt werden könnte, das mit der Anwendung, für die ein Profil erstellt wird, nicht kompatibel ist und es daher zu einem Anwendungsfehler kommen kann.

Zurück nach oben

Aufruflisten

Die Profilerstellungs-API bietet zwei Methoden zum Abrufen von Aufruflisten: eine Stapelmomentaufnahmemethode, mit der Anruflisten sporadisch überwacht werden können, und eine Schattenstapelmethode, mit der Anruflisten laufend überwacht werden können.

Stapelmomentaufnahme

Unter einer Stapelmomentaufnahme versteht man die Überwachung eines Threadstapels zu einem bestimmten Zeitpunkt. Die Profilerstellungs-API unterstützt die Überwachung von verwalteten Funktionen im Stapel, überlässt jedoch die Überwachung nicht verwalteter Funktionen dem Stackwalker des Profilers.

Weitere Informationen darüber, wie Sie den Profiler zum Durchlaufen verwalteter Stapel programmieren, finden Sie in den Ausführungen zur ICorProfilerInfo2::DoStackSnapshot-Methode in dieser Dokumentation und in der MSDN Library unter Profiler Stack Walking in the .NET Framework 2.0: Basics and Beyond.

Schattenstapel

Die allzu häufige Verwendung der Momentaufnahmemethode kann schnell zu Leistungseinbußen führen. Wenn Sie regelmäßig Stapelüberwachungen vornehmen möchten, sollte der Profiler stattdessen die Ausnahmerückrufe FunctionEnter2, FunctionLeave2, FunctionTailcall2 und ICorProfilerCallback2 verwenden, um einen Schattenstapel zu erstellen. Der Schattenstapel ist immer aktuell und kann schnell in den Speicher kopiert werden, wenn eine Stapelmomentaufnahme benötigt wird.

Mit einem Schattenstapel können Funktionsargumente, Rückgabewerte und Informationen über generische Instanziierungen abgerufen werden. Diese Informationen sind nur über den Schattenstapel verfügbar und können abgerufen werden, wenn die Steuerung an eine Funktion übergeben wird. Sobald die Funktion ausgeführt wird, sind diese Informationen u. U. jedoch nicht mehr verfügbar.

Zurück nach oben

Rückrufe und Stapeltiefe

Profilerrückrufe können ausgegeben werden, wenn der Stapel stark eingeschränkt ist, und ein Stapelüberlauf in einem Profilerrückruf führt zum sofortigen Prozessende. Ein Profiler sollte bei der Reaktion auf Rückrufe möglichst wenige Stapel verwenden. Wenn der Profiler für Prozesse verwendet werden soll, die vor Stapelüberlauf geschützt sind, sollte der Profiler selbst möglichst auch keinen Stapelüberlauf auslösen.

Zurück nach oben

Verwandte Themen

Titel

Beschreibung

Profilerstellung in .NET Framework 2.0

Beschreibt die Änderungen und Verbesserungen der Profilerstellung in .NET Framework 2.0 und höheren Versionen.

Einrichten einer Profilerstellungsumgebung

Erklärt, wie ein Profiler initialisiert, Ereignisbenachrichtigungen festgelegt und ein Profil für einen Windows-Dienst erstellt werden.

Ladeprogrammrückrufe in der Profilerstellungs-API

Erläutert Rückrufe, die zum Laden von Anwendungsdomänen, Assemblys, Modulen und Klassen ausgegeben werden.

Garbage Collection in der Profilerstellungs-API

Erläutert, wie die Garbage Collection ausgelöst, erkannt und blockiert wird.

Objektverfolgung in der Profilerstellungs-API

Erläutert, wie Objekte, die während der Garbage Collection verschoben wurden, verfolgt werden können.

Objektüberprüfung in der Profilerstellungs-API

Erläutert, wie ein Profiler Metadaten zum Abrufen von Informationen über Objekte verwenden kann.

Behandlung von Ausnahmen in der Profilerstellungs-API

Erläutert, wie ein Profiler Ausnahmeereignisse überwachen kann.

Codegenerierung in der Profilerstellungs-API

Beschreibt, wie ein Profiler die automatische und manuelle Codegenerierung steuern kann.

Profilerstellungs- und Laufzeitbenachrichtigungs-IDs

Erläutert Klassen-, Thread- und Anwendungsdomänen-IDs, die durch die Common Language Runtime an Profiler übergeben werden.

Konventionen für Profilerstellungs-API-Methoden

Erläutert HRESULT-Rückgabewerte, das Reservieren von Rückgabepuffern für die Profilerstellungs-APIs und die Verwendung der optionalen Ausgabeparameter.

Profilerstellungsschnittstellen

Beschreibt die nicht verwalteten Schnittstellen, die die Profilerstellungs-API verwendet.

Profilerstellung für globale statische Funktionen

Beschreibt die nicht verwalteten globalen statischen Funktionen, die die Profilerstellungs-API verwendet.

Profilerstellungsenumerationen

Beschreibt die nicht verwalteten Enumerationen, die die Profilerstellungs-API verwendet.

Profilerstellungsstrukturen

Beschreibt die nicht verwalteten Strukturen, die die Profilerstellungs-API verwendet.

Zurück nach oben