Dela via


C++ Build Insights SDK

C++ Build Insights SDK är kompatibelt med Visual Studio 2017 och senare. Om du vill se dokumentationen för dessa versioner, ställ in Väljarkontrollen för Visual Studio Version i den här artikeln på Visual Studio 2017 eller senare. Den finns överst i innehållsförteckningen på den här sidan.

C++ Build Insights SDK är en samling API:er som gör att du kan skapa anpassade verktyg ovanpå C++ Build Insights-plattformen. Den här sidan innehåller en översikt på hög nivå som hjälper dig att komma igång.

Hämta SDK:et

Du kan ladda ned C++ Build Insights SDK som ett NuGet-paket genom att följa dessa steg:

  1. Från Visual Studio 2017 och senare skapar du ett nytt C++-projekt.
  2. I fönstret Solution Explorer högerklickar du på projektet.
  3. Välj Hantera NuGet-paket på snabbmenyn.
  4. Längst upp till höger väljer du nuget.org paketkälla.
  5. Sök efter den senaste versionen av Microsoft.Cpp.BuildInsights-paketet.
  6. Välj Installera.
  7. Godkänn licensen.

Läs vidare om du vill ha information om de allmänna begreppen kring SDK:t. Du kan också komma åt den officiella GitHub-lagringsplatsen C++ Build Insights-exempel för att se exempel på verkliga C++-program som använder SDK:t.

Samla in ett spårningslogg

Om du använder C++ Build Insights SDK för att analysera händelser som kommer ut från MSVC-verktygskedjan måste du först samla in en spårning. SDK använder händelsespårning för Windows (ETW) som den underliggande spårningstekniken. Du kan samla in en spårning på två sätt:

Metod 1: använda vcperf i Visual Studio 2019 och senare

  1. Öppna en upphöjd x64 Native Tools-kommandotolk för VS 2019.

  2. Kör följande kommando: vcperf /start MySessionName

  3. Skapa ditt projekt.

  4. Kör följande kommando: vcperf /stopnoanalyze MySessionName outputTraceFile.etl

    Viktigt!

    /stopnoanalyze Använd kommandot när du stoppar spårningen med vcperf. Du kan inte använda C++ Build Insights SDK för att analysera spårningar som stoppas av det vanliga /stop kommandot.

Metod 2: programmatiskt

Använd någon av dessa C++ Build Insights SDK-spårningsinsamlingsfunktioner för att starta och stoppa spårningar programmatiskt. Programmet som kör dessa funktionsanrop måste ha administratörsbehörighet. Endast start- och stoppspårningsfunktionerna kräver administratörsbehörighet. Alla andra funktioner i C++ Build Insights SDK kan köras utan dem.

Funktionalitet C++ API C API
Starta en spårning StartTracingSession StartTracingSessionA
StartTracingSessionW
Stoppa en spårning StopTracingSession StopTracingSessionA
StopTracingSessionW
Stoppa en spårning och
analyserar resultatet omedelbart
StoppaOchAnalyseraSpårningssessionen Stoppa och analysera spårningssession A
StoppaOchAnalyseraSpårningssessionen
Stoppa en spårning och
logga om resultatet omedelbart
StopAndRelogTracingSession StopAndRelogTracingSessionA
StopAndRelogTracingSessionW

Avsnitten som följer visar hur du konfigurerar en analys eller en omloggningssession. Det krävs för de kombinerade funktionsfunktionerna, till exempel StopAndAnalyzeTracingSession.

Förbruka ett spår

När du har en ETW-spårning använder du C++ Build Insights SDK för att packa upp den. SDK:et ger dig händelserna i ett format som gör att du snabbt kan utveckla dina verktyg. Vi rekommenderar inte att du använder rå ETW-spårningen utan att använda SDK:t. Händelseformatet som används av MSVC är odokumenterat, optimerat för att skala till enorma byggen och svårt att förstå. Dessutom är C++ Build Insights SDK-API:et stabilt, medan det råa ETW-spårningsformatet kan ändras utan föregående meddelande.

