Condividi tramite


C++ Build Insights SDK

Build Insights SDK per C++ è compatibile con Visual Studio 2017 e versioni successive. Per visualizzare la documentazione per queste versioni, impostare il controllo selettore della versione di Visual Studio per questo articolo su Visual Studio 2017 o versione successiva. Si trova nella parte superiore del sommario in questa pagina.

C++ Build Insights SDK è una raccolta di API che consentono di creare strumenti personalizzati sulla piattaforma C++ Build Insights. Questa pagina offre una panoramica generale che consente di iniziare.

Ottenere l'SDK

È possibile scaricare C++ Build Insights SDK come pacchetto NuGet seguendo questa procedura:

  1. Da Visual Studio 2017 e versioni successive creare un nuovo progetto C++.
  2. Nel riquadro Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto.
  3. Selezionare Gestisci pacchetti NuGet dal menu di scelta rapida.
  4. In alto a destra selezionare l'origine del pacchetto nuget.org .
  5. Cercare la versione più recente del pacchetto Microsoft.Cpp.BuildInsights.
  6. Scegliere Installa.
  7. Accettare la licenza.

Leggere per informazioni sui concetti generali relativi all'SDK. È anche possibile accedere al repository GitHub ufficiale degli esempi di Build Insights per C++ per visualizzare esempi di applicazioni C++ reali che usano l'SDK.

Raccolta di una traccia

L'uso di C++ Build Insights SDK per analizzare gli eventi provenienti dalla toolchain MSVC richiede prima di tutto di raccogliere una traccia. L'SDK usa Event Tracing for Windows (ETW) come tecnologia di traccia sottostante. La raccolta di una traccia può essere eseguita in due modi:

Metodo 1: uso di vcperf in Visual Studio 2019 e versioni successive

  1. Aprire un prompt dei comandi degli strumenti nativi x64 con privilegi elevati per VS 2019.

  2. Eseguire il seguente comando: vcperf /start MySessionName

  3. Crea il progetto.

  4. Eseguire il seguente comando: vcperf /stopnoanalyze MySessionName outputTraceFile.etl

    Importante

    Usare il /stopnoanalyze comando quando si arresta la traccia con vcperf. Non è possibile usare C++ Build Insights SDK per analizzare le tracce arrestate dal normale /stop comando.

Metodo 2: a livello di codice

Usare una di queste funzioni di raccolta di tracce di C++ Build Insights SDK per avviare e arrestare le tracce a livello di codice. Il programma che esegue queste chiamate di funzione deve disporre di privilegi amministrativi. Solo le funzioni di avvio e arresto della traccia richiedono privilegi amministrativi. Tutte le altre funzioni in C++ Build Insights SDK possono essere eseguite senza di esse.

Funzionalità API C++ API C
Avvio di una traccia StartTracingSession StartTracingSessionA
StartTracingSessionW
Arresto di una traccia StopTracingSession StopTracingSessionA
StopTracingSessionW
Arresto di una traccia e
analisi immediata del risultato
StopAndAnalyzeTracingSession StopAndAnalyzeTracingSessionA
StopAndAnalyzeTracingSession
Arresto di una traccia e
rilocazione immediata del risultato
StopAndRelogTracingSession StopAndRelogTracingSessionA
StopAndRelogTracingSessionW

Le sezioni seguenti illustrano come configurare un'analisi o una sessione di rilogging. È necessario per le funzioni combinate di funzionalità, ad esempio StopAndAnalyzeTracingSession.

Utilizzo di una traccia

Dopo aver creato una traccia ETW, usare C++ Build Insights SDK per decomprimerla. L'SDK offre gli eventi in un formato che consente di sviluppare rapidamente gli strumenti. Non è consigliabile usare la traccia ETW non elaborata senza usare l'SDK. Il formato di evento usato da MSVC non è documentato, ottimizzato per la scalabilità a build di grandi dimensioni e difficile da comprendere. Inoltre, l'API di Build Insights SDK di C++ è stabile, mentre il formato di traccia ETW non elaborato è soggetto a modifiche senza preavviso.

