Compartir vía


SDK de C++ Build Insights

El SDK de C++ Build Insights es compatible con Visual Studio 2017 y versiones posteriores. Para ver la documentación de estas versiones, establezca el control de selector de Versión de Visual Studio para este artículo en Visual Studio 2017 o versiones posteriores. Se encuentra en la parte superior de la tabla de contenido de esta página.

El SDK de C++ Build Insights es una colección de API que permiten crear herramientas personalizadas basadas en la plataforma de C++ Build Insights. En esta página se proporciona información general de alto nivel que lo ayudará a empezar.

Obtención del SDK

Siga estos pasos para descargar el SDK de C++ Build Insights como un paquete NuGet:

  1. En Visual Studio 2017 y versiones posteriores, cree un proyecto nuevo de C++.
  2. En el panel del Explorador de soluciones, haga clic con el botón derecho en su proyecto.
  3. Seleccione Administrar paquetes NuGet en el menú contextual.
  4. En la parte superior derecha, seleccione el origen del paquete nuget.org.
  5. Busque la versión más reciente del paquete Microsoft.Cpp.BuildInsights.
  6. Elija Instalar.
  7. Acepte la licencia.

Siga leyendo para obtener información sobre los conceptos generales relacionados con el SDK. También puede acceder al repositorio GitHub oficial de ejemplos de C++ Build Insights para ver ejemplos de aplicaciones de C++ reales que usan el SDK.

Recopilación de un seguimiento

El uso del SDK de C++ Build Insights para analizar eventos que proceden de la cadena de herramientas de MSVC requiere que primero se recopile un seguimiento. El SDK usa el Seguimiento de eventos para Windows (ETW) como la tecnología de seguimiento subyacente. La recopilación de un seguimiento se puede hacer de dos maneras:

Método 1: uso de vcperf en Visual Studio 2019 y versiones posteriores

  1. Abra un símbolo del sistema de las herramientas nativas x64 con privilegios elevados para VS 2019.

  2. Ejecute el siguiente comando: vcperf /start MySessionName

  3. Compile el proyecto.

  4. Ejecute el siguiente comando: vcperf /stopnoanalyze MySessionName outputTraceFile.etl

    Importante

    Use el comando /stopnoanalyze al detener el seguimiento con vcperf. No puede usar el SDK de C++ Build Insights para analizar los seguimientos detenidos por el comando /stop habitual.

Método 2: mediante programación

Use cualquiera de estas funciones de recopilación de seguimiento del SDK de C++ Build Insights para iniciar y detener los seguimientos mediante programación. El programa que ejecuta estas llamadas de función debe tener privilegios administrativos. Solo las funciones de inicio y detención de seguimiento requieren privilegios administrativos. Todas las demás funciones del SDK de C++ Build Insights se pueden ejecutar sin ellos.

Funcionalidad API de C++ API de C
Inicio de un seguimiento StartTracingSession StartTracingSessionA
StartTracingSessionW
Detención de un seguimiento StopTracingSession StopTracingSessionA
StopTracingSessionW
Detención de un seguimiento y
análisis inmediato del resultado
StopAndAnalyzeTracingSession StopAndAnalyzeTracingSessionA
StopAndAnalyzeTracingSession
Detención de un seguimiento y
registro inmediato del resultado
StopAndRelogTracingSession StopAndRelogTracingSessionA
StopAndRelogTracingSessionW

En las secciones siguientes se muestra cómo configurar una sesión de análisis o de registro. Es necesario para las funciones de funcionalidad combinada, como StopAndAnalyzeTracingSession.

Consumo de un seguimiento

Una vez que tenga un seguimiento de ETW, use el SDK de C++ Build Insights para desempaquetarlo. El SDK proporciona los eventos en un formato que le permite desarrollar rápidamente sus herramientas. No se recomienda consumir el seguimiento de ETW sin procesar sin usar el SDK. El formato de evento que el MSVC usa no está documentado, está optimizado para escalar a compilaciones muy grandes y es difícil de entender. Además, la API del SDK de C++ Build Insights es establece, mientras que el formato de seguimiento de ETW sin procesar está sujeto a cambios sin previo aviso.

