Débogage vs performances de publication

132

J'ai rencontré le paragraphe suivant:

«Le paramètre Debug vs. Release dans l'EDI lorsque vous compilez votre code dans Visual Studio ne fait pratiquement aucune différence sur les performances… le code généré est presque le même. Le compilateur C # ne fait vraiment aucune optimisation. Le compilateur C # crache juste IL… et au moment de l'exécution c'est le JITer qui fait toute l'optimisation. Le JITer a un mode Debug / Release et cela fait une énorme différence en termes de performances. Mais cela ne détermine pas si vous exécutez la configuration Debug ou Release de votre projet, cela détermine si un débogueur est attaché. »

La source est ici et le podcast est ici .

Quelqu'un peut-il me diriger vers un article Microsoft qui peut réellement le prouver?

Googler « C # debug vs release performance » renvoie principalement des résultats indiquant « Debug has a lot of performance hit », « release is optimized » et « don't deploy debug to production ».

Sagie
la source
duplication possible des différences
Hans Passant
Avec .Net4 sur Win7-x86, j'ai un programme limité en CPU que j'ai écrit et qui tourne presque 2x plus vite en version qu'en débogage sans assertions / etc dans la boucle principale.
Bengie
De plus, si vous vous souciez de l'utilisation de la mémoire, il peut y avoir de grandes différences. J'ai vu un cas où un service Windows multithread compilé en mode débogage utilisait 700 Mo par thread, contre 50 Mo par thread dans la version Release. La version Debug a rapidement manqué de mémoire dans des conditions d'utilisation typiques.
o. nate
@Bengie - avez-vous vérifié que si vous attachez un débogueur à la version de la version, il fonctionne toujours 2 fois plus vite? Notez que la citation ci-dessus indique que l'optimisation JIT est affectée par l'attachement du débogueur.
ToolmakerSteve

Réponses:

99

Partiellement vrai. En mode débogage, le compilateur émet des symboles de débogage pour toutes les variables et compile le code tel quel. En mode version, certaines optimisations sont incluses:

  • les variables inutilisées ne sont pas du tout compilées
  • certaines variables de boucle sont retirées de la boucle par le compilateur si elles s'avèrent être des invariants
  • le code écrit sous la directive #debug n'est pas inclus, etc.

Le reste appartient au JIT.

Liste complète des optimisations ici gracieuseté d' Eric Lippert .

Adrian Zanescu
la source
10
Et n'oubliez pas Debug.Asserts! Dans la construction DEBUG, s'ils échouent, ils arrêteront le thread et afficheront une boîte de message. En version, ils ne sont pas du tout compilés. Cela s'applique à toutes les méthodes qui ont [ConditionalAttribute].
Ivan Zlatanov
13
Le compilateur C # n'effectue pas d'optimisation des appels de fin; la gigue le fait. Si vous voulez une liste précise de ce que fait le compilateur C # lorsque le commutateur d'optimisation est activé, voir blogs.msdn.com/ericlippert/archive/2009/06/11
Eric Lippert
63

Il n'y a aucun article qui "prouve" quoi que ce soit sur une question de performance. La façon de prouver une affirmation sur l'impact d'un changement sur les performances est de l'essayer dans les deux sens et de le tester dans des conditions réalistes mais contrôlées.

Vous posez une question sur la performance, donc vous vous souciez clairement de la performance. Si vous vous souciez des performances, la bonne chose à faire est de définir des objectifs de performance, puis de vous écrire une suite de tests qui suit vos progrès par rapport à ces objectifs. Une fois que vous avez une telle suite de tests, vous pouvez facilement l'utiliser pour tester par vous-même la véracité ou la fausseté des déclarations telles que "la compilation de débogage est plus lente".

Et en plus, vous pourrez obtenir des résultats significatifs. «Plus lent» n'a pas de sens car il n'est pas clair si c'est une microseconde plus lent ou vingt minutes plus lent. «10% plus lent dans des conditions réalistes» est plus significatif.

