Sdílet prostřednictvím


Sada SDK pro C++ Build Insights

Sada C++ Build Insights SDK je kompatibilní se sadou Visual Studio 2017 a novějšími verzemi. Pokud chcete zobrazit dokumentaci k těmto verzím, nastavte ovládací prvek selektoru verzí sady Visual Studio pro tento článek na Visual Studio 2017 nebo novější. Nachází se v horní části obsahu na této stránce.

Sada C++ Build Insights SDK je kolekce rozhraní API, která umožňují vytvářet přizpůsobené nástroje na platformě C++ Build Insights. Tato stránka obsahuje základní přehled, který vám pomůže začít.

Získání sady SDK

Sadu SDK C++ Build Insights si můžete stáhnout jako balíček NuGet pomocí následujícího postupu:

  1. V sadě Visual Studio 2017 a novějších vytvořte nový projekt C++.
  2. V podokně Průzkumník řešení klikněte pravým tlačítkem na projekt.
  3. V místní nabídce vyberte Spravovat balíčky NuGet.
  4. V pravém horním rohu vyberte zdroj balíčku nuget.org .
  5. Vyhledejte nejnovější verzi balíčku Microsoft.Cpp.BuildInsights.
  6. Zvolte Nainstalovat.
  7. Přijměte licenci.

Přečtěte si informace o obecných konceptech kolem sady SDK. Můžete také získat přístup k oficiálnímu úložišti GitHub s ukázkami buildů C++, abyste viděli příklady skutečných aplikací C++, které používají sadu SDK.

Shromažďování trasování

K analýze událostí přicházejících ze sady nástrojů MSVC je potřeba nejprve shromáždit trasování pomocí sady SDK pro sestavení jazyka C++. Sada SDK používá trasování událostí pro Windows (ETW) jako základní technologii trasování. Shromažďování trasování lze provést dvěma způsoby:

Metoda 1: Použití vcperf v sadě Visual Studio 2019 a novější

  1. Otevřete příkazový řádek nativních nástrojů x64 se zvýšenými oprávněními pro VS 2019.

  2. Spusťte následující příkaz: vcperf /start MySessionName.

  3. Sestavte svůj projekt.

  4. Spusťte následující příkaz: vcperf /stopnoanalyze MySessionName outputTraceFile.etl.

    Důležité

    /stopnoanalyze Při zastavování trasování pomocí nástroje vcperf použijte příkaz. Sadu SDK C++ Build Insights nemůžete použít k analýze trasování zastavených pravidelným /stop příkazem.

Metoda 2: programově

K programovému spuštění a zastavení trasování použijte některou z těchto funkcí trasování sady C++ Build Insights SDK. Program, který spouští tato volání funkcí, musí mít oprávnění správce. Pouze funkce pro spuštění a zastavení trasování vyžadují oprávnění správce. Všechny ostatní funkce v sadě C++ Build Insights SDK je možné spouštět bez nich.

Funkce Rozhraní API C++ C API
Spuštění trasování StartTracingSession StartTracingSessionA
StartTracingSessionW
Zastavení trasování StopTracingSession StopTracingSessionA
StopTracingSessionW
Zastavení trasování a
okamžitá analýza výsledku
StopAndAnalyzeTracingSession StopAndAnalyzeTracingSessionA
StopAndAnalyzeTracingSession
Zastavení trasování a
okamžité opětovné zalogování výsledku
StopAndRelogTracingSession StopAndRelogTracingSessionA
StopAndRelogTracingSessionW

V následujících částech se dozvíte, jak nakonfigurovat analýzu nebo relaci relogování. Vyžaduje se pro kombinované funkce, jako je StopAndAnalyzeTracingSession.

Využívání trasování

Jakmile budete mít trasování Trasování událostí pro Windows, použijte k rozbalení sadu SDK C++ Build Insights. Sada SDK poskytuje události ve formátu, který umožňuje rychle vyvíjet nástroje. Bez použití sady SDK nedoporučujeme využívat nezpracované trasování trasování Trasování událostí pro Windows. Formát události používaný msVC je nezdokumentovaný, optimalizovaný tak, aby se škáloval na obrovské buildy, a těžko dávat smysl. Kromě toho je rozhraní API sady SDK pro Build Insights jazyka C++ stabilní, zatímco nezpracovaný formát trasování trasování událostí pro Windows se může bez předchozího upozornění změnit.