Funcionalidad API de C++ API de C Notas
Configuración de devoluciones de llamada de evento IAnalyzer
IRelogger
ANALYSIS_CALLBACKS
RELOG_CALLBACKS
El SDK de C++ Build Insights proporciona eventos a través de funciones de devolución de llamada. En C++, implemente las funciones de devolución de llamada mediante la creación de una clase de analizador o de registrador que herede la interfaz IAnalyzer o IRelogger. En C, implemente las devoluciones de llamada en funciones globales y proporcione punteros que las señalen en la estructura ANALYSIS_CALLBACKS o RELOG_CALLBACKS.
Creación de grupos MakeStaticAnalyzerGroup
MakeStaticReloggerGroup
MakeDynamicAnalyzerGroup
MakeDynamicReloggerGroup
La API de C++ proporciona tipos y funciones auxiliares para agrupar en conjunto varios objetos de analizador y de registro. Los grupos son una manera práctica de dividir un análisis complejo en pasos más sencillos. vcperf está organizado de esta manera.
Análisis o registro Analizar
Registro
AnalyzeA
AnalyzeW
RelogA
RelogW

Análisis y registro

El consumo de un seguimiento se realiza a través de una sesión de análisis o una sesión de registro.

El uso de un análisis normal es adecuado para la mayoría de los escenarios. Este método ofrece la flexibilidad de elegir el formato de salida: printf texto, XML, JSON, base de datos, llamadas REST, etc.

El registro es para los análisis de uso especial que necesitan generar un archivo de salida de ETW. Mediante el registro, puede traducir los eventos de C++ Build Insights a su propio formato de evento ETW. Un uso apropiado del registro sería enlazar datos de C++ Build Insights a la infraestructura y las herramientas de ETW existentes. Por ejemplo, vcperf usa las interfaces de registro. Esto es porque debe generar datos que Windows Performance Analyzer, una herramienta de ETW, pueda entender. Si planea usar las interfaces de registro, se requiere ciertos conocimientos previos de cómo funciona ETW.

Creación de grupos de analizadores

Resulta importante saber cómo crear grupos. Este es un ejemplo que muestra cómo crear un grupo de analizadores que imprime el mensaje Hola mundo para cada inicio de actividad que se reciba.

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 de eventos

Funcionalidad API de C++ API de C Notas
Coincidencia y filtrado de eventos MatchEventStackInMemberFunction
MatchEventStack
MatchEventInMemberFunction
MatchEvent
La API de C++ ofrece funciones que facilitan la extracción de los eventos que le interesan de los seguimientos. Con la API de C, este filtrado se debe hacer manualmente.
Tipos de datos de eventos Actividad
BackEndPass
BottomUp
C1DLL
C2DLL
CodeGeneration
CommandLine
Compilador
CompilerPass
EnvironmentVariable
Evento
EventGroup
EventStack
ExecutableImageOutput
ExpOutput
FileInput
FileOutput
ForceInlinee
FrontEndFile
FrontEndFileGroup
FrontEndPass
Función
HeaderUnit
ImpLibOutput
Invocación
InvocationGroup
LibOutput
Enlazador
LinkerGroup
LinkerPass
LTCG
Módulo
ObjOutput
OptICF
OptLBR
OptRef
Pass1
Pass2
PrecompiledHeader
PreLTCGOptRef
SimpleEvent
SymbolName
TemplateInstantiation
TemplateInstantiationGroup
Subproceso
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

Actividades y eventos sencillos

Los eventos tienen dos categorías: actividades y eventos sencillos. Las actividades son procesos continuos en el tiempo que tienen un inicio y un final. Los eventos sencillos son ocurrencias puntuales sin duración. Al analizar los seguimientos de MSVC con el SDK de C++ Build Insights, recibirá eventos independientes cuando una actividad se inicie y se detenga. Recibirá solo un evento cuando se produzca un evento sencillo.

