web-dev-qa-db-fra.com

Profilage de fonctions C++ intégrées avec Visual Studio Compiler

Comment puis-je comprendre le profilage des données C++ sous Windows, lorsque le compilateur insère beaucoup de code? C'est à dire. Bien sûr, je veux mesurer le code qui est réellement exécuté. Par définition, je vais donc mesurer une version optimisée du code. Mais il semble qu'aucun des outils que j'essaie ne parvienne réellement à résoudre les fonctions en ligne.

J'ai essayé le profileur d'échantillonnage dans Visual Studio 2017 Professional ainsi que dans VTune 2018. J'ai essayé d'activer /Zo, mais cela ne semble pas avoir d'incidence.

J'ai trouvé la ressource suivante qui semble indiquer que seul Visual Studio Ultimate ou Premium prend en charge les informations de cadre en ligne. Est-ce toujours le cas pour Visual Studio 2017? https://social.msdn.Microsoft.com/Forums/fr-9df15363-5aae-4f0b-a5ad-dd9939917d4c/which-functions-arent-pgo-optimized-using-profile-profile-dofile-data?dum=vsdebug

Voici un exemple de code:

#include <cmath>
#include <random>
#include <iostream>

inline double burn()
{
    std::uniform_real_distribution<double> uniform(-1E5, 1E5);
    std::default_random_engine engine;
    double s = 0;
    for (int i = 0; i < 100000000; ++i) {
        s += uniform(engine);
    }
    return s;
}

int main()
{
    std::cout << "random sum: " << burn() << '\n';
    return 0;
}

Compilez-le avec Visual Studio en mode Release. Ou sur la ligne de commande, essayez cl /O2 /Zi /Zo /EHsc main.cpp. Essayez ensuite de le profiler avec le CPU Sampling Profiler dans Visual Studio. Vous verrez tout au plus quelque chose comme ceci:

 confusing profile since inline frames are missing

VTune 2018 ressemble à Windows. Sous Linux, perf et VTune n'ont aucun problème à afficher les images des fonctions en ligne ... Cette fonctionnalité, qui est à mon avis cruciale pour les outils C++, ne fait-elle vraiment pas partie des chaînes d'outils Visual Studio non Premium/Ultimate? Comment les utilisateurs de Windows traitent-ils cela? Quel est le point de /Zo alors?

EDIT: Je viens d'essayer de compiler l'exemple minimal ci-dessus avec clang et cela produit des résultats différents, mais toujours insatisfaisants? J'ai compilé clang 6.0.0 (trunk), construit à partir de LLVM rev 318844 et clang rev 318874. Ensuite, je compile mon code avec clang++ -std=c++17 -O2 -g main.cpp -o main.exe et exécute à nouveau l'exécutable résultant avec Sampling Profiler dans Visual Studio. Le résultat est le suivant:

 inline frames are shown in profile after compiling with clang

Alors maintenant, je vois la fonction burn, mais j'ai perdu les informations du fichier source. De plus, le uniform_real_distribution n'est toujours affiché nulle part.

EDIT 2: Comme suggéré dans les commentaires, j’ai maintenant aussi essayé clang-cl avec les mêmes arguments que cl ci-dessus, à savoir: clang-cl.exe /O2 /Zi /Zo /EHsc main.cpp. Cela produit les mêmes résultats que clang.exe, mais nous obtenons également des mappages de sources de travail:

 clang-cl shows inliners and somewhat functional source mapping

EDIT 3: Je pensais à l’origine que clang pourrait résoudre ce problème par magie. Ce n'est pas le cas, malheureusement. La plupart des cadres en ligne sont toujours manquants :(

EDIT 4: Les cadres inline ne sont pas pris en charge dans VTune pour les applications construites avec les versions MSVC/PDB: https://software.intel.com/en-us/forums/intel-vtune-amplifier-xe/topic/749363

15
milianw

J'ai essayé le profileur d'échantillonnage dans Visual Studio 2017 Professional et VTune 2018. J'ai essayé d'activer/Zo, mais il ne semble pas y avoir d'incidence.

J'ai trouvé la ressource suivante qui semble indiquer que seul Visual Studio Ultimate ou Premium prend en charge les informations de cadre en ligne - Est-ce toujours le cas pour Visual Studio 2017?

Heureusement, j'ai déjà trois versions différentes de VS installées. Je peux vous dire plus d'informations sur la prise en charge de la fonctionnalité d'informations sur les fonctions intégrées, comme indiqué dans le article que vous avez cité:

  • VS Community 2013 Update 5 ne prend pas en charge l'affichage des fonctions en ligne même lorsque je spécifie/d2Zi +. Il semble que cela ne soit pris en charge que par VS 2013 Premium ou Ultimate.
  • VS Community 2015 Update 3 prend en charge l'affichage des fonctions en ligne (fonctionnalité décrite dans le article ). Par défaut,/Zi est spécifié. /Zo est activé implicitement avec/Zi , vous n'avez donc pas à le spécifier explicitement. Par conséquent, vous n'avez pas besoin de VS 2015 Premium ou Ultimate.
  • VS Community 2017 avec la dernière mise à jour ne prend pas en charge l'affichage des fonctions en ligne indépendamment de/Zi et/Zo. Il semble que cela ne soit pris en charge que par VS 2017 Professional et/ou Enterprise.

Il n'y a pas d'annonce sur le blog VC++ concernant les améliorations apportées au profileur d'échantillonnage VS 2017; je ne pense donc pas que ce soit meilleur par rapport au profileur de VS Community 2015.

