Quelles sont les méthodes de refactoring pour réduire la taille du code compilé?
J'ai un héritage du firmware de l'application qui requiert de nouvelles fonctionnalités. La taille de l'application était déjà près de la limité flash capacité de l'appareil et le peu de nouvelles fonctions et de variables poussé sur le bord. Tournant sur l'optimisation du compilateur fait le tour, mais le client se méfie de le faire parce qu'ils ont causés échecs dans le passé. Alors, quelles sont les choses à rechercher lors d'un refactoring de code C à produire de plus petites sortie?
source d'informationauteur Judge Maygarden
Vous devez vous connecter pour publier un commentaire.
Si vous avez encore besoin de plus d'espace avec
compile with optimizations
allumé, puis regardez l'assembly généré rapport unoptimized code. Puis de le ré-écrire le code où les plus grands changements ont eu lieu, de sorte que le compilateur génère les mêmes optimisations basées sur la délicate C re-écrit avec l'optimisation éteint.Par exemple, vous pouvez avoir plusieurs " si " des déclarations qui font des comparaisons similaires:
Puis créer à nouveau de la variable, et de faire des comparaisons à l'avance permettra d'économiser le compilateur à partir de la duplication de code:
C'est l'un des optimisations du compilateur fait automatiquement pour vous si vous le mettez sur. Il y a beaucoup, beaucoup d'autres, et vous pourriez envisager de lire un peu de la théorie des compilateurs si vous voulez apprendre comment faire cela à la main dans le code C.
En général: faire usage de votre linker carte ou des outils pour comprendre ce que votre plus grand/plus nombreux symboles sont, et puis, éventuellement, prendre un coup d'oeil à l'aide d'un désassembleur. Vous seriez surpris de voir à ce que vous trouver de cette façon.
Avec un peu de perl ou le souhaitez, vous pouvez faire qu'une bouchée de un .xMAP fichier ou les résultats de la "objdump" ou "nm", et re-trier les différentes façons pour les informations pertinentes.
Spécifique aux petits jeux d'instructions: voir pour littérale de la piscine d'utilisation. Tout en changeant par exemple le BRAS (32 bits par instruction) jeu d'instructions pour le POUCE (16 bits par instruction) jeu d'instructions peut être utile sur certains processeurs ARM, il réduit la taille de la "immédiate" sur le terrain.
Soudain, quelque chose qui serait une directe de la charge de manière globale ou statique devient très indirecte; il faut d'abord charger l'adresse de l'global/statique dans un registre, puis la charge de qui, plutôt que de simplement l'encodage de l'adresse directement dans l'instruction. Ainsi, vous obtenez un supplément de quelques instructions et une entrée supplémentaire dans le sens littéral de la piscine pour quelque chose qui, normalement, auraient été une instruction.
Une stratégie pour lutter contre cela est de regrouper les variables globales et statiques ensemble dans des structures; de cette façon, vous ne stocker un littéral (l'adresse de votre structure globale) et de calculer les décalages de cela, plutôt que de stocker beaucoup de différents littéraux lorsque vous avez accès à plusieurs statique/globals.
Nous avons converti notre "singleton" les classes de la gestion de leur propre instance pointeurs à ne plus être que des membres dans un grand "struct GlobalTable", et il faire une différence notable dans la taille du code (quelques pour cent) ainsi que les performances dans certains cas.
Autrement: gardez un œil sur la statique des structures et des tableaux de non-trivialement construit de données. Chacun de ces génère habituellement des quantités énormes de .sinit code ("invisible fonctions", si vous voulez) qui sont exécutés avant le main() pour remplir ces tableaux correctement. Si vous ne pouvez utiliser que trivial types de données dans votre statique, vous serez beaucoup mieux lotis.
C'est encore quelque chose qui peut être facilement identifié à l'aide d'un outil sur les résultats de la "nm" ou "objdump" ou similaire. Si vous avez une tonne de .sinit d'autres choses, vous aurez envie d'étudier!
Oh, et -- si votre compilateur/linker supporte, n'hésitez pas à activer de manière sélective d'optimisation ou de petits ensembles d'instructions pour seulement certains fichiers ou des fonctions!
Refactoring hors code en double devrait avoir le plus grand impact sur votre programme de la mémoire.
Prêter attention à des macros. Ils peuvent produire beaucoup de code à partir d'une seule macro d'extension. Si vous trouvez que ces macros - essayer de réécrire de sorte que leur taille est réduite et la fonctionnalité est déplacé à fonctions.
Attention à dupliquer le code, le copier-collé et logiquement en double. Essayez de séparer les dupliquer le code dans des fonctions.
Vérifier si le compilateur prend en charge l'in-lining et il peut être éteint.
Optimisation de compilateur qui déclenche bug ? C'est étrange.
Obtenir une carte de votre programme, et de voir si vous devriez cibler les données ou le code.
Recherchez le code dupliqué. Recherchez le code avec le même objectif. Un exemple de cela est le busybox code, qui vise pour une petite empreinte mémoire.
C'est en favorisant taille plus de lisibilité, de sorte qu'il parfois devenir très laid, avec des gotos et ainsi de suite.
Les réponses ci-dessus, la revendication "d'allumer optimisation du compilateur [réduit la taille du code]". Compte tenu de l'ensemble de la documentation et de l'expérience que j'ai eu dans les systèmes embarqués TI DSP de la programmation, je sais pour un fait que tourner sur l'optimisation permettra d'AUGMENTER votre taille de code ( pour TI puce DSP ) !
Laissez-moi vous expliquer:
La TI TMSCx6416 DSP a 9 drapeaux du compilateur qui affectent la taille du code.
Pour mon compilateur, lorsque vous allumez l'optimisation au niveau trois, les états de documentation:
Ce qui est software pipelining?
C'est là que le compilateur va faire les choses dans l'assemblée qui font le pour les boucles exécuter beaucoup plus rapide ( jusqu'à deux fois plus rapide ), mais au prix d'une plus grande taille de code. Je suggère la lecture sur software pipelining sur wikipedia ( voir déroulement de la boucle, prologue et épilogue ).
Afin de vérifier votre documentation pour vous assurer que l'optimisation n'est pas de rendre votre code plus.
Une autre suggestion est de chercher les drapeaux du compilateur qui se rapportent à la taille du code. Si vous avez de la taille du code drapeaux du compilateur, assurez-vous de tourner la manivelle jusqu'à la position la plus haute. Habituellement, la compilation de code de taille signifie que votre code s'exécute plus lentement... mais vous pouvez avoir à le faire.