C'est assez standard dans l'ingénierie logicielle dans son ensemble - lorsque vous optimisez le code, le compilateur est autorisé à réorganiser les choses à peu près comme il le souhaite, tant que vous ne pouvez pas faire de différence de fonctionnement. Ainsi, par exemple, si vous initialisez une variable à l'intérieur de chaque itération d'une boucle et que vous ne changez jamais la variable à l'intérieur de la boucle, l'optimiseur est autorisé à déplacer cette initialisation hors de la boucle, afin de ne pas perdre de temps avec.
Il peut également se rendre compte que vous calculez un nombre avec lequel vous ne faites rien avant d'écraser. Dans ce cas, cela pourrait éliminer le calcul inutile.
Le problème avec l'optimisation est que vous voudrez mettre un point d'arrêt sur un morceau de code que l'optimiseur a déplacé ou éliminé. Dans ce cas, le débogueur ne peut pas faire ce que vous voulez (généralement, il mettra le point d'arrêt quelque part près). Ainsi, pour que le code généré ressemble davantage à ce que vous avez écrit, vous désactivez les optimisations pendant le débogage - cela garantit que le code que vous souhaitez utiliser est vraiment là.
Cependant, vous devez être prudent avec cela, car en fonction de votre code, l'optimisation peut casser les choses! En général, le code qui est cassé par un optimiseur fonctionnant correctement est vraiment juste du code bogué qui s'en sort avec quelque chose, donc vous voulez généralement comprendre pourquoi l'optimiseur le casse.
J'ai envoyé cette question à Jack Ganssle et voici ce qu'il m'a répondu:
la source
Cela dépend, et cela est généralement vrai pour tous les outils, pas seulement C30.
Les optimisations suppriment et / ou restructurent souvent le code de diverses manières. Votre instruction switch peut être réimplémentée avec une construction if / else ou dans certains cas peut être supprimée tous ensemble. y = x * 16 peut être remplacé par une série de décalages à gauche, etc. bien que ce dernier type d'optimisation puisse généralement encore être franchi, c'est principalement la restructuration de la déclaration de contrôle qui y parvient.
Cela peut rendre impossible le passage d'un débogueur dans votre code C car les structures que vous avez définies en C n'existent plus, elles ont été remplacées ou réorganisées par le compilateur en quelque chose que le compilateur pense être plus rapide ou utiliser moins d'espace. Cela peut également rendre les points d'arrêt impossibles à définir à partir de la liste C, car l'instruction sur laquelle vous appuyez peut ne plus exister. Par exemple, vous pouvez essayer de définir un point d'arrêt dans une instruction if, mais le compilateur peut l'avoir supprimé if. Vous pouvez essayer de définir un point d'arrêt à l'intérieur d'une boucle while ou for mais le compilateur a décidé de dérouler cette boucle afin qu'elle n'existe plus.
Pour cette raison, si vous pouvez déboguer avec des optimisations désactivées, c'est généralement plus facile. Vous devez toujours retester avec les optimisations activées. C'est à peu près la seule façon de découvrir que vous avez raté un important
volatile
et que cela provoque des échecs intermittents (ou une autre bizarrerie).Dans le cas du développement intégré, vous devez quand même faire attention aux optimisations. Plus précisément dans les sections de code dont le timing est critique, certaines interruptions par exemple. Dans ces cas, vous devez soit coder les bits critiques de l'assembly, soit utiliser des directives de compilation pour vous assurer que ces sections ne sont pas optimisées afin que vous sachiez qu'elles ont un temps d'exécution fixe ou un temps d'exécution du pire cas fixe.
L'autre gotcha peut être l'adaptation de code dans l'UC, vous pouvez avoir besoin d'optimisations de densité de code pour adapter simplement votre code dans la puce. C'est une des raisons pour lesquelles c'est généralement une bonne idée de commencer avec la plus grande capacité de ROM uC d'une famille et de n'en choisir qu'une plus petite pour la fabrication, une fois votre code verrouillé.
la source
En règle générale, je déboguerais avec les paramètres avec lesquels je prévoyais de publier. Si je devais publier du code optimisé, je déboguerais avec du code optimisé. Si je devais libérer du code non optimisé, je déboguerais avec du code non optimisé. Je le fais pour deux raisons. Premièrement, les optimiseurs peuvent faire des différences de synchronisation suffisamment importantes pour que le produit final se comporte différemment du code non optimisé. Deuxièmement, même si la plupart sont assez bons, les éditeurs de compilateurs font des erreurs et le code optimisé peut produire des résultats différents à partir du code non optimisé. En conséquence, j'aime obtenir autant de temps de test que possible avec le paramètre avec lequel je prévois de sortir.
Cela étant dit, les optimiseurs peuvent rendre le débogage difficile, comme indiqué dans les réponses précédentes. Si je trouve une section de code particulière qui est difficile à déboguer, je désactiverai temporairement l'optimiseur, je ferai le débogage pour que le code fonctionne, puis je réactiverai l'optimiseur et je testerai à nouveau.
la source
Ma stratégie normale est de développer avec l'optimisation finale (max pour la taille ou la vitesse selon le cas), mais désactivez temporairement l'optimisation si j'ai besoin de déboguer ou de tracer quelque chose. Cela réduit le risque de bogues apparaissant en raison de la modification des niveaux d'optimisation.
Un mode d'échec typique est lorsque l'augmentation de l'optimisation fait apparaître des bogues précédemment invisibles du fait que vous n'avez pas déclaré les variables comme volatiles si nécessaire - cela est essentiel pour dire au compilateur quelles choses ne doivent pas être `` optimisées ''.
la source
Utilisez la forme que vous allez publier, les débogueurs et la compilation pour le débogage cachent beaucoup (BEAUCOUP) de bogues que vous ne voyez pas jusqu'à ce que vous compiliez pour la sortie. D'ici là, il est beaucoup plus difficile de trouver ces bogues, par rapport au débogage au fur et à mesure. 20 ans quelque chose maintenant et je n'ai jamais eu d'utilisation d'un gdb ou d'un autre débogueur comme, pas besoin de regarder des variables ou une seule étape. Des centaines à des milliers de lignes par jour. Il est donc possible, ne soyez pas amené à penser le contraire.
La compilation pour le débogage puis la compilation ultérieure pour la publication peut et prendra deux à plus de deux fois l'effort. Si vous entrez dans une liaison et devez utiliser un outil comme un débogueur, puis compilez pour que le débogueur résout le problème spécifique, puis revenez au fonctionnement normal.
D'autres problèmes sont également vrais comme l'optimiseur rend le code plus rapide, donc pour incorporer en particulier vos changements de timing avec les options du compilateur et qui peuvent affecter les fonctionnalités de votre programme, utilisez ici encore le choix de compilation livrable pendant toute la phase. Les compilateurs sont aussi des programmes et ont des bugs et les optimiseurs font des erreurs et certains n'y croient pas. Si c'est le cas, il n'y a rien de mal à compiler sans optimisation, faites-le de cette façon tout le temps. Le chemin que je préfère est de compiler pour l'optimisation, puis si je soupçonne un problème de compilateur, désactivez l'optimisation si cela le corrige, généralement en va-et-vient, en examinant parfois la sortie de l'assembleur pour comprendre pourquoi.
la source
Je développe toujours du code avec -O0 (option gcc pour désactiver l'optimisation). Lorsque je sens que je suis au point où je veux commencer à laisser les choses se diriger davantage vers une version, je commence par -Os (optimiser la taille), car généralement plus vous pouvez conserver de code dans le cache, mieux ce sera, même si ce n'est pas optimisé super-duper.
Je trouve que gdb fonctionne beaucoup mieux avec le code -O0, et c'est beaucoup plus facile à suivre si vous devez entrer dans l'assemblage. Le basculement entre -O0 et -Os vous permet également de voir ce que le compilateur fait à votre code. C'est parfois une éducation assez intéressante, et peut également découvrir des bogues de compilation ... ces choses désagréables qui vous font vous arracher les cheveux en essayant de comprendre ce qui ne va pas avec votre code!
Si j'en ai vraiment besoin, je vais commencer à ajouter des sections -fdata et -fcode-sections avec --gc-sections, qui permettent à l'éditeur de liens de supprimer des fonctions et des segments de données entiers qui ne sont pas réellement utilisés. Il y a beaucoup de petites choses avec lesquelles vous pouvez bricoler pour essayer de réduire davantage ou d'accélérer les choses, mais dans l'ensemble ce sont les seules astuces que je finis par utiliser, et tout ce qui doit être plus petit ou plus rapide, je vais le remettre -assembler.
la source
Oui, la désactivation des optimisations pendant le débogage est la meilleure pratique depuis un certain temps maintenant, pour trois raisons:
Beaucoup de gens vont encore plus loin dans cette direction et expédient avec des assertions activées .
la source
Simple: les optimisations prennent du temps et peuvent être inutiles si vous devez modifier ce morceau de code plus tard dans le développement. Ils peuvent donc être une perte de temps et d'argent.
Ils sont cependant utiles pour les modules finis; des parties du code qui n'auront probablement plus besoin de modifications.
la source
cela a certainement du sens dans le cas des points d'arrêt ... car le compilateur peut supprimer de nombreuses instructions qui n'affectent pas réellement la mémoire.
considérez quelque chose comme:
pourrait être entièrement optimisé (car il
i
n'est jamais lu). il semblerait, du point de vue de votre point d'arrêt, qu'il a ignoré tout ce code, alors qu'il n'était tout simplement pas là ... Je suppose que c'est pourquoi dans les fonctions de type veille, vous verrez souvent quelque chose comme:la source
Si vous utilisez le débogueur, je désactiverais les optimisations et activerais le débogage.
Personnellement, je trouve que le débogueur PIC provoque plus de problèmes qu'il ne m'aide à résoudre.
J'utilise simplement printf () pour USART pour déboguer mes programmes écrits en C18.
la source
La plupart des arguments contre l'activation de l'optimisation dans votre compilation se résument à:
À mon humble avis, les deux premiers sont légitimes, le troisième moins. Cela signifie souvent que vous avez un mauvais code ou que vous comptez sur une exploitation non sécurisée du langage / de l'implémentation ou que l'auteur est peut-être juste un fan du bon vieux comportement de l'oncle non défini.
Le blog Embedded in Academia a une ou deux choses à dire sur le comportement indéfini, et cet article explique comment les compilateurs l'exploitent: http://blog.regehr.org/archives/761
la source