Поделиться через


Руководство. Устранение влияния файла заголовка на время сборки

Используйте средства Build Insights , включенные в файлы и включить представления дерева , чтобы устранить влияние файлов на время сборки #include C и C++.

Необходимые компоненты

  • Visual Studio 2022 17.8 или более поздней версии.
  • Аналитика сборки C++ включена по умолчанию, если вы устанавливаете рабочую нагрузку C++ с рабочей нагрузкой C++ с помощью установщика Visual Studio:

Снимок экрана: установщик Visual Studio с выбранной рабочей нагрузкой C++ для разработки классических приложений.

Отображается список установленных компонентов. Аналитика сборки C++ выделена и выбрана, что означает, что она установлена.

Или разработка игр с помощью рабочей нагрузки C++:

Снимок экрана: установщик Visual Studio с выбранной рабочей нагрузкой C++.

Отображается список установленных компонентов. Аналитика сборки C++ выделена и выбрана, что означает, что она установлена.

Обзор

Аналитика сборки, интегрированная в Visual Studio, помогает оптимизировать время сборки, особенно для крупных проектов, таких как тройная игра. Если большой файл заголовка анализируется, и особенно при повторном анализе, это влияет на время сборки.

Build Insights предоставляет аналитику в представлении включенных файлов , что помогает диагностировать влияние синтаксического анализа #include файлов в проекте. Отображается время, необходимое для анализа каждого файла заголовка и представления связей между файлами заголовков.

Из этой статьи вы узнаете, как использовать включенные файлы build Insights и включить представления дерева для определения наиболее дорогих файлов заголовков для анализа и оптимизации времени сборки путем создания предварительно скомпилированного файла заголовка.

Задание параметров сборок

Перед сбором данных Build Insights задайте параметры сборки для типа сборки, которую вы хотите измерить. Например, если вы обеспокоены временем сборки отладки x64, задайте сборку для отладки и x64:

  • В раскрывающемся списке "Конфигурации решений" выберите "Отладка".

  • В раскрывающемся списке платформ решений выберите x64.

    Снимок экрана: раскрывающийся список конфигурации решения.

    Отображается раскрывающийся список конфигурации решения. Он имеет параметры отладки, выпуска и Configuration Manager. Раскрывающийся список платформы решений имеет значение x64.

Запуск Аналитики сборки

В выбранном проекте и использовании параметров сборки отладки, заданных в предыдущем разделе, запустите Build Insights, выбрав в главном меню >Build Insights для перестроения выборок.> Вы также можете щелкнуть проект правой кнопкой мыши в обозревателе решений и выбрать команду "Выполнить сборку аналитики".> Выберите "Перестроить", а не "Сборка", чтобы оценить время сборки для всего проекта, а не только для нескольких файлов, которые могут быть грязные прямо сейчас.

Снимок экрана: главное меню с выбранным параметром

После завершения сборки откроется файл журнала трассировки событий (ETL). Он сохраняется в папке, на которую указывает переменная среды Windows TEMP . Созданное имя основано на времени сбора.

Представление включенных файлов

Файл трассировки показывает время сборки, которое для этого примера составило 16,404 секунды. Сеанс диагностики — это общее время выполнения сеанса Build Insights. Перейдите на вкладку "Включенные файлы ".

В этом представлении показано время, затраченное на обработку #include файлов.

Снимок экрана: представление включенных файлов.

В столбце пути к файлу выделено несколько файлов со значком пожара, так как они занимают более 10 % времени сборки для анализа. winrtHeaders.h является самым большим в 8,581 секунд или 52,3% от 16,404-секундного времени сборки.

В столбце "Путь к файлу" некоторые файлы имеют значок огня рядом с ними, чтобы указать, что они занимают 10 % или больше времени сборки.