Notez que différentes versions du compilateur peuvent prendre différentes décisions d'optimisation. Par exemple, j'ai observé que VS 2013 et 2015 n'alignaient pas la fonction burn.

En utilisant VS Community 2015 Update 3, les résultats du profilage sont très similaires à ceux de la troisième image et le même code est mis en surbrillance.

Je vais maintenant expliquer en quoi ces informations supplémentaires peuvent être utiles lors de l’interprétation des résultats du profilage, comment les obtenir manuellement avec un peu plus d’effort et comment interpréter les résultats malgré les fonctions en ligne.

Comment donner un sens aux données de profilage C++ sous Windows, lorsqu'un grand nombre de codes Sont insérés en ligne par le compilateur?

Le profileur de VS n'attribuera des coûts qu'aux fonctions non en ligne. Pour les fonctions en ligne, les coûts seront additionnés et inclus dans une fonction appelant qui ne l’était pas (dans ce cas, la fonction burn).

En additionnant le temps d'exécution estimé des fonctions appelées non insérées à partir de burn (comme indiqué dans l'image), nous obtenons 31,3 + 22,7 + 4,7 + 1,1 = 59,8%. De plus, le temps d'exécution estimé du Function Body indiqué dans l'image est de 40,2%. Notez que 59,8% + 40,2% = 100% du temps passé dans burn, comme il se doit. En d'autres termes, 40,2% du temps passé dans burn a été passé dans le corps de la fonction et de toutes les fonctions qui y étaient intégrées.

40,2%, c'est beaucoup. La prochaine question logique est de savoir quelles fonctions sont intégrées à burn? En utilisant cette fonctionnalité dont j'ai parlé précédemment (disponible dans VS Community 2015), je peux déterminer que les fonctions suivantes ont été insérées dans burn:

std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>::{ctor};
std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::{ctor};
std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::seed;
std::uniform_real<double>::operator();
std::uniform_real<double>::_Eval;
std::generate_canonical;

Sans cette fonctionnalité, vous devrez désassembler manuellement le binaire exécutable émis (à l'aide du débogueur VS ou de dumpbin ) et localiser toutes les instructions x86 call. En comparant cela avec les fonctions appelées dans le code source, vous pouvez déterminer quelles fonctions ont été intégrées.

Les capacités du profileur d'échantillonnage VS, y compris VS 2017, prennent fin à ce stade. Mais ce n'est vraiment pas une restriction significative. Généralement, peu de fonctions sont en ligne dans la même fonction en raison d'une limite supérieure stricte imposée par le compilateur sur la taille de chaque fonction. Il est donc généralement possible de vérifier manuellement le code source et/ou le code d'assemblage de chaque fonction en ligne et de voir si ce code contribuerait de manière significative au temps d'exécution. Je l'ai fait et il est probable que le corps de burn (à l'exclusion des fonctions en ligne) et ces deux fonctions en ligne soient principalement responsables de ces 40,2%.

std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::seed;
std::uniform_real<double>::_Eval;

En prenant tout cela en considération, la seule opportunité potentielle d'optimisation que je vois ici est de mémoriser les résultats de log2.

Le profileur d'échantillonnage VTune est certainement plus puissant que le profileur d'échantillonnage VS. En particulier, VTune attribue des coûts à des lignes de code source individuelles ou à des instructions d'assemblage. Cependant, cette attribution est très approximative et souvent absurde. Je ferais donc très attention en interprétant les résultats visualisés de cette manière. Je ne sais pas si VTune prend en charge les informations Enhanced Optimized Debugging ou le degré de prise en charge qui permet d'attribuer des coûts aux fonctions intégrées. Le meilleur endroit pour poser ces questions est le forum de la communauté Intel VTune Amplifier .

3
Hadi Brais

Je ne suis pas sûr d'avoir bien compris le problème décrit dans votre question. Sur votre site, j'essayerais l'option du compilateur/Ob0 Visual C++. Il doit désactiver le développement en ligne.

L'option/Ob compilateur contrôle le développement en ligne des fonctions. Il doit être suivi du numéro 0 , 1 ou 2 .

0 Désactive les développements en ligne. Par défaut, le compilateur développe les extensions de toutes les fonctions, souvent appelées auto-alignement.

1 Autorise uniquement le développement de fonctions marquées comme inline, __inline ou __forceinline ou dans une fonction membre C++ définie dans une déclaration de classe.

2 La valeur par défaut. Permet le développement de fonctions marquées comme inline, __inline ou __forceinline, ainsi que de toute autre fonction choisie par le compilateur.

/Ob2 est en vigueur lorsque/O1 ,/O2 (réduire la taille, maximiser la vitesse) ou/Ox (activer les optimisations les plus rapides ) est utilisé.

Cette option nécessite que vous activiez les optimisations avec/O1 ,/O2 ,/Ox ou/Og .

Pour définir cette option du compilateur dans l'environnement de développement Visual Studio

  1. Ouvrez la boîte de dialogue Pages de propriétés du projet. Pour plus d'informations, voir Utilisation des propriétés du projet.
  2. Développez Propriétés de configuration, C/C++, puis sélectionnez Optimisation.
  3. Modifiez la propriété Expansion de fonction en ligne.

 enter image description here

Pour plus d'informations, consultez l'article /Ob (extension de fonction en ligne)

0
S.M.