Partager via


Didacticiel : Résoudre les problèmes d’impact du fichier d’en-tête sur le temps de génération

Utilisez les affichages Fichiers inclus et Arborescence Include de Build Insights pour réduire l’impact des fichiers #include sur les temps de génération C et C++.

Prérequis

  • Visual Studio 2022 17.8 ou ultérieur.
  • C++ Build Insights est activé par défaut si vous installez le développement Desktop avec la charge de travail C++ à l’aide du programme d’installation de Visual Studio :

Capture d’écran de Visual Studio Installer avec le développement Desktop avec la charge de travail C++ sélectionné.

La liste des composants installés est affichée. C++ Build Insights est mis en surbrillance et sélectionné, ce qui signifie qu’il est installé.

Ou le développement de jeux avec la charge de travail C++ :

Capture d’écran de Visual Studio Installer avec le développement de jeux et la charge de travail C++ sélectionnée.

La liste des composants installés est affichée. C++ Build Insights est mis en surbrillance et sélectionné, ce qui signifie qu’il est installé.

Vue d’ensemble

Build Insights, désormais intégré à Visual Studio, vous permet d’optimiser vos temps de génération, en particulier pour les grands projets tels que les jeux AAA. Lorsqu’un fichier d’en-tête volumineux est analysé, et surtout lorsqu’il est analysé à plusieurs reprises, le temps de génération est impacté.

Build Insights fournit des analyses dans l’affichage Fichiers inclus, ce qui permet de diagnostiquer l’impact de l’analyse des fichiers #include dans votre projet. Il affiche le temps nécessaire pour analyser chaque fichier d’en-tête et une vue des relations entre les fichiers d’en-tête.

Dans cet article, découvrez comment utiliser les affichages Fichiers inclus et Arborescence Include de Build Insights pour identifier les fichiers d’en-tête les plus coûteux à analyser et comment optimiser le temps de génération en créant un fichier d’en-tête précompilé.

Définition des options de génération

Avant de collecter des données Build Insights, définissez les options de génération pour le type de build que vous souhaitez mesurer. Par exemple, si vous vous inquiétez du temps de génération de débogage x64, définissez Déboguer pour la build et x64 :

  • Dans la liste déroulante Configurations de solution, choisissez Déboguer.

  • Dans la liste déroulante Plateformes de solutions, choisissez x64.

    Capture d’écran de la liste déroulante Configuration de la solution.

    La liste déroulante Configuration de la solution s’affiche. Elle présente les options Déboguer, Libérer et Gestionnaire de configuration. La liste déroulante Plateforme de solutions est définie sur x64.

Exécuter Build Insights

Dans un projet de votre choix et à l’aide des options de débogage définies dans la section précédente, exécutez Build Insights en choisissant dans le menu principal Générer>Exécuter Build Insights sur la sélection>Regénérer. Vous pouvez également cliquer avec le bouton droit sur un projet dans l’explorateur de solutions et choisir Exécuter Build Insights>Regénérer. Choisissez Regénérer au lieu de Générer pour mesurer le temps de génération de l’ensemble du projet, pas seulement pour les quelques fichiers qui pourraient être corrompus en ce moment.

Capture d’écran du menu principal avec Exécuter Build Insights sur la sélection > Regénérer sélectionné.

Une fois la génération est terminée, un fichier ETL (Event Trace Log) s’ouvre. Il est enregistré dans le dossier vers lequel pointe la variable d’environnement TEMP Windows. Le nom généré est basé sur l’heure de collecte.

Affichage Fichiers inclus

Le fichier de trace affiche l’heure de génération, qui était de 16,404 secondes pour cet exemple. La session diagnostics représente le temps global nécessaire pour exécuter la session Build Insights. Choisissez l’onglet Fichiers inclus.

Cet affichage montre le temps passé à traiter les fichiers #include.

Capture d’écran de l’affichage Fichiers inclus.

Dans la colonne Chemin d’accès au fichier, plusieurs fichiers avec une icône de flamme sont mis en surbrillance, car ils prennent plus de 10 % du temps de génération pour l’analyse. winrtHeaders.h est le plus grand avec 8,581 secondes soit 52,3 % du temps de génération de 16,404 secondes.

Dans la colonne Chemin d’accès au fichier, certains fichiers présentent une icône de flamme pour indiquer qu’ils prennent jusqu’à 10 % ou plus du temps de génération.