Столбец Time [sec, %] показывает, сколько времени потребовалось для компиляции каждой функции в время ответственности за стены (WCTR). Эта метрика распределяет время настенные часы, необходимое для анализа файлов на основе их использования параллельных потоков. Например, если два разных потока синтаксического анализа двух разных файлов одновременно в течение одного секунды, wcTR каждого файла записывается как 0,5 секунды. Это отражает пропорциональную долю каждого файла общего времени компиляции, учитывая ресурсы, используемые при параллельном выполнении. Таким образом, WCTR обеспечивает более высокую оценку влияния каждого файла на общее время сборки в средах, где одновременно происходит несколько действий компиляции.

Столбец "Анализ счетчика" показывает, сколько раз был проанализирован файл заголовка.

Первый файл заголовка, выделенный в этом списке, — winrtHeaders.h это 8,581 секунды общей 16,404-секундной сборки или 52,3% времени сборки. Следующий самый дорогой , Windows.UI.Xaml.Interop.hа затем Windows.Xaml.h.

Чтобы увидеть, какой файл включает winrtHeaders.h, щелкните шеврон рядом с ним. Столбец "Анализ счетчика " может быть полезным, указывая, сколько раз файл заголовка включается другими файлами. Возможно, файл заголовка включается несколько раз, что может быть признаком того, что это хороший кандидат для предварительно скомпилированного файла заголовка или рефакторинга.

В столбце единицы перевода показано, какой файл обрабатывается при обработке включенного файла. В этом примере winrtHeaders.h было включено во время Grapher.cpp компиляции:

Снимок экрана: представление включенных файлов.

Пример ETL-файла с файлами включает файлы для примера проекта. В столбце пути к файлу выбран и развернут winrtHeaders.h. Сборка занимает 8,219 секунд, что составляет 50,1 % времени сборки. Его дочерний узел Grapher.cpp, который также указан в качестве единицы перевода".

Столбец единицы перевода может помочь отключать, какой файл компилируется в случаях, когда файл заголовка включается много раз, и вы хотите узнать, где это происходит больше всего.

Мы знаем, что winrtHeaders.h это дорого для синтаксического анализа, но мы можем узнать больше.

Включение представления "Дерево"

В этом представлении дочерние узлы — это файлы, включенные родительским узлом. Это поможет понять связи между файлами заголовков и определить возможности для уменьшения количества файлов заголовков.

Выберите вкладку "Включить дерево " в файле ETL, чтобы просмотреть представление "Включить дерево":

Снимок экрана: представление

Отображает дерево включения проекта. В столбце пути к файлу отображается каждый файл, содержащий другие файлы, а также количество файлов, которые он включает, и время его анализа.

В этом представлении столбец пути к файлу отображает каждый файл, содержащий другие файлы. В списке "Количество включений" перечисляется количество файлов, включаемые в этот файл заголовка. Время анализа этого файла отображается, а при развертывании — время анализа каждого отдельного файла заголовка, включаемого этим файлом заголовка.

Ранее мы видели, что синтаксический анализ winrtHeaders.h занимает много времени. В текстовом поле winrtHeaders.h"Файлы фильтров" можно отфильтровать представление только для записей, содержащихся winrtHeaders.h в имени. Щелкнув шеврон рядом с winrtHeaders.h файлами, которые он включает:

Снимок экрана: развернутое представление

Столбец пути к файлу перечисляет каждый файл, содержащий другие файлы, а также количество файлов, которые он включает, и время, необходимое для анализа. winrtHeaders.h выбран и развернут, чтобы отобразить файлы, которые он включает. Windows.UI.Xaml.Interop.h является одним из этих файлов и развернут, чтобы отобразить windows.UI.Xaml.Interop.h, развернутый для отображения файлов заголовков, которые он включает.

Мы видим, что winrtHeaders.h включает в себя Windows.UI.Xaml.Interop.h. Помните, что в представлении включенных файлов это также занимает много времени для синтаксического анализа. Щелкните шеврон рядом с Windows.UI.Xaml.Interop.h тем, чтобы увидеть, что он включает Windows.UI.Xaml.hв себя 21 других файлов заголовков, два из которых также находятся в горячем списке.

Определив некоторые из самых дорогих файлов заголовков для синтаксического анализа и видя, что winrtHeaders.h они отвечают за их ввод, предполагает, что мы можем использовать предварительно скомпилированные заголовки, чтобы сделать winrtHeaders.h их более быстрым.