Funktionalitet C++ API C API Noteringar
Konfigurera återanrop till händelser IAnalyzer
IRelogger
ANALYSIS_CALLBACKS
RELOG_CALLBACKS
C++ Build Insights SDK tillhandahåller händelser via återanropsfunktioner. I C++implementerar du återanropsfunktionerna genom att skapa en analyzer- eller relogger-klass som ärver gränssnittet IAnalyzer eller IRelogger. I C implementerar du återanropen i globala funktioner och ger pekare till dem i ANALYSIS_CALLBACKS eller RELOG_CALLBACKS struktur.
Skapa grupper MakeStaticAnalyzerGroup
MakeStaticReloggerGroup
MakeDynamicAnalyzerGroup
MakeDynamicReloggerGroup
C++-API:et innehåller hjälpfunktioner och typer för att gruppera flera analys- och återloggningsobjekt. Grupper är ett snyggt sätt att dela in en komplex analys i enklare steg. vcperf ordnas på det här sättet.
Analysera eller logga om Analysera
Omlogga
Analysera
AnalyseraW
Omlogga
ÅterloggaW

Analysera och logga om

Användning av ett spår sker antingen via en analyssession eller en omloggningssession.

Att använda en regelbunden analys är lämpligt för de flesta scenarier. Den här metoden ger dig flexibiliteten att välja utdataformat: printf text, xml, JSON, databas, REST-anrop och så vidare.

Omloggning är avsedd för specialanalyser som behöver skapa en ETW-utdatafil. Med hjälp av omloggning kan du översätta C++ Build Insights-händelser till ditt eget ETW-händelseformat. En lämplig användning av omloggning skulle vara att koppla C++ Build Insights-data till dina befintliga ETW-verktyg och infrastruktur. vcperf använder till exempel omloggningsgränssnitten. Det beror på att den måste producera data som Windows Performance Analyzer, ett ETW-verktyg, kan förstå. Viss förkunskap om hur ETW fungerar krävs om du planerar att använda omloggningsgränssnitten.

Skapa analysgrupper

Det är viktigt att veta hur du skapar grupper. Här är ett exempel som visar hur du skapar en analysgrupp som skriver ut Hello, world! för varje aktivitetsstarthändelse den tar emot.

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;
}

Använda händelser

Funktionalitet C++ API C API Noteringar
Matchnings- och filtreringshändelser MatchEventStackInMemberFunction
MatchEventStack
MatchEventInMemberFunction
MatchEvent
C++-API:et erbjuder funktioner som gör det enkelt att extrahera de händelser som du bryr dig om från dina spårningar. Med C-API:et måste den här filtreringen göras för hand.
Händelsedatatyper Aktivitet
BackEndPass
Nederkant
C1DLL
C2DLL
CodeGeneration
Kommandorad
Kompilator
CompilerPass
Miljövariabel
Händelse
EventGroup
EventStack
ExecutableImageOutput
ExpOutput
FileInput
FileOutput
ForceInlinee
FrontEndFile
FrontEndFileGroup
FrontEndPass
Funktion
HeaderUnit
ImpLibOutput
Åkallan
Anropsgrupp
LibOutput
Länkare
LinkerGroup
LinkerPass
LTCG
Modul
ObjOutput
OptICF
OptLBR
OptRef
Pass1
Pass2
PrecompiledHeader
PreLTCGOptRef
SimpleEvent
Symbolnamn
TemplateInstantiation
TemplateInstantiationGroup
Tråd
TopDown
TraceInfo
TranslationUnitType
WholeProgramAnalysis
CL_PASS_DATA
EVENT_COLLECTION_DATA
EVENT_DATA
EVENT_ID
FILE_DATA
FILE_TYPE_CODE
FRONT_END_FILE_DATA
FUNCTION_DATA
FUNCTION_FORCE_INLINEE_DATA
INVOCATION_DATA
INVOCATION_VERSION_DATA
MSVC_TOOL_CODE
NAME_VALUE_PAIR_DATA
SYMBOL_NAME_DATA
TEMPLATE_INSTANTIATION_DATA
TEMPLATE_INSTANTIATION_KIND_CODE
TRACE_INFO_DATA
ÖVERSÄTTNINGSENHET_LÖSENKOD
TRANSLATION_UNIT_TYPE
ÖVERSÄTTNINGSENHET_TYP_DATA