La colonne Temps [sec, %] indique le temps nécessaire pour compiler chaque fonction en Temps de responsabilité de temps réel (WCTR). Cette métrique distribue le temps nécessaire pour analyser les fichiers en fonction de leur utilisation de threads parallèles. Par exemple, si deux threads différents analysent deux fichiers différents simultanément dans un délai d’une seconde, le WCTR de chaque fichier est enregistré sous la forme de 0,5 seconde. Cela reflète la part proportionnelle de chaque fichier vis-à-vis du temps de compilation total, en tenant compte des ressources consommées chaque fois pendant l’exécution parallèle. Ainsi, WCTR fournit une meilleure mesure de l’impact que chaque fichier a sur le temps de génération global dans les environnements où plusieurs activités de compilation se produisent simultanément.

La colonne Nombre d’analyses indique le nombre d’analyses du fichier d’en-tête.

Le premier fichier d’en-tête mis en surbrillance dans cette liste est winrtHeaders.h Il lui faut 8,581 secondes du temps de génération global de 16,404 secondes, soit 52,3 %. Le deuxième plus coûteux est Windows.UI.Xaml.Interop.h, puis Windows.Xaml.h.

Pour voir quel fichier inclut winrtHeaders.h, cliquez sur le chevron en regard de celui-ci. La colonne Nombre d’analyses peut être utile en pointant le nombre de fois où un fichier d’en-tête est inclus par d’autres fichiers. Peut-être qu’un fichier d’en-tête est inclus plusieurs fois, ce qui peut faire de lui un bon candidat pour un fichier d’en-tête précompilé ou une refactorisation.

La colonne Unité de traduction indique le fichier en cours de traitement lorsque le fichier inclus a été traité. Dans cet exemple, winrtHeaders.h a été inclus pendant la compilation de Grapher.cpp :

Capture d’écran de l’affichage Fichiers inclus.

Exemple de fichier ETL montrant les fichiers inclus pour un exemple de projet. Dans la colonne Chemin d’accès au fichier, winrtHeaders.h est sélectionné et développé. La génération prend 8,219 secondes, soit 50,1 % du temps de génération. Son nœud enfant est Grapher.cpp, qui est également répertorié comme unité de traduction. »

La colonne d’unité de traduction peut aider à clarifier le fichier qui a été compilé dans les cas où un fichier d’en-tête est inclus plusieurs fois et que vous souhaitez savoir où cela se produit le plus.

Nous savons que winrtHeaders.h est coûteux à analyser, mais nous pouvons en savoir plus.

Affichage Arborescence Include

Dans cet affichage, les nœuds enfants sont les fichiers inclus par le nœud parent. Cela peut vous aider à comprendre les relations entre les fichiers d’en-tête, et à identifier les opportunités de réduction du nombre de fois où un fichier d’en-tête est analysé.

Sélectionnez l’onglet Arborescence Include dans le fichier ETL pour afficher l’arborescence Include :

Capture d’écran de l’affichage Arborescence Include.

Affiche l’arborescence Include d’un projet. Dans la colonne Chemin d’accès au fichier, chaque fichier qui inclut d’autres fichiers est répertorié, ainsi que le nombre de fichiers qu’il inclut et le temps d’analyse.

Dans cet affichage, la colonne Chemin d’accès au fichier affiche chaque fichier qui inclut d’autres fichiers. Le Nombre d’inclusions répertorie le nombre de fichiers inclus dans ce fichier d’en-tête. Le temps d’analyse de ce fichier est répertorié et une fois développé, il répertorie le temps d’analyse de chaque fichier d’en-tête individuel inclus dans ce fichier d’en-tête.

Plus tôt, nous avons constaté que l’analyse de winrtHeaders.h prenait du temps. Dans la zone de texte Filtrer les fichiers, si nous entrez winrtHeaders.h, vous pouvez filtrer l’affichage uniquement sur les entrées contenant winrtHeaders.h dans leur nom. Cliquez sur le chevron en regard de winrtHeaders.h pour voir les fichiers qu’il contient :

Capture d’écran de l’arborescence Include développée.

La colonne Chemin d’accès au fichier répertorie chaque fichier qui inclut d’autres fichiers, ainsi que le nombre de fichiers qu’il inclut et le temps nécessaire pour l’analyser. winrtHeaders.h est sélectionné et développé pour afficher les fichiers qu’il inclut. Windows.UI.Xaml.Interop.h est l’un de ces fichiers et est développé pour afficher Windows.UI.Xaml.Interop.h, qui est développé pour afficher les fichiers d’en-tête qu’il inclut.

On peut constater que winrtHeaders.h inclut Windows.UI.Xaml.Interop.h. N’oubliez pas que dans l’affichage Fichiers inclus, son analyse prenait également du temps. Cliquez sur le chevron en regard de Windows.UI.Xaml.Interop.h pour voir qu’il inclut Windows.UI.Xaml.h, qui lui-même inclut 21 autres fichiers d’en-tête, dont deux sont également dans la liste à chaud.