Funzionalità API C++ API C Note
Configurazione dei callback degli eventi IAnalyzer
IRelogger
ANALYSIS_CALLBACKS
RELOG_CALLBACKS
L'SDK di Build Insights per C++ fornisce eventi tramite funzioni di callback. In C++, implementare le funzioni di callback creando un analizzatore o una classe relogger che eredita l'interfaccia IAnalyzer o IRelogger. In C implementare i callback nelle funzioni globali e fornire puntatori a essi nella struttura ANALYSIS_CALLBACKS o RELOG_CALLBACKS.
Compilazione di gruppi MakeStaticAnalyzerGroup
MakeStaticReloggerGroup
MakeDynamicAnalyzerGroup
MakeDynamicReloggerGroup
L'API C++ fornisce funzioni helper e tipi per raggruppare più oggetti analizzatori e rilogger. I gruppi sono un modo ordinato per dividere un'analisi complessa in passaggi più semplici. vcperf è organizzato in questo modo.
Analisi o rilogging Analisi.
Ripetere il log
AnalyzeA
AnalyzeW
RilogA
RilogW

Analisi e rilogging

L'utilizzo di una traccia viene eseguito tramite una sessione di analisi o una sessione di rilogging.

L'uso di un'analisi regolare è appropriato per la maggior parte degli scenari. Questo metodo offre la flessibilità necessaria per scegliere il formato di output: printf testo, xml, JSON, database, chiamate REST e così via.

Il relogging è destinato ad analisi speciali che devono produrre un file di output ETW. Usando il relogging, è possibile convertire gli eventi di C++ Build Insights nel proprio formato di evento ETW. Un uso appropriato del rilogging sarebbe quello di associare i dati di Build Insights C++ agli strumenti e all'infrastruttura ETW esistenti. Ad esempio, vcperf usa le interfacce di rilogging. Ciò è dovuto al fatto che deve produrre dati che windows analizzatore prestazioni, uno strumento ETW, può comprendere. Alcune conoscenze precedenti sul funzionamento di ETW sono necessarie se si prevede di usare le interfacce di rilogging.

Creazione di gruppi di analizzatori

È importante sapere come creare gruppi. Ecco un esempio che mostra come creare un gruppo di analizzatori che stampa Hello, world! per ogni evento di avvio dell'attività ricevuto.

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

Uso degli eventi

Funzionalità API C++ API C Note
Eventi di corrispondenza e filtro MatchEventStackInMemberFunction
MatchEventStack
MatchEventInMemberFunction
MatchEvent
L'API C++ offre funzioni che semplificano l'estrazione degli eventi di cui si è a cuore dalle tracce. Con l'API C, questo filtro deve essere eseguito a mano.
Tipi di dati dell'evento Attività
BackEndPass
BottomUp
C1DLL
C2DLL
CodeGeneration
CommandLine
Compilatore
CompilerPass
AmbienteVariable
Evento
EventGroup
EventStack
ExecutableImageOutput
ExpOutput
FileInput
FileOutput
ForceInlinee
FrontEndFile
FrontEndFileGroup
FrontEndPass
Funzione
HeaderUnit
ImpLibOutput
Chiamata
InvocationGroup
LibOutput
Linker
LinkerGroup
LinkerPass
LTCG
Modulo
ObjOutput
OptICF
OptLBR
OptRef
Pass1
Pass2
PrecompiledHeader
PreLTCGOptRef
SimpleEvent
SymbolName
TemplateInstantiation
TemplateInstantiationGroup
Thread
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
TRANSLATION_UNIT_PASS_CODE
TRANSLATION_UNIT_TYPE
TRANSLATION_UNIT_TYPE_DATA

Attività ed eventi semplici

Gli eventi sono disponibili in due categorie: attività ed eventi semplici. Le attività sono processi in corso nel tempo che hanno un inizio e una fine. Gli eventi semplici sono occorrenze puntuali e non hanno una durata. Quando si analizzano tracce MSVC con C++ Build Insights SDK, si riceveranno eventi separati all'avvio e all'arresto di un'attività. Si riceverà un solo evento quando si verifica un evento semplice.