Funkce Rozhraní API C++ C API Notes
Nastavení zpětných volání událostí IAnalyzer
IRelogger
ANALYSIS_CALLBACKS
RELOG_CALLBACKS
Sada C++ Build Insights SDK poskytuje události prostřednictvím funkcí zpětného volání. V jazyce C++ implementujte funkce zpětného volání vytvořením analyzátoru nebo relogger třídy, která dědí rozhraní IAnalyzer nebo IRelogger. V jazyce C implementujte zpětná volání v globálních funkcích a poskytněte na ně ukazatele ve struktuře ANALYSIS_CALLBACKS nebo RELOG_CALLBACKS.
Vytváření skupin MakeStaticAnalyzerGroup
MakeStaticReloggerGroup
MakeDynamicAnalyzerGroup
MakeDynamicReloggerGroup
Rozhraní API jazyka C++ poskytuje pomocné funkce a typy pro seskupení více analyzátorů a relogger objektů dohromady. Skupiny představují elegantní způsob rozdělení komplexní analýzy do jednodušších kroků. Vcperf je uspořádaný tímto způsobem.
Analýza nebo relogování Analýza
Relog
Analýza A
AnalyzeW
RelogA
RelogW

Analýza a relogování

Využití trasování se provádí buď prostřednictvím relace analýzy, nebo relace relogování.

Použití pravidelné analýzy je vhodné pro většinu scénářů. Tato metoda poskytuje flexibilitu při výběru výstupního formátu: printf text, xml, JSON, databáze, volání REST atd.

Relogování je určené pro speciální analýzy, které potřebují vytvořit výstupní soubor ETW. Pomocí relogování můžete přeložit události C++ Build Insights do vlastního formátu událostí pro Windows. Vhodné použití relogování by bylo připojit data C++ Build Insights k existujícím nástrojům a infrastruktuře trasování událostí pro Windows. Například vcperf využívá rozhraní pro přelogování. Je to proto, že musí vytvářet data, která nástroj pro Windows Analyzátor výkonu, nástroj pro Windows Pro Windows dokáže pochopit. Některé předchozí znalosti o tom, jak ETW funguje, je potřeba, pokud plánujete používat rozhraní pro přelogování.

Vytváření skupin analyzátorů

Je důležité vědět, jak vytvářet skupiny. Tady je příklad, který ukazuje, jak vytvořit skupinu analyzátorů, která vytiskne Hello, World! pro každou událost zahájení aktivity, kterou obdrží.

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

Použití událostí

Funkce Rozhraní API C++ C API Notes
Porovnávání a filtrování událostí MatchEventStackInMemberFunction
MatchEventStack
MatchEventInMemberFunction
MatchEvent
Rozhraní API jazyka C++ nabízí funkce, které usnadňují extrakci událostí, které vás zajímají, z trasování. S rozhraním API jazyka C musí být toto filtrování provedeno ručně.
Datové typy událostí Aktivita
BackEndPass
Dole
C1DLL
C2DLL
Generování kódu
Příkazový řádek
Překladač
CompilerPass
EnvironmentVariable
Událost
EventGroup
EventStack
Spustitelný souborImageOutput
ExpOutput
FileInput
FileOutput
ForceInlinee
FrontEndFile
FrontEndFileGroup
FrontEndPass
Funkce
HeaderUnit
ImpLibOutput
Vyvolání
InvocationGroup
LibOutput
Linker
LinkerGroup
LinkerPass
LTCG
Modul
ObjOutput
OptICF
OptLBR
OptRef
Pass1
Pass2
PrekompiledHeader
PreLTCGOptRef
SimpleEvent
SymbolName
TemplateInstantiation
TemplateInstantiationGroup
Vlákno
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

Aktivity a jednoduché události

