Пакет SDK для C++ Build Insights
Пакет SDK для Сборки C++ совместим с Visual Studio 2017 и более поздними версиями. Чтобы увидеть документацию для этих версий, установите в данной статье селектор Версия Visual Studio в Visual Studio 2017 и более поздних версий. Он находится в верхней части оглавления на этой странице.
Пакет SDK Аналитики сборок C++ — это набор API-интерфейсов, позволяющих создавать персонализированные средства на основе платформы Аналитики сборок C++. На этой странице представлены общие сведения, необходимые на начальном этапе работы.
Получение пакета SDK
Пакет SDK Аналитики сборок C++ можно скачать в виде пакета NuGet, выполнив следующие действия:
- Откройте Visual Studio 2017 или новее и создайте проект C++.
- В области Обозревателя решений щелкните правой кнопкой мыши свой проект.
- В контекстном меню выберите Управление пакетами NuGet.
- В правом верхнем углу выберите источник пакета nuget.org.
- Найдите последнюю версию пакета Microsoft.Cpp.BuildInsights.
- Выберите Установить.
- Примите условия лицензии.
Ознакомьтесь с информацией об общих понятиях, связанных с пакетом SDK. Вы также можете получить доступ к официальному репозиторию GitHub с примерами Аналитики сборок C++, чтобы просмотреть примеры реальных приложений C++, использующих пакет SDK.
Сбор данных трассировки
Для анализа событий, исходящих из цепочки инструментов MSVC, с помощью пакета SDK Аналитики сборок C++, сначала необходимо собрать данные трассировки. Пакет SDK использует функцию трассировки событий Windows (ETW) в качестве базовой технологии трассировки. Сбор данных трассировки можно выполнить двумя способами:
Метод 1. Использование vcperf в Visual Studio 2019 и более поздних версий
Откройте командную строку Native Tools x64 с повышенными привилегиями для VS 2019.
Выполните следующую команду:
vcperf /start MySessionName
Выполните сборку проекта.
Выполните следующую команду:
vcperf /stopnoanalyze MySessionName outputTraceFile.etl
Внимание
При остановке трассировки с помощью vcperf используйте команду
/stopnoanalyze
. Пакет SDK Аналитики сборок C++ нельзя использовать для анализа трассировок, остановленных с помощью обычной команды/stop
.
Метод 2. Программный способ
Используйте любую из этих функций сбора данных трассировки пакета SDK Аналитики сборок C++, чтобы программно запускать и останавливать трассировки. Для программы, выполняющей эти вызовы функций, необходимы права администратора. Права администратора требуются только для функций запуска и остановки трассировки. Все остальные функции пакета SDK Аналитики сборок C++ можно выполнять без них.
Функции пакета SDK, связанные со сбором данных трассировки
Функция | API C++ | API C |
---|---|---|
Запуск трассировки | StartTracingSession | StartTracingSessionA StartTracingSessionW |
Остановка трассировки | StopTracingSession | StopTracingSessionA StopTracingSessionW |
Остановка трассировки и немедленный анализ результата |
StopAndAnalyzeTracingSession | StopAndAnalyzeTracingSessionA StopAndAnalyzeTracingSession |
Остановка трассировки и немедленная перерегистрация результата |
StopAndRelogTracingSession | StopAndRelogTracingSessionA StopAndRelogTracingSessionW |
В следующих разделах показано, как настроить анализ или сеанс перерегистрации. Это необходимо для функций объединенных возможностей, таких как StopAndAnalyzeTracingSession.
Использование трассировки
После выполнения трассировки ETW для распаковки используйте пакет SDK Аналитики сборок C++. Пакет SDK предоставляет события в формате, который позволяет быстро разрабатывать средства. Не рекомендуется использовать необработанные данные трассировки ETW без использования пакета SDK. Формат событий, используемый MSVC, не документирован и оптимизирован для увеличения масштаба до огромных сборок. Он сложен в использовании. Кроме того, API пакета SDK Аналитики сборок C++ является стабильным, в то время как необработанный формат трассировки ETW может быть изменен без предварительного уведомления.
Типы и функции пакета SDK, связанные с использованием данных трассировки
Функция | API C++ | API C | Примечания. |
---|---|---|---|
Настройка обратных вызовов событий | IAnalyzer IRelogger |
ANALYSIS_CALLBACKS RELOG_CALLBACKS |
Пакет SDK Аналитики сборки C++ предоставляет события с помощью функций обратного вызова. При использовании C ++ реализуйте функции обратного вызова, создав класс анализатора или перерегистрации, который наследует интерфейс IAnalyzer или IRelogger. При использовании C реализуйте обратные вызовы в глобальных функциях и предоставьте указатели на них в структуре ANALYSIS_CALLBACKS или RELOG_CALLBACKS. |
Создание групп | MakeStaticAnalyzerGroup MakeStaticReloggerGroup MakeDynamicAnalyzerGroup MakeDynamicReloggerGroup |
API C++ предоставляет вспомогательные функции и типы для группирования нескольких анализаторов и объектов перерегистрации. Группы — это прямой путь к разделению сложного анализа на более простые этапы. Таким образом работает vcperf. | |
Анализ или перерегистрация | Анализ Relog |
Анализ АнализW RelogA RelogW |
Анализ и перерегистрация
Использование данных трассировки выполняется либо в сеансе анализа, либо в сеансе перерегистрации.
Использование обычного анализа подходит для большинства сценариев. Этот метод предоставляет гибкие возможности для выбора формата выходных данных: текст printf
, XML, JSON, база данных, вызовы REST и т. д.
Перерегистрация предназначена для анализа специальных целей, требующих создания выходного файла ETW. С помощью перерегистрации можно преобразовать события Аналитики сборок C++ в собственный формат событий ETW. Надлежащим использованием перерегистрации является привязка данных Аналитики сборок C++ к имеющимся средствам и инфраструктуре ETW. Например, vcperf использует интерфейсы перерегистрации. Это обусловлено тем, что это средство должно создавать данные, которые может понять Windows Performance Analyzer, средство ETW. Если вы планируете использовать интерфейсы перерегистрации, вам необходимо иметь представление о функционировании ETW.
Создание групп анализаторов
Сведения о создании групп очень важны. Ниже приведен пример, показывающий, как создать группу анализаторов , которая выводит Hello, world! для каждого события запуска действия, которое он получает.
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;
}
Использование событий
Типы и функции пакета SDK, связанные с событиями
Действия и простые события
Существует две категории событий: действия и простые события. Действия — это текущие процессы, имеющие начало и конец. Простые события являются мгновенными вхождениями и не имеют длительности. При анализе трассировок MSVC с помощью пакета SDK Аналитики сборок C++ вы получаете отдельные события для запуска и остановки действия. В случае простого события вы получите лишь одно событие.
Родительско-дочерние связи
Между действиями и простыми событиями существуют родительско-дочерние связи. Родительским элементом действия или простого события является комплексная операция, во время выполнения которой они возникают. Например, при компиляции исходного файла компилятор должен проанализировать файл, а затем создать код. Действия анализа и создания кода являются дочерними элементами операции компилятора.
Простые события не имеют длительности, поэтому во время их выполнения ничего не может произойти. Таким образом, они никогда не имеют дочерних элементов.
Родительско-дочерние связи для каждого действия и простого события указаны в таблице событий. Знание этих связей важно при использовании событий Аналитики сборок C++. Часто оно необходимо для понимания полного контекста события.
Свойства
Все события имеют следующие свойства:
Свойство | Description |
---|---|
Идентификатор типа | Код, который уникально идентифицирует тип события. |
Идентификатор экземпляра | Код, который уникально идентифицирует событие в трассировке. Если в трассировке встречаются два события одного типа, то они получают уникальный идентификатор экземпляра. |
Время запуска | Время начала действия или время возникновения простого события. |
Идентификатор процесса | Код, который идентифицирует процесс, в котором возникло текущее событие. |
Идентификатор потока | Код, который идентифицирует поток, в котором возникло текущее событие. |
Индекс процессора | Указатель, начинающийся с нуля, который указывает на логический процессор, в котором было создано событие. |
Имя события | Строка с описанием типа события. |
Все действия, кроме простых событий, также имеют следующие свойства:
Свойство | Description |
---|---|
Время остановки | Время, когда было остановлено действие. |
Исключительная длительность | Время, затраченное на действие, без учета времени, затраченного на выполнение его дочерних действий. |
Время ЦП | Время, затраченное ЦП на выполнение кода в потоке, присоединенном к действию. Не включает время пребывания в спящем режиме потока, присоединенного к действию. |
Эксклюзивное время ЦП | То же, что и время ЦП, но без учета времени ЦП, потраченного на выполнение дочерних действий. |
Время выполнения по часам | Вклад действия в общее время выполнения по часам. В реальном времени выполнения учитывается параллелизм при выполнении действий. Например, предположим, что два несвязанных действия выполняются параллельно. Длительность обоих составляет 10 секунд и точно такое же время начала и окончания. В этом случае Аналитика сборок присвоит обоим процессам значение 5 тактов времени по часам. В противоположность этому, если эти действия выполняются друг за другом (не параллельно), им назначается значение 10 тактов времени по часам. |
Исключительное время выполнения по часам | Это то же самое, что и время выполнения по часам, но без учета времени выполнения дочерних действий по часам. |
Некоторые события имеют собственные свойства, которые не упомянуты здесь. Эти дополнительные свойства перечислены в таблице событий.
Использование событий, предоставленных пакетом SDK Аналитики сборок C++
Стек событий
Каждый раз, когда пакет SDK Аналитики сборок C++ предоставляет событие, оно поступает в виде стека. Последняя запись в стеке — это текущее событие, а записи до этого — родительская иерархия. Например, события запуска и завершение LTCG происходят во время 1-го прохода компоновщика. В этом случае полученный стек содержит :[LINKER, PASS1, LTCG]. Родительская иерархия удобна, так как вы можете отследить событие до его корневого элемента. Если указанное выше действие LTCG работает медленно, можно сразу узнать, какой вызов компоновщика был задействован.
Сопоставление событий и стеков событий
Пакет SDK Аналитики сборок C++ предоставляет каждое событие в трассировке, но в большинстве случаев вам нужно только их подмножество. В некоторых случаях может потребоваться только подмножество стеков событий. Пакет SDK предоставляет средства, помогающие быстро извлечь нужные события или стек событий, а также отклонить ненужные. Это можно сделать с помощью этих подходящих функций:
Function | Description |
---|---|
MatchEvent | Сохраняет событие, если оно соответствует одному из указанных типов. Переадресовывает сопоставленные события в лямбда или другие вызываемые типы. Эта функция не учитывает родительскую иерархию события. |
MatchEventInMemberFunction | Сохраняет событие, если оно соответствует типу, указанному в параметре функции-члена. Переадресовывает сопоставленные события в функцию-член. Эта функция не учитывает родительскую иерархию события. |
MatchEventStack | Сохраняет событие, если и событие, и его родительская иерархия соответствуют указанным типам. Переадресовывает событие и сопоставленные события родительской иерархии в лямбда или другие вызываемые типы. |
MatchEventStackInMemberFunction | Сохраняет событие, если и событие, и его родительская иерархия соответствуют типам, указанным в списке параметров функции-члена. Переадресовывает событие и сопоставленные события родительской иерархии в функцию-член. |
Подходящие функции стека событий, такие как MatchEventStack
, допускают пропуски при описании родительской иерархии для сопоставления. Например, вы можете сказать, что заинтересованы в стеке [LINKER, LTCG]. Он также соответствует стеку [LINKER, PASS1, LTCG]. Последний указанный тип должен быть типом события для сопоставления. Он не является частью родительской иерархии.
Классы фиксации
Для использования функций Match*
необходимо указать типы для сопоставления. Эти типы выбираются из списка классов записи. Классы записи могут иметь несколько категорий, которые описаны ниже.
Категория | Description |
---|---|
Точно | Эти классы записи используются только для сопоставления определенного типа событий. Примером является класс Compiler, который соответствует событию COMPILER. |
Подстановочный знак | Эти классы записи можно использовать для сопоставления любого события из списка поддерживаемых ими событий. Например, подстановочный знак Activity соответствует любому событию действия. Еще один пример — подстановочный знак CompilerPass, который может соответствовать FRONT_END_PASS или BACK_END_PASS. |
Групповой | В конце имен классов групповой записи указано Group. Они используются для сопоставления нескольких событий одного типа в строке без учета пропусков. Они имеют смысл только при сопоставлении рекурсивных событий, так как их количество в стеке событий неизвестно. Например, действие FRONT_END_FILE происходит каждый раз, когда компилятор анализирует файл. Это действие является рекурсивным, так как компилятор может найти директиву include при анализе файла. Класс FrontEndFile соответствует только одному событию FRONT_END_FILE в стеке. Используйте класс FrontEndFileGroup для сопоставления всей иерархии include. |
Группа подстановочных знаков | Группа подстановочных знаков объединяет свойства подстановочных знаков и групп. Единственным классом этой категории является InvocationGroup, который сопоставляет и записывает все события LINKER и COMPILER в одном стеке событий. |
Сведения о том, какие классы захвата можно использовать для сопоставления каждого события, см. в таблице событий.
После сопоставления: использование записанных событий
После успешного завершения сопоставления функции Match*
создают объекты класса capture и пересылают их в указанную функцию. Используйте эти объекты класса capture для доступа к свойствам событий.
Пример
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;
}
}