Relazioni padre-figlio

Le attività e gli eventi semplici sono correlati tra loro tramite relazioni padre-figlio. L'elemento padre di un'attività o di un evento semplice è l'attività che comprende in cui si verificano. Ad esempio, quando si compila un file di origine, il compilatore deve analizzare il file, quindi generare il codice. Le attività di analisi e generazione del codice sono entrambi elementi figlio dell'attività del compilatore.

Gli eventi semplici non hanno una durata, quindi nessun altro può verificarsi all'interno di essi. Di conseguenza, non hanno mai figli.

Le relazioni padre-figlio di ogni attività e evento semplice sono indicate nella tabella eventi. Conoscere queste relazioni è importante quando si usano gli eventi di Build Insights C++. Spesso è necessario basarsi su di essi per comprendere il contesto completo di un evento.

Proprietà

Tutti gli eventi hanno le proprietà seguenti:

Proprietà Descrizione
Identificatore del tipo Numero che identifica in modo univoco il tipo di evento.
Identificatore dell'istanza Numero che identifica in modo univoco l'evento all'interno della traccia. Se due eventi dello stesso tipo si verificano in una traccia, entrambi ottengono un identificatore di istanza univoco.
Ora di inizio Ora di avvio di un'attività o dell'ora in cui si è verificato un evento semplice.
Identificatore del processo Numero che identifica il processo in cui si è verificato l'evento.
Identificatore del thread Numero che identifica il thread in cui si è verificato l'evento.
Indice processore Indice in base zero che indica il processore logico da cui è stato generato l'evento.
Nome evento Stringa che descrive il tipo di evento.

Tutte le attività diverse da eventi semplici hanno anche queste proprietà:

Proprietà Descrizione
Tempo di arresto Ora in cui l'attività è stata arrestata.
Durata esclusiva Tempo trascorso in un'attività, escluso il tempo trascorso nelle attività figlio.
Tempo CPU Tempo impiegato dalla CPU per l'esecuzione del codice nel thread collegato all'attività. Non include l'ora di sospensione del thread collegato all'attività.
Tempo esclusivo cpu Uguale al tempo della CPU, ma escluso il tempo di CPU impiegato dalle attività figlio.
Responsabilità dell'ora del muro Contributo dell'attività all'ora complessiva del tempo. La responsabilità del tempo a muro tiene conto del parallelismo tra le attività. Si supponga, ad esempio, che due attività non correlate vengano eseguite in parallelo. Entrambi hanno una durata di 10 secondi e esattamente lo stesso tempo di inizio e arresto. In questo caso, Build Insights assegna sia una responsabilità di tempo in tempo reale di 5 secondi. Al contrario, se queste attività vengono eseguite una dopo l'altra senza sovrapposizioni, a entrambi viene assegnata una responsabilità di tempo di clock a muro di 10 secondi.
Responsabilità esclusiva del tempo a muro Come la responsabilità del tempo a muro, ma esclude la responsabilità dell'ora del muro delle attività dei bambini.

Alcuni eventi hanno proprietà proprie oltre quelle menzionate. In questo caso, queste proprietà aggiuntive sono elencate nella tabella eventi.

Utilizzo di eventi forniti da C++ Build Insights SDK

Stack di eventi

Ogni volta che C++ Build Insights SDK offre un evento, si presenta sotto forma di stack. L'ultima voce nello stack è l'evento corrente e le voci prima che siano la gerarchia padre. Ad esempio, gli eventi di avvio e arresto ltcg si verificano durante il passaggio 1 del linker. In questo caso, lo stack ricevuto contiene: [LINKER, PASS1, LTCG]. La gerarchia padre è utile perché è possibile ricondurre un evento alla radice. Se l'attività LTCG menzionata in precedenza è lenta, è possibile apprendere immediatamente quale chiamata del linker è stata coinvolta.

Corrispondenza di eventi e stack di eventi