Aktiviteter och enkla händelser

Händelser finns i två kategorier: aktiviteter och enkla händelser. Aktiviteter är pågående processer i tid som har en början och ett slut. Enkla händelser är punktliga förekomster och har ingen varaktighet. När du analyserar MSVC-spårningar med C++ Build Insights SDK får du separata händelser när en aktivitet startar och stoppas. Du får bara en händelse när en enkel händelse inträffar.

Relationer mellan förälder och barn

Aktiviteter och enkla händelser är relaterade till varandra via relationer mellan överordnade och underordnade. Den övergripande aktiviteten för en aktivitet eller en enkel händelse är den inom vilken de inträffar. När du till exempel kompilerar en källfil måste kompilatorn parsa filen och sedan generera koden. Parsnings- och kodgenereringsaktiviteterna är båda underordnade till kompileringsaktiviteten.

Enkla händelser har ingen varaktighet, så inget annat kan hända i dem. Som sådan har de aldrig några barn.

Relationerna mellan överordnad och underordnad för varje aktivitet och enkel händelse anges i händelsetabellen. Att känna till dessa relationer är viktigt när du använder C++ Build Insights-händelser. Du måste ofta förlita dig på dem för att förstå hela kontexten för en händelse.

Egenskaper

Alla händelser har följande egenskaper:

Fastighet Beskrivning
Typidentifierare Ett tal som unikt identifierar händelsetypen.
Instansidentifierare Ett tal som unikt identifierar händelsen i spårningen. Om två händelser av samma typ inträffar i en spårning får båda en unik instansidentifierare.
Starttid Den tid då en aktivitet startades eller när en enkel händelse inträffade.
Processidentifierare Ett tal som identifierar processen där händelsen inträffade.
Trådidentifierare Ett tal som identifierar tråden där händelsen inträffade.
Processorindex Ett nollbaserat index som anger vilken logisk processor händelsen genererats av.
Händelsenamn En sträng som beskriver händelsetypen.

Alla andra aktiviteter än enkla händelser har också följande egenskaper:

Fastighet Beskrivning
Stopptid Tiden då aktiviteten stoppades.
Exklusiv varaktighet Den tid som ägnas åt en aktivitet, exklusive den tid som läggs ned i dess underordnade aktiviteter.
CPU-tid Den tid som processorn använde för att köra kod i tråden som är kopplad till aktiviteten. Det inkluderar inte tid när tråden som är kopplad till aktiviteten låg i viloläge.
Exklusiv CPU-tid Samma som CPU-tid, men utan CPU-tid som används av underordnade aktiviteter.
Tidsansvar för väggklocka Aktivitetens bidrag till den totala wall-clock-tiden. Tidsansvaret i realtid tar hänsyn till parallellitet mellan aktiviteter. Vi antar till exempel att två orelaterade aktiviteter körs parallellt. Båda har en varaktighet på 10 sekunder och exakt samma start- och stopptid. I det här fallet tilldelar Build Insights både ett tidsansvar för väggklockan på 5 sekunder. Om dessa aktiviteter däremot körs en efter en utan överlappning tilldelas de båda ett tidsansvar på 10 sekunder.
Exklusivt tidsansvar för wall-clock Samma som tidsansvar enligt väggklockan, men exkluderar tidsansvar enligt väggklockan för barnaktiviteter.

Vissa händelser har sina egna egenskaper utöver de som nämns. I det här fallet visas dessa ytterligare egenskaper i händelsetabellen.

Använda händelser som tillhandahålls av C++ Build Insights SDK

Händelsestacken

När C++ Build Insights SDK ger dig en händelse, kommer den i form av en stack. Den sista posten i stacken är den aktuella händelsen, och poster före den är dess överordnade hierarki. Till exempel inträffar LTCG-start- och stopphändelser under pass 1 i länkaren. I det här fallet innehåller stacken som du får: [LINKER, PASS1, LTCG]. Den överordnade hierarkin är praktisk eftersom du kan spåra en händelse till dess rot. Om LTCG-aktiviteten som nämns ovan är långsam kan du omedelbart ta reda på vilket länkanrop som var aktuellt.