Après avoir identifié les fichiers dont l’analyse est la plus coûteuse, et après avoir vu que winrtHeaders.h est responsable de leur mise en place, la solution peut être d’utiliser un en-tête précompilé pour accélérer l’inclusion de winrtHeaders.h.

Améliorer le temps de génération avec des en-têtes précompilés

Puisque nous savons grâce à l’affichage Fichiers inclus que l’analyse de winrtHeaders.h prend beaucoup de temps, et grâce à l’affichage Arborescence Include, que winrtHeaders.h inclut plusieurs autres fichiers d’en-tête dont l’analyse prend aussi beaucoup de temps, nous générons un fichier d’en-tête précompilé (PCH) pour accélérer cette vitesse en les analysant simplement une seule fois dans un PCH.

Nous ajoutons un pch.h pour inclure winrtHeaders.h, ce qui ressemblerait à ceci :

#ifndef CALC_PCH
#define CALC_PCH

#include <winrtHeaders.h>

#endif // CALC_PCH

Les fichiers PCH doivent être compilés avant de pouvoir être utilisés. Nous ajoutons donc un fichier au projet, nommé arbitrairement pch.cpp, qui inclut pch.h. Il contient une ligne :

#include "pch.h"

Ensuite, nous définissons notre projet pour utiliser le PCH. Cela s’effectue dans les propriétés du projet via C/C++>En-têtes précompilés et en définissant En-tête précompilé sur Utilisation (/Yu) et Fichier d’en-tête précompilé sur pch.h.

Capture d’écran de la boîte de dialogue des propriétés du projet avec les paramètres d’en-têtes précompilés ouverts.

L’en-tête précompilé est défini sur : Utilisation (/Yu). Le fichier d’en-tête précompilé est défini sur pch.h.

Pour utiliser le PCH, nous l’incluons comme première ligne dans les fichiers sources qui utilisent winrtHeaders.h. Il doit arriver avant tout autre fichier Include. Ou, par souci de simplicité, nous pourrions également modifier les propriétés du projet pour inclure pch.h au début de chaque fichier de la solution en définissant la propriété du projet : C/C++>Avancé>Fichier Include imposé sur pch.h :

Capture d’écran de la boîte de dialogue Propriétés du projet avec les paramètres avancés ouverts.

Le fichier Include imposé est défini sur pch.h.

Étant donné que le PCH inclut winrtHeaders.h, nous pourrions supprimer winrtHeaders.h de tous les fichiers qui l’incluent actuellement. Ce n’est pas absolument nécessaire, car le compilateur réalise que winrtHeaders.h est déjà inclus et ne le réanalyse pas. Certains développeurs préfèrent conserver le #include dans le fichier source pour plus de clarté, ou si le PCH est susceptible d’être refactorisé et peut ne plus inclure ce fichier d’en-tête.

Tester les modifications

Nous allons d’abord nettoyer le projet pour nous assurer que nous comparons les mêmes fichiers que précédemment. Pour nettoyer un seul projet, cliquez avec le bouton droit sur le projet dans l’explorateur de solutions et choisissez Projet uniquement>Nettoyer uniquement <Nom prj>.

Étant donné que ce projet utilise maintenant un en-tête précompilé (PCH), nous n’avons pas à mesurer le temps passé à créer le PCH, car cela ne se produit qu’une seule fois. Pour ce faire, chargez le fichier pch.cpp et choisissez Ctrl+F7 pour générer uniquement ce fichier. Nous pouvons également compiler ce fichier en cliquant avec le bouton droit sur pch.cpp dans l’explorateur de solutions et en choisissant Compile.

À présent, nous réexécutons Build Insights dans l’explorateur de solutions en cliquant avec le bouton droit sur le projet et en choisissant Projet uniquement>Exécuter Build Insights sur la build. Vous pouvez également cliquer avec le bouton droit sur un projet dans l’explorateur de solutions et choisir Exécuter Build Insights>Générer. Cette fois-ci, nous ne voulons pas regénérer, car cela regénérera le PCH, que nous ne voulons pas mesurer. Nous avons nettoyé le projet précédemment, ce qui signifie qu’une build normale compile tous les fichiers de projet que nous voulons mesurer.

Lorsque les fichiers ETL apparaissent, on constate que le temps de génération est passé de 16,404 secondes à 6,615 secondes. Si vous placez winrtHeaders.h dans la zone de filtre, rien n’apparaît. Cela est dû au fait que le temps passé à l’analyse est maintenant négligeable, car il est extrait par l’en-tête précompilé.

Capture d’écran du volet Arborescence Include dans le fichier de trace. winrtHeaders n’est plus répertorié.