Události mají dvě kategorie: aktivity a jednoduché události. Aktivity jsou probíhající procesy v čase, které mají začátek a konec. Jednoduché události jsou interpunkční výskyty a nemají dobu trvání. Při analýze trasování MSVC pomocí sady C++ Build Insights SDK obdržíte při spuštění a zastavení aktivity samostatné události. Když dojde k jednoduché události, obdržíte pouze jednu událost.

Vztahy nadřazenosti a podřízenosti

Aktivity a jednoduché události spolu vzájemně souvisejí prostřednictvím vztahů nadřazenosti a podřízenosti. Nadřazenou aktivitou nebo jednoduchou událostí je zahrnutí aktivity, ve které k nim dochází. Například při kompilaci zdrojového souboru musí kompilátor soubor analyzovat a pak vygenerovat kód. Aktivity analýzy a generování kódu jsou obě podřízené aktivitě kompilátoru.

Jednoduché události nemají dobu trvání, takže se v nich nic jiného nestane. Takhle nikdy nemají žádné děti.

Relace nadřazenosti a podřízenosti jednotlivých aktivit a jednoduché události jsou uvedené v tabulce událostí. Znalost těchto relací je důležitá při využívání událostí C++ Build Insights. Často se na ně budete muset spolehnout, abyste porozuměli úplnému kontextu události.

Vlastnosti

Všechny události mají následující vlastnosti:

Vlastnost Popis
Identifikátor typu Číslo, které jednoznačně identifikuje typ události.
Identifikátor instance Číslo, které jednoznačně identifikuje událost v rámci trasování. Pokud v trasování dojde ke dvěma událostem stejného typu, oba získají jedinečný identifikátor instance.
Počáteční čas Čas zahájení aktivity nebo čas, kdy došlo k jednoduché události.
Identifikátor procesu Číslo, které identifikuje proces, ve kterém došlo k události.
Identifikátor vlákna Číslo, které identifikuje vlákno, ve kterém došlo k události.
Index procesoru Index založený na nule označující, kterým logickým procesorem událost vygeneroval.
Název události Řetězec, který popisuje typ události.

Všechny aktivity kromě jednoduchých událostí mají také tyto vlastnosti:

Vlastnost Popis
Čas zastavení Čas, kdy se aktivita zastavila.
Výhradní doba trvání Doba strávená v aktivitě, s výjimkou času stráveného ve svých podřízených aktivitách.
Čas procesoru Doba, kterou procesor strávil spouštěním kódu ve vlákně připojeném k aktivitě. Nezahrnuje čas, kdy vlákno připojené k aktivitě spí.
Exkluzivní čas procesoru Stejné jako čas procesoru, ale s výjimkou času procesoru stráveného podřízenými aktivitami.
Odpovědnost za čas strávený hodinou Příspěvek aktivity k celkovému času na nástěnné hodiny. Odpovědnost za nástěnný čas bere v úvahu paralelismus mezi aktivitami. Předpokládejme například, že se paralelně spouští dvě nesouvisející aktivity. Oba mají dobu trvání 10 sekund a přesně stejnou dobu spuštění a zastavení. V tomto případě build Insights přiřazuje odpovědnost za 5 sekund na 5 sekund. Naproti tomu pokud tyto aktivity běží jeden po druhém bez překrytí, oba mají přiřazenou odpovědnost za 10 sekund hodin.
Výhradní odpovědnost za hodiny Stejná jako zodpovědnost za hodiny, ale vylučuje odpovědnost za hodiny dětí.

Některé události mají své vlastní vlastnosti nad rámec zmíněných událostí. V tomto případě jsou tyto další vlastnosti uvedeny v tabulce událostí.

Využívání událostí poskytovaných sadou SDK pro buildy jazyka C++

Zásobník událostí

Pokaždé, když vám sada SDK pro buildy C++ dává událost, přichází ve formě zásobníku. Poslední položka v zásobníku je aktuální událost a položky před ní jsou nadřazenou hierarchií. Například události spuštění a zastavení LTCG probíhají během průchodu 1 linkeru. V tomto případě zásobník, který byste dostali, obsahuje: [LINKER, PASS1, LTCG]. Nadřazená hierarchie je pohodlná, protože můžete trasovat událost do kořenového adresáře. Pokud je výše uvedená aktivita LTCG pomalá, můžete okamžitě zjistit, které vyvolání linkeru se týká.