Улучшение времени сборки с помощью предварительно скомпилированных заголовков

Так как мы знаем из представления включенных файлов, которое занимает много времени для синтаксического анализа, и потому что мы знаем из представления "Включить дерево", включающее winrtHeaders.h несколько других файлов заголовков, которые требует много времени для синтаксического анализа, мы создадим предварительно скомпилированный файл заголовка (PCH), чтобы ускорить этот процесс, только проанализировав их один раз в PCHwinrtHeaders.h.

Мы добавим к ней winrtHeaders.hследующееpch.h:

#ifndef CALC_PCH
#define CALC_PCH

#include <winrtHeaders.h>

#endif // CALC_PCH

PCH-файлы необходимо скомпилировать перед их использованием, поэтому мы добавим файл в проект произвольно именованным pch.cpp, который включает в себя pch.h. Он содержит одну строку:

#include "pch.h"

Затем мы задали проект для использования PCH. Это сделано в свойствах проекта с помощью предварительно скомпилированных заголовков C/C++>и задания предварительно скомпилированного заголовка для использования (/Yu) и предварительно скомпилированного файла заголовка на pch.h.

Снимок экрана: диалоговое окно свойств проекта с открытыми параметрами предварительно скомпилированных заголовков.

Заголовок с предварительной компиляцией имеет значение: Use (/Yu). Файл предкомпилированного заголовка имеет значение pch.h.

Чтобы использовать PCH, мы включаем ее в первую строку в исходные файлы, которые используют winrtHeaders.h. Он должен поступать перед любыми другими файлами. Кроме того, для простоты можно изменить свойства проекта, чтобы включить pch.h в начало каждого файла в решении, задав свойство проекта: C/C++>Advanced>Include File to: pch.h

Снимок экрана: диалоговое окно свойств проекта с открытыми дополнительными параметрами.

Для файла принудительного включения задано значение pch.h.

Так как PCH включает в себя winrtHeaders.h, мы можем удалить winrtHeaders.h из всех файлов, которые в настоящее время включают его. Это не обязательно, потому что компилятор понимает, что winrtHeaders.h уже включен и не анализирует его снова. Некоторые разработчики предпочитают хранить #include в исходном файле для ясности или в случае, если PCH, скорее всего, будет рефакторинг и может больше не включать этот файл заголовка.

Тестирование изменений

Сначала мы очищаем проект, чтобы убедиться, что мы сравниваем создание одинаковых файлов, как и раньше. Чтобы очистить только один проект, щелкните правой кнопкой мыши проект в Обозреватель решений и выберите "Только очистить проект только<> имя> prj".

Так как этот проект теперь использует предварительно скомпилированные заголовки (PCH), мы не хотим измерять время, затраченное на сборку PCH, так как это происходит только один раз. Для этого нужно загрузить pch.cpp файл и выбрать ctrl+F7 , чтобы создать только этот файл. Этот файл можно также скомпилировать, щелкнув pch.cpp правой кнопкой мыши Обозреватель решений и выбрав Compileего.

Теперь мы повторно запустите Аналитику сборки в Обозреватель решений, щелкнув проект правой кнопкой мыши и выбрав "Только>запуск project Build Insights в сборке". Вы также можете щелкнуть проект правой кнопкой мыши в обозревателе решений и выбрать команду "Выполнить сборку Аналитики сборки>". Мы не хотим перестроить это время, потому что это перестроит PCH, который мы не хотим измерять. Мы очистили проект ранее, что означает, что обычная сборка компилирует все файлы проекта, которые мы хотим измерить.

Когда отображаются файлы ETL, мы видим, что время сборки от 16,404 секунд до 6,615 секунд. Поместите winrtHeaders.h в поле фильтра и ничего не отображается. Это связано с тем, что время, затраченное на синтаксический анализ, теперь незначительно, так как оно извлекается предварительно скомпилированного заголовка.

Снимок экрана: панель