Relaciones de elementos primarios y secundarios

Las actividades y los eventos sencillos se relacionan entre sí a través de las relaciones de elementos primarios y secundarios. El elemento primario de una actividad o de un evento sencillo es la actividad englobante en la que se producen. Por ejemplo, al compilar un archivo de código fuente, el compilador tiene que analizar el archivo y, luego, generar el código. Las actividades de análisis y generación de código son elementos secundarios de la actividad del compilador.

Los eventos sencillos no tienen una duración, por lo que no puede ocurrir nada más en ellos. De ese modo, nunca tienen elementos secundarios.

Las relaciones de elementos primarios y secundarios de cada actividad y evento sencillo se indican en la tabla de eventos. Conocer estas relaciones resulta importante al consumir eventos de C++ Build Insights. Con frecuencia tendrá que basarse en ellos para entender el contexto completo de un evento.

Propiedades

Todos los eventos tienen las propiedades siguientes:

Propiedad Descripción
Identificador de tipo Número que identifica el tipo de evento de manera única.
Identificador de instancia Número que identifica el evento dentro del seguimiento de manera única. Si en un seguimiento se producen dos eventos del mismo tipo, ambos obtienen un identificador de instancia único.
Hora de inicio Hora a la que se inició una actividad o la hora a la que se produjo un evento sencillo.
Identificador de proceso Número que identifica el proceso en el que se produjo el evento.
Identificador de subproceso Número que identifica el subproceso en el que se produjo el evento.
Índice de procesador Índice de base cero que indica qué procesador lógico emitió el evento.
Nombre del evento Cadena que describe el tipo de evento.

Todas las actividades distintas de los eventos sencillos también tienen estas propiedades:

Propiedad Descripción
Hora de detención Hora a la que se detuvo la actividad.
Duración exclusiva Tiempo dedicado a una actividad, sin incluir el tiempo dedicado a sus actividades secundarias.
Tiempo de CPU Tiempo que la CPU dedica a ejecutar código en el subproceso adjunto a la actividad. No incluye el tiempo durante el cual el subproceso adjunto a la actividad estaba en suspensión.
Tiempo de CPU exclusivo Igual que el tiempo de CPU, pero sin incluir el tiempo que la CPU dedica a sus actividades secundarias.
Responsabilidad de tiempo de reloj Contribución de la actividad al tiempo de reloj global. La responsabilidad de tiempo de reloj tiene en cuenta el paralelismo entre las actividades. Por ejemplo, supongamos que dos actividades no relacionadas se ejecutan en paralelo. Ambos tienen una duración de 10 segundos y exactamente la misma hora de inicio y de finalización. En este caso, Build Insights asigna a ambos una responsabilidad de tiempo de reloj de 5 segundos. Por el contrario, si estas actividades se ejecutan una tras otra sin superposición, se les asigna a ambas una responsabilidad de tiempo de reloj de 10 segundos.
Responsabilidad de tiempo de reloj exclusiva Igual que la responsabilidad de tiempo de reloj, pero excluye la responsabilidad de tiempo de reloj de las actividades secundarias.

Algunos eventos tienen sus propias propiedades más allá de las mencionadas. En este caso, estas propiedades adicionales se indican en la tabla de eventos.

Consumo de eventos proporcionados por el SDK de C++ Build Insights

La pila de eventos

Cada vez que el SDK de C++ Build Insights proporciona un evento, viene en formato de pila. La última entrada de la pila es el evento actual y las entradas anteriores son su jerarquía primaria. Por ejemplo, los eventos de inicio y detención de LTCG ocurren durante el paso 1 del enlazador. En este caso, la pila que se recibiría contiene: [LINKER, PASS1, LTCG]. La jerarquía primaria resulta útil porque es posible hacer el seguimiento de un evento hasta su raíz. Si la actividad de LTCG mencionada anteriormente es lenta, puede saber de inmediato qué invocación del enlazador estuvo implicada.