Passez le temps que vous auriez passé à rechercher cette question en ligne sur la construction d'un appareil qui répond à la question. Vous obtiendrez ainsi des résultats beaucoup plus précis. Tout ce que vous lisez en ligne n'est qu'une estimation de ce qui pourrait arriver. Raison des faits que vous avez recueillis vous-même, et non des suppositions des autres sur la façon dont votre programme pourrait se comporter.

Eric Lippert
la source
2
Je pense que vous pouvez vous soucier des performances tout en ayant toujours le désir d'utiliser "debug". Par exemple, si la plupart de votre temps est en attente de dépendances, je ne pense pas que la construction en mode débogage fera une grande différence, mais vous avez l'avantage supplémentaire d'obtenir des numéros de ligne dans les traces de pile, ce qui peut aider à corriger les bogues plus rapidement et faire utilisateurs plus heureux. Le fait est que vous devez peser le pour et le contre, et une instruction générale «l'exécution du débogage est plus lente, mais seulement si vous êtes lié au processeur» suffit pour vous aider à prendre une décision.
Josh Mouch
11

Je ne peux pas faire de commentaires sur les performances, mais le conseil «ne pas déployer le débogage en production» tient toujours simplement parce que le code de débogage fait généralement pas mal de choses différemment dans les gros produits. D'une part, vous pourriez avoir des commutateurs de débogage actifs et pour une autre, il y aura probablement des contrôles de cohérence redondants supplémentaires et des sorties de débogage qui n'appartiennent pas au code de production.

Konrad Rudolph
la source
Je suis d'accord avec vous sur ce point, mais cela ne répond pas à la question principale
sagie
5
@sagie: oui, j'en suis conscient mais je pensais que ce point valait encore la peine d'être souligné.
Konrad Rudolph
6

De msdn sociale

Ce n'est pas bien documenté, voici ce que je sais. Le compilateur émet une instance de System.Diagnostics.DebuggableAttribute. Dans la version de débogage, la propriété IsJitOptimizerEnabled a la valeur True, dans la version finale, elle est False. Vous pouvez voir cet attribut dans le manifeste d'assembly avec ildasm.exe

Le compilateur JIT utilise cet attribut pour désactiver les optimisations qui rendraient le débogage difficile. Ceux qui déplacent le code comme le levage invariant de boucle. Dans certains cas, cela peut faire une grande différence en termes de performances. Pas d'habitude cependant.

Le mappage des points d'arrêt aux adresses d'exécution est le travail du débogueur. Il utilise le fichier .pdb et les informations générées par le compilateur JIT qui fournit l'instruction IL au mappage d'adresses de code. Si vous écrivez votre propre débogueur, vous utiliserez ICorDebugCode :: GetILToNativeMapping ().

Fondamentalement, le déploiement de débogage sera plus lent car les optimisations du compilateur JIT sont désactivées.

Neil
la source
3

Ce que vous lisez est tout à fait valable. La version est généralement plus légère en raison de l'optimisation JIT, sans inclure le code de débogage (#IF DEBUG ou [Conditionnel ("DEBUG")]), le chargement minimal des symboles de débogage et souvent non pris en compte est un assemblage plus petit qui réduira le temps de chargement. Les performances différentes sont plus évidentes lors de l'exécution du code dans VS en raison d'une PDB plus étendue et des symboles chargés, mais si vous l'exécutez indépendamment, les différences de performances peuvent être moins apparentes. Certains codes s'optimiseront mieux que les autres et utilisent les mêmes heuristiques d'optimisation que dans d'autres langages.

Scott a une bonne explication sur l'optimisation des méthodes en ligne ici

Consultez cet article qui explique brièvement pourquoi il est différent dans l'environnement ASP.NET pour le paramètre de débogage et de version.

Fadrian Sudaman
la source
3

