C++ Build Insights SDK
Das C++ Build Insights SDK ist mit Visual Studio 2017 und höher kompatibel. Um die Dokumentation für diese Versionen anzuzeigen, legen Sie das Auswahlsteuerelement Version in Visual Studio für diesen Artikel auf Visual Studio 2017 oder höher fest. Es befindet sich am Anfang des Inhaltsverzeichnisses auf dieser Seite.
Das C++ Build Insights SDK ist eine Sammlung von APIs, die Ihnen ermöglichen, personalisierte Tools auf der C++ Build Insights-Plattform zu erstellen. Auf dieser Seite finden Sie eine allgemeine Übersicht, die Ihnen den Einstieg erleichtern soll.
Abrufen des SDK
Sie können das C++ Build Insights SDK mit folgenden Schritten als NuGet-Paket herunterladen:
- Erstellen Sie in Visual Studio 2017 und höher ein neues C++-Projekt.
- Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Ihr Projekt.
- Wählen Sie im Kontextmenü NuGet-Pakete verwalten aus.
- Wählen Sie oben rechts die nuget.org-Paketquelle aus.
- Suchen Sie nach der neuesten Version des Pakets Microsoft.Cpp.BuildInsights.
- Wählen Sie Installieren aus.
- Akzeptieren Sie die Lizenzbedingungen.
Lesen Sie die weiteren Informationen zu den allgemeinen Konzepten im Zusammenhang mit dem SDK. Sie können auch auf das offizielle GitHub-Repository mit C++ Build Insights-Beispielen zugreifen, um Beispiele echter C++-Anwendungen anzuzeigen, die das SDK verwenden.
Erfassen einer Ablaufverfolgung
Wenn Sie mit dem C++ Build Insights SDK Ereignisse aus der MSVC-Toolkette analysieren, müssen Sie zuerst eine Ablaufverfolgung erfassen. Das SDK nutzt die Ereignisablaufverfolgung für Windows (Event Tracing for Windows, ETW) als grundlegende Ablaufverfolgungstechnologie. Das Erfassen einer Ablaufverfolgung kann auf zwei Arten erfolgen:
Methode 1: Verwenden von vcperf in Visual Studio 2019 und höher
Öffnen einer x64 Native Tools-Eingabeaufforderung mit erhöhten Rechten für VS 2019.
Führen Sie den folgenden Befehl aus:
vcperf /start MySessionName
Erstellen Sie das Projekt.
Führen Sie den folgenden Befehl aus:
vcperf /stopnoanalyze MySessionName outputTraceFile.etl
Wichtig
Beenden Sie die Ablaufverfolgung mit vcperf mit dem
/stopnoanalyze
-Befehl. Sie können mit dem C++ Build Insights SDK keine Ablaufverfolgungen analysieren, die mit dem regulären/stop
-Befehl beendet wurden.
Methode 2: programmgesteuert
Verwenden Sie eine dieser C++ Build Insights SDK-Funktionen zum Erfassen von Ablaufverfolgungen, um Ablaufverfolgungen programmgesteuert zu starten und zu beenden. Das Programm, das diese Funktionsaufrufe ausführt, muss über Administratorrechte verfügen. Nur die Funktionen zum Starten und Beenden von Ablaufverfolgungsfunktionen erfordern Administratorrechte. Alle anderen Funktionen im C++ Build Insights SDK können ohne sie ausgeführt werden.
SDK-Funktionen zum Erfassen von Ablaufverfolgungen
Funktionalität | C++-API | C-API |
---|---|---|
Starten einer Ablaufverfolgung | StartTracingSession | StartTracingSessionA StartTracingSessionW |
Beenden einer Ablaufverfolgung | StopTracingSession | StopTracingSessionA StopTracingSessionW |
Beenden einer Ablaufverfolgung und sofortiges Analysieren des Ergebnisses |
StopAndAnalyzeTracingSession | StopAndAnalyzeTracingSessionA StopAndAnalyzeTracingSession |
Beenden einer Ablaufverfolgung und sofortige Neuprotokollierung des Ergebnisses |
StopAndRelogTracingSession | StopAndRelogTracingSessionA StopAndRelogTracingSessionW |
In den folgenden Abschnitten wird gezeigt, wie Sie eine Analyse- oder eine Neuprotokollierungssitzung konfigurieren. Dies ist für die Funktionen mit kombinierter Funktionalität wie StopAndAnalyzeTracingSession erforderlich.
Nutzen einer Ablaufverfolgung
Wenn Sie über eine ETW-Ablaufverfolgung verfügen, entpacken Sie sie mit dem C++ Build Insights SDK. Das SDK stellt Ihnen die Ereignisse in einem Format bereit, mit dem Sie Ihre Tools schnell entwickeln können. Sie sollten die ETW-Ablaufverfolgung nicht ohne das SDK verwenden. Das von MSVC verwendete Ereignisformat ist undokumentiert, zur Skalierung für umfangreiche Builds optimiert und schwer zu verstehen. Außerdem ist die C++ Build Insights SDK-API beständig, während das reine ETW-Format ohne vorherige Ankündigung geändert werden kann.
SDK-Typen und -Funktionen im Zusammenhang mit der Nutzung der Ablaufverfolgung
Funktionalität | C++-API | C-API | Hinweise |
---|---|---|---|
Einrichten von Ereignisrückrufen | IAnalyzer IRelogger |
ANALYSIS_CALLBACKS RELOG_CALLBACKS |
Das C++ Build Insights SDK stellt Ereignisse mithilfe von Rückruffunktionen bereit. Implementieren Sie in C++ die Rückruffunktionen, indem Sie eine Analysetool- oder Reloggerklasse erstellen, die die IAnalyzer- oder IRelogger-Schnittstelle erbt. Implementieren Sie in C die Rückrufe in globalen Funktionen, und stellen Sie in der ANALYSIS_CALLBACKS- oder RELOG_CALLBACKS-Struktur Zeiger darauf bereit. |
Erstellen von Gruppen | MakeStaticAnalyzerGroup MakeStaticReloggerGroup MakeDynamicAnalyzerGroup MakeDynamicReloggerGroup |
Die C++-API stellt Hilfsfunktionen und -typen bereit, um mehrere Analysetool- und Reloggerobjekte zu gruppieren. Gruppen sind eine gute Möglichkeit, eine komplexe Analyse in einfachere Schritte aufzuteilen. vcperf ist auf diese Weise organisiert. | |
Analysieren oder erneut protokollieren | Analysieren. Relog |
AnalyzeA AnalyzeW ErneutesLoga NeulogW |
Analysieren und erneut protokollieren
Die Nutzung einer Ablaufverfolgung erfolgt entweder über eine Analyse- oder eine Neuprotokollierungssitzung.
Die Verwendung einer regulären Analyse ist für die meisten Szenarien geeignet. Diese Methode bietet Ihnen die Flexibilität, das Ausgabeformat auszuwählen: printf
-Text, XML, JSON, Datenbank, REST-Aufrufe usw.
Die Neuprotokollierung ist für zweckgebundene Analysen vorgesehen, die eine ETW-Ausgabedatei produzieren müssen. Mithilfe der Neuprotokollierung können Sie die C++ Build Insights-Ereignisse in Ihr eigenes ETW-Ereignisformat übersetzen. Eine geeignete Verwendung der Neuprotokollierung wäre, die C++ Build Insights-Daten in Ihre vorhandenen ETW-Tools und Ihre Infrastruktur einzubinden. Beispielsweise verwendet vcperf die Schnittstellen der Neuprotokollierung. Das liegt daran, dass Daten erzeugt werden müssen, die der Windows Performance Analyzer – ein ETW-Tool – versteht. Wenn Sie die Schnittstellen der Neuprotokollierung verwenden möchten, benötigen Sie Vorkenntnisse der Funktionsweise von ETW.
Erstellen von Analysetoolgruppen
Sie müssen wissen, wie Gruppen erstellt werden. Hier ist ein Beispiel, das zeigt, wie Sie eine Analysegruppe erstellen, die Hello, world! für jedes empfangene Aktivitätsstartereignis druckt.
using namespace Microsoft::Cpp::BuildInsights;
class Hello : public IAnalyzer
{
public:
AnalysisControl OnStartActivity(
const EventStack& eventStack) override
{
std::cout << "Hello, " << std::endl;
return AnalysisControl::CONTINUE;
}
};
class World : public IAnalyzer
{
public:
AnalysisControl OnStartActivity(
const EventStack& eventStack) override
{
std::cout << "world!" << std::endl;
return AnalysisControl::CONTINUE;
}
};
int main()
{
Hello hello;
World world;
// Let's make Hello the first analyzer in the group
// so that it receives events and prints "Hello, "
// first.
auto group = MakeStaticAnalyzerGroup(&hello, &world);
unsigned numberOfAnalysisPasses = 1;
// Calling this function initiates the analysis and
// forwards all events from "inputTrace.etl" to my analyzer
// group.
Analyze("inputTrace.etl", numberOfAnalysisPasses, group);
return 0;
}
Verwenden von Ereignissen
SDK-Typen und -Funktionen im Zusammenhang mit Ereignissen
Aktivitäten und einfache Ereignisse
Ereignisse lassen sich in zwei Kategorien einteilen: Aktivitäten und einfache Ereignisse. Aktivitäten sind in einem Zeitraum ablaufende Prozesse mit Anfang und Ende. Einfache Ereignisse sind punktuelle Vorkommnisse ohne Dauer. Beim Analysieren von MSVC-Ablaufverfolgungen mit dem C++ Build Insights SDK erhalten Sie separate Ereignisse, wenn eine Aktivität startet und endet. Sie erhalten nur ein Ereignis, wenn ein einfaches Ereignis auftritt.
Beziehungen zwischen übergeordneten und untergeordneten Elementen
Aktivitäten und einfache Ereignisse sind über Beziehungen zwischen übergeordneten und untergeordneten Elementen miteinander verknüpft. Das übergeordnete Element von Aktivitäten oder einfachen Ereignissen ist die umfassende Aktivität, in der sie auftreten. Wenn Sie z. B. eine Quelldatei kompilieren, muss der Compiler die Datei analysieren und dann den Code generieren. Die Aktivitäten für Analyse und Codegenerierung sind beide untergeordnete Elemente der Compileraktivität.
Da einfache Ereignisse keine Dauer haben, kann innerhalb einfacher Ereignisse nichts anderes geschehen. Folglich haben sie niemals untergeordnete Elemente.
Die Beziehungen zwischen übergeordneten und untergeordneten Elementen der einzelnen Aktivitäten und einfachen Ereignisse werden in der Ereignistabelle angegeben. Wenn Sie C++ Build Insights-Ereignisse nutzen, müssen Sie diese Beziehungen kennen. Häufig müssen Sie sich auf sie verlassen, um den vollständigen Kontext eines Ereignisses zu verstehen.
Eigenschaften
Alle Ereignisse verfügen über folgende Eigenschaften:
Eigenschaft | Beschreibung |
---|---|
Typbezeichner | Eine Zahl, die den Ereignistyp eindeutig identifiziert. |
Instanzbezeichner | Eine Zahl, die das Ereignis innerhalb der Ablaufverfolgung eindeutig identifiziert. Wenn zwei Ereignisse desselben Typs in einer Ablaufverfolgung auftreten, erhalten beide einen eindeutigen Instanzbezeichner. |
Startzeit | Der Zeitpunkt, zu dem eine Aktivität gestartet wurde, oder der Zeitpunkt, zu dem ein einfaches Ereignis auftrat. |
Prozessbezeichner | Eine Zahl, die den Prozess identifiziert, in dem das Ereignis auftrat. |
Threadbezeichner | Eine Zahl, die den Thread identifiziert, in dem das Ereignis auftrat. |
Prozessorindex | Ein auf 0 (null) basierender Index, der den logischen Prozessor angibt, von dem das Ereignis ausgegeben wurde. |
Event name (Ereignisname) | Eine Zeichenfolge, die den Ereignistyp beschreibt. |
Alle Aktivitäten, die keine einfachen Ereignisse sind, haben auch folgende Eigenschaften:
Eigenschaft | Beschreibung |
---|---|
Endzeit | Der Zeitpunkt, zu dem die Aktivität beendet wurde. |
Exklusive Dauer | Die für eine Aktivität aufgewendete Zeit mit Ausnahme der in den untergeordneten Aktivitäten aufgewendeten Zeit. |
CPU-Zeit | Die Zeit, die die CPU für das Ausführen von Code in dem der Aktivität angefügten Thread aufgewendet hat. Die Zeit, für die der der Aktivität angefügte Thread sich im Ruhezustand befand, ist darin nicht enthalten. |
Exklusive CPU-Zeit | CPU-Zeit ohne die für untergeordnete Aktivitäten aufgewendete CPU-Zeit. |
Gesamtbetrachtungszeit-Verantwortung | Der Beitrag der Aktivität zur Gesamtbetrachtungszeit. Die Gesamtbetrachtungszeit berücksichtigt die Parallelität zwischen Aktivitäten. Nehmen wir beispielsweise an, dass zwei nicht verknüpfte Aktivitäten parallel ausgeführt werden. Beide haben eine Dauer von 10 Sekunden und genau dieselbe Start- und Endzeit. In diesem Fall weist Build Insights beiden eine Gesamtbetrachtungszeit-Verantwortung von 5 Sekunden zu. Wenn diese Aktivitäten dagegen nacheinander und ohne Überlappung ausgeführt werden, wird ihnen jeweils eine Gesamtbetrachtungszeit-Verantwortung von 10 Sekunden zugewiesen. |
Exklusive Gesamtbetrachtungszeit-Verantwortung | Gesamtbetrachtungszeit-Verantwortung mit Ausnahme der Gesamtbetrachtungszeit-Verantwortung untergeordneter Aktivitäten. |
Einige Ereignisse haben neben den erwähnten Eigenschaften eigene Eigenschaften. In diesem Fall werden diese zusätzlichen Eigenschaften in der Ereignistabelle aufgelistet.
Nutzen von Ereignissen, die vom C++ Build Insights SDK bereitgestellt werden
Der Ereignisstapel
Immer dann, wenn das C++ Build Insights SDK ein Ereignis meldet, wird es in Form eines Stapels bereitgestellt. Der letzte Eintrag im Stapel ist das aktuelle Ereignis, und die Einträge davor sind ihm übergeordnet. Beispielsweise treten das LTCG-Start- und Endeereignis während des ersten Linkerdurchlaufs auf. In diesem Fall enthält der empfangene Stapel: [LINKER, PASS1, LTCG]. Die übergeordnete Hierarchie ist praktisch, da Sie so ein Ereignis auf seine Ursache zurückverfolgen können. Wenn die oben genannte LTCG-Aktivität langsam ist, können Sie sofort ermitteln, welcher Linkeraufruf beteiligt war.
Abgleichen von Ereignissen und Ereignisstapeln
Das C++ Build Insights SDK stellt Ihnen jedes Ereignis in einer Ablaufverfolgung bereit, aber in den meisten Fällen ist nur eine Teilmenge davon wichtig. In einigen Fällen ist möglicherweise nur eine Teilmenge der Ereignisstapel für Sie interessant. Mithilfe des SDK können Sie schnell die benötigten Ereignisse oder Ereignisstapel extrahieren und diejenigen ablehnen, die Sie nicht benötigen. Dies erfolgt über diese Abgleichsfunktionen:
Function | Beschreibung |
---|---|
MatchEvent | Beibehalten eines Ereignisses, wenn es mit einem der angegebenen Typen übereinstimmt. Weiterleiten übereinstimmender Ereignisse an eine Lambdafunktion oder einen anderen aufrufbaren Typ. Die übergeordnete Hierarchie des Ereignisses wird von dieser Funktion nicht berücksichtigt. |
MatchEventInMemberFunction | Beibehalten eines Ereignisses, wenn es mit dem in einem Parameter der Memberfunktion angegebenen Typen übereinstimmt. Weiterleiten übereinstimmender Ereignisse an eine Memberfunktion. Die übergeordnete Hierarchie des Ereignisses wird von dieser Funktion nicht berücksichtigt. |
MatchEventStack | Beibehalten eines Ereignisses, wenn sowohl das Ereignis als auch seine übergeordnete Hierarchie den angegebenen Typen entspricht. Weiterleiten des Ereignisses und der übereinstimmenden Ereignisse der übergeordneten Hierarchie an eine Lambdafunktion oder einen anderen aufrufbaren Typen. |
MatchEventStackInMemberFunction | Beibehalten eines Ereignisses, wenn sowohl das Ereignis als auch seine übergeordnete Hierarchie den in der Parameterliste einer Memberfunktion angegebenen Typen entspricht. Weiterleiten des Ereignisses und der übereinstimmenden Ereignisse der übergeordneten Hierarchie an die Memberfunktion. |
Die Ereignisstapel-Abgleichsfunktionen wie MatchEventStack
lassen Lücken bei der Beschreibung der abzugleichenden übergeordneten Hierarchie zu. Sie können beispielsweise sagen, dass Sie an dem Stapel [LINKER, LTCG] interessiert sind. Es würde auch mit dem Stapel [LINKER, PASS1, LTCG] übereinstimmen. Der letzte angegebene Typ muss dem Ereignistyp entsprechen, der abgeglichen werden soll, und ist nicht Teil der übergeordneten Hierarchie.
Erfassungsklassen
Die Verwendung der Match*
-Funktionen erfordert, dass Sie die Typen angeben, die Sie abgleichen möchten. Diese Typen werden aus einer Liste von Erfassungsklassen ausgewählt. Erfassungsklassen sind in verschiedenen Kategorien enthalten, die unten beschrieben werden.
Category | Beschreibung |
---|---|
Exact | Diese Erfassungsklassen werden verwendet, um einen bestimmten Ereignistyp und keinen anderen abzugleichen. Ein Beispiel hierfür ist die Compiler-Klasse zum Abgleich des COMPILER-Ereignisses. |
Platzhalter | Diese Erfassungsklassen können verwendet werden, um beliebige Ereignisse aus der Liste der von Ihnen unterstützten Ereignisse abzugleichen. Beispielsweise entspricht der Activity-Platzhalter jedem Aktivitätsereignis. Ein weiteres Beispiel ist der CompilerPass-Platzhalter, der entweder dem FRONT_END_PASS- oder dem BACK_END_PASS-Ereignis entsprechen kann. |
Group | Die Namen der Gruppenerfassungsklassen enden mit Group. Sie werden verwendet, um mehrere Ereignisse desselben Typs in einer Zeile abzugleichen, wobei Lücken ignoriert werden. Sie sind nur sinnvoll, wenn rekursive Ereignisse abgeglichen werden, da Sie nicht wissen, wie viele im Ereignisstapel vorhanden sind. Beispielsweise erfolgt die FRONT_END_FILE-Aktivität jedes Mal, wenn der Compiler eine Datei analysiert. Diese Aktivität ist rekursiv, da der Compiler möglicherweise bei der Analyse der Datei eine Include-Direktive findet. Die FrontEndFile-Klasse stimmt nur mit einem FRONT_END_FILE-Ereignis im Stapel überein. Verwenden Sie die Klasse FrontEndFileGroup, um die gesamte Include-Hierarchie abzugleichen. |
Platzhaltergruppe | Eine Platzhaltergruppe vereinigt in sich die Eigenschaften von Platzhaltern und Gruppen. Die einzige Klasse dieser Kategorie ist InvocationGroup, die alle LINKER- und COMPILER-Ereignisse in einem einzelnen Ereignisstapel abgleicht und erfasst. |
Informationen zu den Erfassungsklassen, die verwendet werden können, um die einzelnen Ereignisse abzugleichen, finden Sie in der Ereignistabelle.
Nach dem Abgleich: Verwenden von aufgezeichneten Ereignissen
Nach erfolgreichem Abschluss eines Abgleichs erstellen die Match*
-Funktionen die Erfassungsklassenobjekte und leiten sie an die angegebene Funktion weiter. Verwenden Sie diese Objekte der Erfassungsklasse zum Zugriff auf die Eigenschaften der Ereignisse.
Beispiel
AnalysisControl MyAnalyzer::OnStartActivity(const EventStack& eventStack)
{
// The event types to match are specified in the PrintIncludes function
// signature.
MatchEventStackInMemberFunction(eventStack, this, &MyAnalyzer::PrintIncludes);
}
// We want to capture event stacks where:
// 1. The current event is a FrontEndFile activity.
// 2. The current FrontEndFile activity has at least one parent FrontEndFile activity
// and possibly many.
void PrintIncludes(FrontEndFileGroup parentIncludes, FrontEndFile currentFile)
{
// Once we reach this point, the event stack we are interested in has been matched.
// The current FrontEndFile activity has been captured into 'currentFile', and
// its entire inclusion hierarchy has been captured in 'parentIncludes'.
cout << "The current file being parsed is: " << currentFile.Path() << endl;
cout << "This file was reached through the following inclusions:" << endl;
for (auto& f : parentIncludes)
{
cout << f.Path() << endl;
}
}