Eventos y pilas de eventos coincidentes

El SDK de C++ Build Insights le proporciona todos los eventos de un seguimiento, pero la mayor parte del tiempo solo le interesa un subconjunto de ellos. En algunos casos, es posible que solo le interese un subconjunto de pilas de eventos. El SDK proporciona los recursos para ayudarlo a extraer rápidamente los eventos o la pila de eventos que necesita y a rechazar los que no. Esto se hace a través de estas funciones coincidentes:

Función Descripción
MatchEvent Conserve un evento si coincide con uno de los tipos especificados. Reenvíe los eventos coincidentes a una expresión lambda o a otro tipo al que se puede llamar. Esta función no toma en cuenta la jerarquía primaria del evento.
MatchEventInMemberFunction Conserve un evento si coincide con el tipo especificado en el parámetro de una función miembro. Reenvíe los eventos coincidentes a la función miembro. Esta función no toma en cuenta la jerarquía primaria del evento.
MatchEventStack Conserve un evento si tanto el evento como su jerarquía primaria coinciden con los tipos especificados. Reenvíe el evento y los eventos de la jerarquía primaria coincidente a una expresión lambda o a otro tipo al que se puede llamar.
MatchEventStackInMemberFunction Conserve un evento si tanto el evento como su jerarquía primaria coinciden con los tipos especificados en la lista de parámetros de una función miembro. Reenvié el evento y los eventos de la jerarquía primaria coincidente a la función miembro.

Las funciones coincidentes de la pila de eventos como MatchEventStack permiten hacer coincidir las lagunas en la descripción de la jerarquía primaria. Por ejemplo, digamos que le interesa la pila [LINKER, LTCG]. También coincidiría con la pila [LINKER, PASS1, LTCG]. El último tipo especificado debe ser el tipo de evento con que se va a coincidir y no forma parte de la jerarquía primaria.

Clases de captura

El uso de las funciones Match* requiere especificar los tipos que quiere hacer coincidir. Estos tipos se seleccionan de una lista de clases de captura. Las clases de captura tienen varias categorías, las que se describen a continuación.

Category Descripción
Exact Estas clases de captura se usan para coincidir con un tipo de evento específico y ningún otro. Un ejemplo es la clase Compiler, que coincide con el evento COMPILER.
Wildcard (Carácter comodín) Estas clases de captura se pueden usar para coincidir con cualquier evento de la lista de eventos que admiten. Por ejemplo, el carácter comodín Activity coincide con cualquier evento de actividad. Otro ejemplo es el carácter comodín CompilerPass, que puede coincidir con el evento FRONT_END_PASS o con el evento BACK_END_PASS.
Grupo Los nombres de las clases de captura de grupo finalizan en Group. Se usan para coincidir con varios eventos del mismo tipo en una fila, sin considerar las lagunas. Solo tienen sentido al hacer coincidir eventos recursivos, porque no se sabe cuántos hay en la pila de eventos. Por ejemplo, la actividad FRONT_END_FILE se produce cada vez que el compilador analiza un archivo. Esta actividad es recursiva porque el compilador podría encontrar una directiva Include al analizar el archivo. La clase FrontEndFile solo coincide con un evento FRONT_END_FILE de la pila. Use la clase FrontEndFileGroup para coincidir con toda la jerarquía Include.
Grupo de caracteres comodín Un grupo de caracteres comodín combina las propiedades de los caracteres comodín y los grupos. La única clase de esta categoría es InvocationGroup, que coincide con todos los eventos LINKER y COMPILER de una sola pila de eventos y los captura.

Consulte la tabla de eventos para saber qué clases de captura se pueden usar para coincidir con cada evento.

Después de la coincidencia: uso de los eventos capturados

Una vez que se completa correctamente una coincidencia, las funciones Match* construyen los objetos de la clase de captura y los reenvía a la función especificada. Use estos objetos de la clase de captura para acceder a las propiedades de los eventos.

Ejemplo

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