Matchande händelser och händelsestackar

C++ Build Insights SDK ger dig varje händelse i en spårning, men för det mesta bryr du dig bara om en delmängd av dem. I vissa fall kanske du bara bryr dig om en delmängd av händelsestackar. SDK:t tillhandahåller faciliteter som hjälper dig att snabbt extrahera de händelser eller händelsestackar du behöver och avvisa dem som du inte gör. Det görs genom dessa matchande funktioner:

Funktion Beskrivning
MatchEvent Behåll en händelse om den matchar en av de angivna typerna. Vidarebefordra matchade händelser till en lambda eller annan anropsbar typ. Händelsens överordnade hierarki beaktas inte av den här funktionen.
MatchEventInMemberFunction Behåll en händelse om den matchar den typ som anges i en medlemsfunktions parameter. Vidarebefordra matchade händelser till medlemsfunktionen. Händelsens överordnade hierarki beaktas inte av den här funktionen.
MatchEventStack Behåll en händelse om både händelsen och dess överordnade hierarki matchar de angivna typerna. Vidarebefordra händelsen och de matchade överordnade hierarkihändelserna till en lambda eller annan anropsbar typ.
MatchEventStackInMemberFunction Behåll en händelse om både händelsen och dess överordnade hierarki matchar de typer som anges i en medlemsfunktions parameterlista. Vidarebefordra händelsen och de matchande händelserna i den överordnade hierarkin till medlemsfunktionen.

Matchningsfunktioner för händelsestacken, som MatchEventStack, tillåter luckor när du beskriver den överordnade hierarki som ska matchas. Du kan till exempel säga att du är intresserad av stacken [LINKER, LTCG]. Det skulle också matcha stacken [LINKER, PASS1, LTCG]. Den senast angivna typen måste vara den händelsetyp som ska matchas och är inte en del av den överordnade hierarkin.

Samla in klasser

Match* Om du använder funktionerna måste du ange de typer som du vill matcha. Dessa typer väljs från en lista över avbildningsklasser. Infångningsklasser finns i flera kategorier, som beskrivs nedan.

Kategori Beskrivning
Exakt Dessa avbildningsklasser används för att matcha en specifik händelsetyp och ingen annan. Ett exempel är klassen Compiler , som matchar händelsen COMPILER .
Jokertecken Dessa avbildningsklasser kan användas för att matcha alla händelser från listan över händelser som de stöder. Jokertecknet Aktivitet matchar till exempel alla aktivitetshändelser. Ett annat exempel är jokertecknet CompilerPass , som kan matcha antingen FRONT_END_PASS eller händelsen BACK_END_PASS .
Grupp Namnen på gruppfångstklasserna slutar i Grupp. De används för att matcha flera händelser av samma typ i en rad och ignorerar luckor. De är bara meningsfulla när du matchar rekursiva händelser, eftersom du inte vet hur många som finns i händelsestacken. Den FRONT_END_FILE aktiviteten inträffar till exempel varje gång kompilatorn parsar en fil. Den här aktiviteten är rekursiv eftersom kompilatorn kan hitta ett inkluderingsdirektiv medan filen parsas. Klassen FrontEndFile matchar bara en FRONT_END_FILE händelse i stacken. Använd klassen FrontEndFileGroup för att matcha hela inkluderingshierarkin.
Wildcard-grupp En jokerteckengrupp kombinerar egenskaperna för jokertecken och grupper. Den enda klassen i den här kategorin är InvocationGroup, som matchar och samlar in alla LINKER - och COMPILER-händelser i en enda händelsestack.

Se händelsetabellen för att lära dig vilka avbildningsklasser som kan användas för att matcha varje händelse.

Efter matchning: använda insamlade händelser

När en matchning har slutförts Match* konstruerar funktionerna avbildningsklassobjekten och vidarebefordrar dem till den angivna funktionen. Använd dessa avbildningsklassobjekt för att komma åt händelsernas egenskaper.

Exempel

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;
    }
}