Odpovídající události a zásobníky událostí

Sada SDK C++ Build Insights poskytuje každou událost v trasování, ale ve většině případů vám záleží jenom na jejich podmnožině. V některých případech se můžete starat pouze o podmnožinu zásobníků událostí. Sada SDK poskytuje možnosti, které vám pomůžou rychle extrahovat události nebo zásobník událostí, které potřebujete, a odmítnout ty, které nepotřebujete. Provádí se prostřednictvím těchto odpovídajících funkcí:

Function Popis
MatchEvent Pokud odpovídá některému ze zadaných typů, zachovejte událost. Přeposlání odpovídajících událostí na lambda nebo jiný typ volatelný. Nadřazená hierarchie události není touto funkcí považována.
MatchEventInMemberFunction Pokud odpovídá typu zadanému v parametru členské funkce, ponechte událost. Přeposlání odpovídajících událostí členské funkci Nadřazená hierarchie události není touto funkcí považována.
MatchEventStack Pokud událost i nadřazená hierarchie odpovídají zadaným typům, ponechte událost. Přesměrujte událost a odpovídající události nadřazené hierarchie na lambda nebo jiný typ volatelného typu.
MatchEventStackInMemberFunction Pokud událost i nadřazená hierarchie odpovídají typům zadaným v seznamu parametrů členské funkce, ponechte událost. Přeposlání události a odpovídajících nadřazených hierarchických událostí členské funkci.

Odpovídající funkce zásobníku událostí, jako je MatchEventStack například povolit mezery při popisu nadřazené hierarchie, aby se shodovaly. Můžete například říct, že vás zajímá zásobník [LINKER, LTCG]. Také by odpovídal zásobníku [LINKER, PASS1, LTCG]. Poslední zadaný typ musí být typ události, který se má shodovat a není součástí nadřazené hierarchie.

Třídy zachytávání

Match* Použití funkcí vyžaduje, abyste zadali typy, které se mají shodovat. Tyto typy jsou vybrány ze seznamu tříd zachycení. Třídy zachycení mají několik kategorií, které jsou popsané níže.

Kategorie Popis
Přesný Tyto třídy zachycení slouží ke shodě s konkrétním typem události a žádnou jinou. Příkladem je třída kompilátoru, která odpovídá události COMPILER.
Divoká karta Tyto třídy zachytávání se dají použít ke spárování jakékoli události ze seznamu událostí, které podporují. Zástupný znak aktivity například odpovídá události aktivity. Dalším příkladem je zástupný znak CompilerPass , který může odpovídat FRONT_END_PASS nebo události BACK_END_PASS .
Seskupit Názvy tříd zachycení skupin končí ve skupině. Slouží k porovnávání více událostí stejného typu v řádku a ignoruje mezery. Mají smysl jenom při porovnávání rekurzivních událostí, protože nevíte, kolik existuje v zásobníku událostí. Například aktivita FRONT_END_FILE probíhá pokaždé, když kompilátor analyzuje soubor. Tato aktivita je rekurzivní, protože kompilátor může při analýze souboru najít direktivu include. Třída FrontEndFile odpovídá pouze jedné FRONT_END_FILE události v zásobníku. Pomocí třídy FrontEndFileGroup se shoduje s celou hierarchií zahrnutí.
Skupina zástupných znaků Skupina zástupných znaků kombinuje vlastnosti zástupných znaků a skupin. Jedinou třídou této kategorie je InvocationGroup, která odpovídá a zachycuje všechny události LINKER a COMPILER v jediném zásobníku událostí.

V tabulce událostí se dozvíte, které třídy zachytávání se dají použít k porovnání jednotlivých událostí.

Po porovnávání: použití zachycených událostí

Jakmile se shoda úspěšně dokončí, Match* funkce sestaví objekty třídy capture a předají je zadané funkci. Tyto objekty třídy zachycení použijte pro přístup k vlastnostem událostí.

Příklad

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