Cet exemple utilise des en-têtes précompilés, car ils représente une solution courante avant C++20. Toutefois, à partir de C++20, il existe d’autres méthodes plus rapides et moins fragiles permettant d’inclure des fichiers d’en-tête, tels que des unités d’en-tête et des modules. Pour plus d’informations, consultez Comparer les unités d’en-tête, les modules et les en-têtes précompilés.

Il existe certaines fonctionnalités de navigation pour les affichages Fichiers inclus et Arborescence Include :

  • Double-cliquez sur un fichier (ou appuyez sur Entrée) dans Fichiers inclus ou dans Arborescence Include pour ouvrir le code source de ce fichier.
  • Cliquez avec le bouton droit sur un fichier d’en-tête pour trouver ce fichier dans l’autre affichage. Par exemple, dans l’affichage Fichier inclus, cliquez avec le bouton droit sur winrtHeaders.h et choisissez Rechercher dans Arborescence Include pour le voir dans l’affichage Arborescence Include.

Capture d’écran d’un clic droit sur un fichier dans l’affichage Fichiers inclus. L’option de menu Afficher dans Arborescence Include est mise en surbrillance.

Vous pouvez également cliquer avec le bouton droit sur un fichier dans l’affichage Arborescence Include pour y accéder dans l’affichage Fichiers inclus.

Conseils

  • Vous pouvez enregistrer le fichier ETL dans un emplacement plus permanent via Fichier>Enregistrer sous pour conserver un enregistrement de l’heure de génération. Vous pouvez ensuite la comparer aux futures builds pour voir si vos modifications améliorent le temps de génération.
  • Si vous fermez par inadvertance la fenêtre Build Insights, rouvrez-la en recherchant le fichier <dateandtime>.etl dans votre dossier temporaire. La variable d’environnement TEMP Windows fournit le chemin d’accès à votre dossier de fichiers temporaires.
  • Pour explorer les données Build Insights avec Windows Performance Analyzer (WPA), cliquez sur le bouton Ouvrir dans WPA en bas à droite de la fenêtre ETL.
  • Faites glisser des colonnes pour modifier leur ordre. Par exemple, vous préférerez peut-être placer la colonne Heure en première. Vous pouvez masquer les colonnes en cliquant avec le bouton droit sur l’en-tête de la colonne et en désélectionnant les colonnes que vous ne souhaitez pas voir.
  • Les affichages Fichiers inclus et Arborescence Include fournissent une zone de filtre pour rechercher un fichier d’en-tête qui vous intéresse. Elle effectue des correspondances partielles sur le nom que vous fournissez.
  • Parfois, l’heure d’analyse signalée pour un fichier d’en-tête est différente selon le fichier qui l’inclut. Cela peut être dû à l’interaction de différents #define qui affectent les parties de l’en-tête qui sont développées, la mise en cache des fichiers et d’autres facteurs système.
  • Si vous oubliez ce que les affichages Fichiers inclus ou Arborescence Include veulent vous montrer, pointez sur l’onglet pour afficher une info-bulle qui décrit l’affichage. Par exemple, si vous pointez sur l’onglet Arborescence Include, l’info-bulle indique : « Affiche les statistiques Include pour chaque fichier où les nœuds enfants sont les fichiers inclus par le nœud parent ».
  • Dans certains cas, (comme pour Windows.h), la durée agrégée de toutes les fois pour un fichier d’en-tête est supérieure à la durée de la build entière. Ce qui se passe, c’est que les en-têtes sont analysés sur plusieurs threads en même temps. Si deux threads passent simultanément une seconde à analyser un fichier d’en-tête, cela revient à 2 secondes de temps de génération, même si une seule seconde de temps réel s’est écoulée. Pour plus d’informations, consultez Temps de responsabilité de temps réel (WCTR).

Dépannage

  • Si la fenêtre Build Insights n’apparaît pas, effectuez une reconstruction au lieu d’une build. La fenêtre Build Insights n’apparaît pas si rien ne se génère réellement, ce qui peut être le cas si aucun fichier n’a changé depuis la dernière build.
  • Si un fichier d’en-tête qui vous intéresse n’apparaît pas dans l’affichage Fichiers inclus ou Arborescence Include, il n’a pas été généré ou son temps de génération n’est pas suffisamment significatif pour être répertorié.

Voir aussi

Comparer les unités d’en-tête, les modules et les en-têtes précompilés
Vidéo Générer des insights dans Visual Studio – Pure Virtual C++ 2023
Builds C++ accélérées et simplifiées : une nouvelle métrique de temps
Didacticiel : Résoudre les problèmes de fonctions inline lors du temps de génération
Didacticiel : vcperf et Windows Performance Analyzer