Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Résolvez les problèmes liés à l’impact de l’incorporation de fonctions sur le temps de build dans vos projets C++ à l’aide de la vue Fonctions de Build Insights.
Conditions préalables
- Visual Studio 2022 17.8 ou version ultérieure.
- C++ Build Insights est activé par défaut si vous installez le développement Desktop avec la charge de travail C++ ou le développement de jeux avec la charge de travail C++.
La liste des composants installés s’affiche. C++ Build Insights est mis en surbrillance et sélectionné, ce qui signifie qu’il est installé.
La liste des composants installés s’affiche. 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 build, en particulier pour les grands projets tels que les jeux AAA. Build Insights fournit des analyses telles que la vue Fonctions, ce qui permet de diagnostiquer la génération de code coûteuse durant le temps de build. Il affiche le temps nécessaire pour générer du code pour chaque fonction et l’impact de __forceinline.
La directive __forceinline indique au compilateur d’incorporer une fonction, quelle que soit sa taille ou sa complexité. L’incorporation d’une fonction peut améliorer les performances du runtime en réduisant la surcharge liée à l’appel de la fonction. Le compromis est que cela peut augmenter la taille du binaire et impacter vos temps de build.
Pour les builds optimisées, le temps passé à générer du code contribue considérablement au temps de build total. En général, l’optimisation des fonctions C++ se produit rapidement. Dans certains cas exceptionnels, des fonctions peuvent devenir suffisamment volumineuses et complexes pour faire pression sur l’optimiseur et ralentir considérablement vos builds.
Dans cet article, découvrez comment rechercher des goulots d’étranglement liés à l’incorporation dans votre build à l’aide de la vue Fonctions de Build Insights.
Définir des options de build
Mesurez les résultats de __forceinline à l’aide d’une build Mise en production, car les builds de débogage n’incorporent pas __forceinline puisqu’elles utilisent le commutateur de compilateur /Ob0, ce qui désactive cette optimisation. Définir la build pour Mise en production et x64 :
- Dans la liste déroulante Configurations de solution, choisissez Mise en production.
- Dans la liste déroulante Plateformes de solution, choisissez x64.
Définissez le niveau d’optimisation sur les optimisations maximales :
Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet et sélectionnez Propriétés.
Dans les propriétés du projet, accédez à C/C++>Optimisation.
Définissez la liste déroulante Optimisation sur Optimisation maximale (favoriser la vitesse) (
/O2).
Cliquez sur OK pour fermer la boîte de dialogue.
Exécuter Build Insights
Dans un projet de votre choix et à l’aide des options de build Mise en production définies dans la section précédente, exécutez Build Insights en choisissant dans le menu principal Build>Exécuter Build Insights lors de la sélection>Rebuild. Vous pouvez également cliquer avec le bouton droit sur un projet dans l’Explorateur de solutions et choisir Exécuter Build Insights>Rebuild. Choisissez Reconstruire au lieu de Générer pour mesurer le temps de génération de l’ensemble du projet et non pour les quelques fichiers qui peuvent être sales pour le moment.
Une fois la build 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.
Vus Fonctions
Dans la fenêtre du fichier ETL, cliquez sur l’onglet Fonctions. Il affiche les fonctions compilées et le temps nécessaire pour générer le code pour chaque fonction. Si la quantité de code générée pour une fonction est négligeable, elle n’apparaît pas dans la liste pour éviter de dégrader les performances de la collection d’événements de build.
Dans la colonne Nom de la fonction, performPhysicsCalculations() est mise en surbrillance et marquée d’une icône représentant une flamme.
La colonne Temps [sec, %] indique le temps nécessaire pour compiler chaque fonction en Temps de responsabilité de la durée d’exécution (WCTR). Cette mesure distribue la durée d’exécution au sein des fonctions, selon leur utilisation de threads de compilateur parallèles. Par exemple, si deux threads différents compilent deux fonctions différentes simultanément dans une période d’une seconde, le WCTR de chaque fonction est enregistré sous forme de 0,5 secondes. Cela reflète la part proportionnelle de chaque fonction du temps de compilation total, en tenant compte des ressources consommées chaque fois pendant l’exécution parallèle. Ainsi, le WCTR fournit une meilleure mesure de l’impact de chaque fonction sur le temps de build global dans les environnements où plusieurs activités de compilation se produisent simultanément.
La colonne Taille Forceinline indique approximativement le nombre d’instructions générées pour la fonction. Cliquez sur le chevron avant le nom de la fonction pour voir les fonctions insérées individuelles qui ont été développées dans cette fonction et approximativement le nombre d’instructions générées pour chacun d’eux.
Vous pouvez trier la liste en cliquant sur la colonne Temps pour voir les fonctions prenant le plus de temps pour être compilées. Une icône « fire » indique que le coût de la génération de cette fonction est élevé et vaut la peine d’étudier. L’utilisation excessive de fonctions __forceinline peut ralentir considérablement la compilation.
Vous pouvez rechercher une fonction spécifique à l’aide de la zone Fonctions de filtre. Si le temps de génération de code d’une fonction est trop petit, il ne s’affiche pas dans la vue Fonctions.
Améliorer le temps de build en ajustant l’incorporation de fonctions
Dans cet exemple, la fonction performPhysicsCalculations prend le plus de temps à compiler.
Dans la colonne Nom de la fonction, performPhysicsCalculations() est mise en surbrillance et marquée d’une icône représentant une flamme.
En sélectionnant le chevron avant cette fonction, puis en triant la colonne Taille forceinline de la plus haute au plus bas, nous voyons les principaux contributeurs au problème.
performPhysicsCalculations() est développée et affiche une longue liste de fonctions qui y sont incorporées. Plusieurs instances de fonctions telles que complexOperation(), recursiveHelper() et sin() s’affichent. La colonne Taille Forceinline indique que complexOperation() est la fonction incorporée la plus grande, avec 315 instructions. recursiveHelper() comporte 119 instructions. Sin() comporte 75 instructions; mais il y a bien plus d’instances de cette fonction que des autres.
Des fonctions incorporées sont plus volumineuses, comme Vector2D<float>::complexOperation() et Vector2D<float>::recursiveHelper(), qui contribuent au problème. Mais il existe de nombreuses autres instances (dont certaines ne s’affichent pas ici) de Vector2D<float>::sin(float), Vector2D<float>::cos(float), Vector2D<float>::power(float,int) et Vector2D<float>::factorial(int). Lorsque vous les ajoutez, le nombre total d’instructions générées dépasse rapidement les quelques fonctions générées plus volumineuses.
En examinant ces fonctions dans le code source, nous voyons que le temps d’exécution va être passé dans les boucles. Par exemple, voici le code pour factorial() :
static __forceinline T factorial(int n)
{
T result = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < i; ++j) {
result *= (i - j) / (T)(j + 1);
}
}
return result;
}
Peut-être que le coût global d’appel de cette fonction est négligeable par rapport au coût de la fonction elle-même. La création d’une fonction inline est plus bénéfique lorsque le temps nécessaire à l’appel de la fonction (transmission d’arguments sur la pile, saut vers la fonction, affichage d’arguments de retour et retour de la fonction) est approximativement similaire au temps nécessaire à l’exécution de la fonction, et lorsque la fonction est souvent appelée. Si ce n’est pas le cas, il peut être moins intéressant de la rendre inline. Nous pouvons essayer de supprimer la directive __forceinline pour voir si cela réduit le temps de build. Le code pour power, sin() et cos() est similaire car il se compose d’une boucle qui s’exécute plusieurs fois. Nous pouvons également essayer de supprimer la directive __forceinline de ces fonctions.
Nous réexécutons Build Insights à partir du menu principal en choisissant Build>Exécuter Build Insights lors de la sélection>Rebuild. Vous pouvez également cliquer avec le bouton droit sur un projet dans l’Explorateur de solutions et choisir Exécuter Build Insights>Rebuild. Nous choisissons Reconstruire au lieu de Générer pour mesurer le temps de génération pour l’ensemble du projet, comme précédemment, et pas pour les quelques fichiers qui peuvent être sales pour le moment.
Le temps de build passe de 25,181 secondes à 13,376 secondes et la fonction performPhysicsCalculations ne s’affiche plus dans la vue Fonctions, car elle ne contribue pas suffisamment au temps de build à compter.
Dans la colonne Nom de la fonction, performPhysicsCalculations() est mise en surbrillance et marquée d’une icône représentant une flamme.
Le temps de session diagnostics est le temps global nécessaire pour effectuer la génération, ainsi que toute surcharge pour la collecte des données Build Insights.
L’étape suivante consiste à profiler l’application pour voir si la modification nuit à ses performances. Si tel est le cas, nous pouvons rajouter de manière sélective __forceinline si nécessaire.
Accéder au code source
Double-cliquez, cliquez avec le bouton droit ou appuyez sur Entrée lorsque vous êtes sur un fichier dans la vue Fonctions pour ouvrir le code source de ce fichier.
Conseils
- Enregistrez le fichier ETL à un emplacement plus permanent pour garder une trace des informations sur le temps de build à l’aide de Fichier>Enregistrer sous. Vous pouvez ensuite la comparer aux futures builds pour voir comment vos modifications améliorent les choses.
- Si vous fermez la fenêtre Build Insights, rouvrez-la en recherchant le
<dateandtime>.etlfichier dans votre dossier temporaire. La variable d’environnement WindowsTEMPfournit 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 de la fenêtre ETL à droite.
- Faites glisser des colonnes pour modifier leur ordre. Par exemple, vous préférerez peut-être placer la colonne Temps en tête. Vous pouvez masquer des colonnes en cliquant avec le bouton droit sur l’en-tête de colonne et en désélectionnant les colonnes que vous ne souhaitez pas voir.
- La vue Fonctions fournit une zone de filtre afin de rechercher une fonction qui vous intéresse. Elle offre des correspondances partielles sur le nom que vous fournissez.
- Si vous oubliez comment interpréter ce que la vue Fonctions essaye de vous montrer, survolez l’onglet pour afficher une info-bulle qui décrit la vue. Si vous survolez l’onglet Fonctions, l’info-bulle indique : « Vue qui affiche les statistiques des fonctions où les nœuds enfants sont des fonctions incorporées de force ».
Résolution des problèmes
- Si la fenêtre Build Insights ne s’affiche pas, générez une rebuild au lieu d’une build. La fenêtre Build Insights ne s’affiche 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 la vue Fonctions n’affiche aucune fonction, vous ne générez peut-être pas avec les paramètres d’optimisation appropriés. Vérifiez que vous générez la build Mise en production avec des optimisations complètes, comme décrit dans Définir les options de build. En outre, si le temps de génération de code d’une fonction est trop petit, il ne s’affiche pas dans la liste.
Voir aussi
Conseils et astuces relatifs à Build Insights
Fonctions inline (C++)
Builds C++ accélérées et simplifiées : une nouvelle mesure de temps
Vidéo Build Insights dans Visual Studio - Pure Virtual C++ 2023
Résoudre les problèmes de l’impact du fichier d’en-tête sur le temps de build
Vue Fonctions de Build Insights dans Visual Studio 2022 17.8
Tutoriel : vcperf et Analyseur de performance Windows
Améliorer le temps de génération de code avec C++ Build Insights