В этом примере используются предварительно скомпилированные заголовки, так как они являются общим решением до C++20. Однако начиная с C++20 существуют другие, более быстрые, менее хрупкие способы включения файлов заголовков, таких как единицы заголовков и модули. Дополнительные сведения см. в статье "Сравнение единиц заголовков, модулей и предварительно скомпилированных заголовков".

Существуют некоторые функции навигации как для включенных файлов, так и для представлений "Включить дерево":

  • Дважды щелкните файл (или нажмите клавишу ВВОД) в включенных файлах или в виде дерева включения, чтобы открыть исходный код для этого файла.
  • Щелкните правой кнопкой мыши файл заголовка, чтобы найти этот файл в другом представлении. Например, в представлении "Включенный файл" щелкните правой кнопкой мыши winrtHeaders.h и выберите "Найти в дереве включения ", чтобы увидеть его в представлении "Дерево включения ".

Снимок экрана: щелкните правой кнопкой мыши файл в представлении включенных файлов. Выделен параметр меню

Вы также можете щелкнуть правой кнопкой мыши файл в представлении "Включить дерево ", чтобы перейти к нему в представлении включенных файлов .

Советы

  • Вы можете >сохранить файл как ETL-файл в более постоянном расположении, чтобы сохранить запись времени сборки. Затем вы можете сравнить его с будущими сборками, чтобы узнать, улучшается ли время сборки.
  • Если вы непреднамеренно закройте окно Build Insights, повторно откройте его, найдя <dateandtime>.etl файл во временной папке. Переменная TEMP среды Windows предоставляет путь к папке временных файлов.
  • Чтобы получить сведения о данных Build Insights с помощью Windows Анализатор производительности (WPA), нажмите кнопку "Открыть в WPA" в правом нижнем углу окна ETL.
  • Перетащите столбцы, чтобы изменить порядок столбцов. Например, вы можете предпочесть перемещение столбца Time в первый столбец. Вы можете скрыть столбцы, щелкнув правой кнопкой мыши заголовок столбца и отменив выбор столбцов, которые вы не хотите видеть.
  • Включенные файлы и представления дерева включают в себя поле фильтра, чтобы найти нужный файл заголовка. Он выполняет частичные совпадения по указанному имени.
  • Иногда время синтаксического анализа, сообщаемое для файла заголовка, отличается в зависимости от того, какой файл включает его. Это может быть связано с взаимодействием различных #defines, влияющих на то, какие части заголовка развернуты, кэширование файлов и другие системные факторы.
  • Если вы забыли, что показывает представление "Включенные файлы " или "Включить в дерево ", наведите указатель мыши на вкладку, чтобы увидеть подсказку, описывающую представление. Например, если наведите указатель мыши на вкладку "Включить дерево ", подсказка говорит: "Представление, включающее статистику для каждого файла, в котором дочерние узлы являются файлами, включенными родительским узлом".
  • Вы можете увидеть случаи (например Windows.h), когда агрегированная длительность всех времен для файла заголовка превышает продолжительность всей сборки. Что происходит, заключается в том, что заголовки анализируются в нескольких потоках одновременно. Если два потока одновременно проводят один второй анализ файла заголовка, то это 2 секунды времени сборки, хотя только одна секунда времени на стены часы прошла. Дополнительные сведения см. в разделе "Время ответственности за стены" (WCTR).

Устранение неполадок

  • Если окно "Аналитика сборки" не отображается, выполните перестроение вместо сборки. Окно "Аналитика сборки" не отображается, если ничего на самом деле не выполняется; это может быть так, если файлы не изменились с момента последней сборки.
  • Если нужный файл заголовка не отображается в представлениях "Включенные файлы " или "Включить дерево ", он либо не выполняет сборку, либо время сборки не достаточно важно для перечисления.

См. также

Сравнение единиц заголовков, модулей и предварительно скомпилированных заголовков
Создание аналитики в видео Visual Studio — Pure Virtual C++ 2023
Просто об ускорении сборок C++: новая метрика времени
Руководство. Устранение неполадок с функцией встраивание во время сборки
Руководство. Средство vcperf и Windows Performance Analyzer