Une chose à noter, concernant les performances et si le débogueur est attaché ou non, quelque chose qui nous a pris par surprise.

Nous avions un morceau de code, impliquant de nombreuses boucles serrées, qui semblait prendre une éternité à déboguer, mais qui fonctionnait assez bien tout seul. En d'autres termes, aucun client ou client n'avait des problèmes, mais lorsque nous déboguions, cela semblait fonctionner comme de la mélasse.

Le coupable était l'une Debug.WriteLinedes boucles serrées, qui crachait des milliers de messages de journal, laissés par une session de débogage il y a quelque temps. Il semble que lorsque le débogueur est attaché et écoute une telle sortie, il y a une surcharge impliquée qui ralentit le programme. Pour ce code particulier, il était de l'ordre de 0,2 à 0,3 seconde d'exécution seul, et plus de 30 secondes lorsque le débogueur était attaché.

Solution simple cependant, supprimez simplement les messages de débogage qui n'étaient plus nécessaires.

Lasse V. Karlsen
la source
2

Sur le site msdn ...

Configurations Release vs Debug

Pendant que vous travaillez encore sur votre projet, vous générez généralement votre application à l'aide de la configuration de débogage, car cette configuration vous permet d'afficher la valeur des variables et de contrôler l'exécution dans le débogueur. Vous pouvez également créer et tester des builds dans la configuration de la version pour vous assurer que vous n'avez introduit aucun bogue qui se manifeste uniquement sur un type de build ou l'autre. Dans la programmation .NET Framework, ces bogues sont très rares, mais ils peuvent survenir.

Lorsque vous êtes prêt à distribuer votre application aux utilisateurs finaux, créez une version de version, qui sera beaucoup plus petite et aura généralement de bien meilleures performances que la configuration de débogage correspondante. Vous pouvez définir la configuration de construction dans le volet Génération du Concepteur de projet ou dans la barre d'outils Génération. Pour plus d'informations, consultez Configurations de construction.

hallie
la source
1

Dans une large mesure, cela dépend de la question de savoir si votre application est liée au calcul, et ce n'est pas toujours facile à dire, comme dans l'exemple de Lasse. Si j'ai la moindre question sur ce qu'il fait, je le mets en pause plusieurs fois et examine la pile. S'il se passe quelque chose de plus dont je n'avais pas vraiment besoin, cela le détecte immédiatement.

Mike Dunlavey
la source
1

J'ai récemment rencontré un problème de performances. La liste complète des produits prenait trop de temps, environ 80 secondes. J'ai réglé la base de données, amélioré les requêtes et il n'y avait aucune différence. J'ai décidé de créer un TestProject et j'ai découvert que le même processus était exécuté en 4 secondes. Ensuite, j'ai réalisé que le projet était en mode Debug et que le projet de test était en mode Release. J'ai basculé le projet principal en mode Release et la liste complète des produits n'a pris que 4 secondes pour afficher tous les résultats.

Résumé: Le mode de débogage est beaucoup plus lent que le mode d'exécution car il conserve les informations de débogage. Vous devez toujours déployer en mode Relase. Vous pouvez toujours avoir des informations de débogage si vous incluez des fichiers .PDB. De cette façon, vous pouvez enregistrer des erreurs avec des numéros de ligne, par exemple.

Francisco Goldenstein
la source
Par "mode exécution", vous voulez dire "Release"?
Ron Klein
Oui, exactement. Release n'a pas tous les frais généraux de débogage.
Francisco Goldenstein
1

Les modes Debug et Release ont des différences. Il existe un outil Fuzzlyn : c'est un fuzzer qui utilise Roslyn pour générer des programmes C # aléatoires. Il exécute ces programmes sur .NET core et garantit qu'ils donnent les mêmes résultats lorsqu'ils sont compilés en mode débogage et version.

Avec cet outil, il a été trouvé et signalé de nombreux bugs.

Sergey Ponomarev
la source