C++ Build Insights SDK offre ogni evento in una traccia, ma la maggior parte del tempo è importante solo per un sottoinsieme di essi. In alcuni casi, è possibile preoccuparsi solo di un subset di stack di eventi. L'SDK offre funzionalità che consentono di estrarre rapidamente gli eventi o lo stack di eventi necessari e rifiutare quelli non necessari. Questa operazione viene eseguita tramite queste funzioni di corrispondenza:

Funzione Descrizione
MatchEvent Mantenere un evento se corrisponde a uno dei tipi specificati. Inoltrare gli eventi corrispondenti a un'espressione lambda o a un altro tipo chiamabile. La gerarchia padre dell'evento non viene considerata da questa funzione.
MatchEventInMemberFunction Mantenere un evento se corrisponde al tipo specificato nel parametro di una funzione membro. Inoltrare gli eventi corrispondenti alla funzione membro. La gerarchia padre dell'evento non viene considerata da questa funzione.
MatchEventStack Mantenere un evento se l'evento e la relativa gerarchia padre corrispondono ai tipi specificati. Inoltrare l'evento e gli eventi della gerarchia padre corrispondenti a un'espressione lambda o a un altro tipo chiamabile.
MatchEventStackInMemberFunction Mantenere un evento se l'evento e la relativa gerarchia padre corrispondono ai tipi specificati nell'elenco dei parametri di una funzione membro. Inoltrare l'evento e gli eventi della gerarchia padre corrispondenti alla funzione membro.

Le funzioni di corrispondenza dello stack di eventi, ad esempio MatchEventStack consentono lacune durante la descrizione della gerarchia padre. Ad esempio, si può dire di essere interessati allo stack [LINKER, LTCG]. Corrisponderebbe anche allo stack [LINKER, PASS1, LTCG]. L'ultimo tipo specificato deve essere il tipo di evento da trovare e non fa parte della gerarchia padre.

Classi di acquisizione

Per usare le Match* funzioni è necessario specificare i tipi che si desidera associare. Questi tipi vengono selezionati da un elenco di classi di acquisizione. Le classi di acquisizione sono disponibili in diverse categorie, descritte di seguito.

Categoria Descrizione
Exact Queste classi di acquisizione vengono usate per trovare una corrispondenza con un tipo di evento specifico e nessun altro. Un esempio è la classe Compiler , che corrisponde all'evento COMPILER .
Wildcard (Carattere jolly) Queste classi di acquisizione possono essere usate per trovare le corrispondenze con qualsiasi evento dall'elenco di eventi supportati. Ad esempio, il carattere jolly Activity corrisponde a qualsiasi evento di attività. Un altro esempio è il carattere jolly CompilerPass , che può corrispondere al FRONT_END_PASS o all'evento BACK_END_PASS .
Raggruppa I nomi delle classi di acquisizione di gruppo terminano in Group. Vengono usati per trovare le corrispondenze con più eventi dello stesso tipo in una riga, ignorando le lacune. Hanno senso solo quando corrispondono a eventi ricorsivi, perché non si conosce il numero di eventi presenti nello stack di eventi. Ad esempio, l'attività FRONT_END_FILE viene eseguita ogni volta che il compilatore analizza un file. Questa attività è ricorsiva perché il compilatore potrebbe trovare una direttiva di inclusione durante l'analisi del file. La classe FrontEndFile corrisponde a un solo evento FRONT_END_FILE nello stack. Usare la classe FrontEndFileGroup per trovare la corrispondenza con l'intera gerarchia di inclusione.
Gruppo con caratteri jolly Un gruppo con caratteri jolly combina le proprietà dei caratteri jolly e dei gruppi. L'unica classe di questa categoria è InvocationGroup, che corrisponde e acquisisce tutti gli eventi LINKER e COMPILER in un singolo stack di eventi.

Fare riferimento alla tabella eventi per informazioni sulle classi di acquisizione che è possibile usare per trovare le corrispondenze con ogni evento.

Dopo la corrispondenza: uso degli eventi acquisiti

Al termine di una corrispondenza, le Match* funzioni costruiscono gli oggetti della classe di acquisizione e li inoltrano alla funzione specificata. Usare questi oggetti classe di acquisizione per accedere alle proprietà degli eventi.

Esempio

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