Quelles sont les méthodes de refactoring permettant de réduire la taille du code compilé?

J’ai une ancienne application de micrologiciel qui nécessite de nouvelles fonctionnalités. La taille de l’application était déjà proche de la capacité de flash limitée de l’appareil et les quelques nouvelles fonctions et variables l’ont poussée à bout. L’activation de l’optimisation du compilateur fait l’affaire, mais le client se méfie de le faire car ils ont déjà provoqué des échecs. Alors, quelles sont les choses communes à rechercher lors de la refactorisation du code C pour produire une sortie plus petite?

  • Utiliser des fonctions de génération au lieu de tables de données, si possible
  • Désactiver les fonctions en ligne
  • Transforme les macros fréquemment utilisées en fonctions
  • Réduisez la résolution pour les variables plus grandes que la taille de la machine native (micro 8 bits, essayez de vous débarrasser des variables 16 et 32 ​​bits – doublons et quadruplent certaines séquences de code)
  • Si le micro a un jeu d’instructions plus petit (Arm thumb), activez-le dans le compilateur
  • Si la mémoire est segmentée (paginée ou non linéaire), alors
    • Réorganisez le code de sorte qu’il soit nécessaire d’utiliser moins d’appels globaux (instructions d’appel plus volumineuses)
    • Réorganisez le code et l’utilisation variable pour éliminer les appels de mémoire globaux
    • Réévaluez l’utilisation de la mémoire globale – si elle peut être placée dans la stack, tant mieux
  • Assurez-vous que vous comstackz avec le débogage désactivé – sur certains processeurs, cela fait une grande différence
  • Compressez les données qui ne peuvent pas être générées à la volée – puis décompressez-les en RAM au démarrage pour un access rapide
  • Explorez les options du compilateur – il se peut que chaque appel soit automatiquement global, mais vous pourrez peut-être le désactiver en toute sécurité fichier par fichier pour réduire la taille (parfois de manière significative)

Si vous avez encore besoin de plus d’espace qu’avec la comstack with optimizations activées, examinez l’assemblage généré par rapport au code non optimisé. Ensuite, réécrivez le code contenant les modifications les plus importantes afin que le compilateur génère les mêmes optimisations basées sur de difficiles réécritures en C avec optimisation désactivée.

Par exemple, vous pouvez avoir plusieurs instructions “if” qui font des comparaisons similaires:

 if(A && B && (C || D)){} if(A && !B && (C || D)){} if(!A && B && (C || D)){} 

Ensuite, créer une nouvelle variable et faire des comparaisons à l’avance sauvera le compilateur de la duplication de code:

 E = (C || D); if(A && B && E){} if(A && !B && E){} if(!A && B && E){} 

C’est l’une des optimisations que le compilateur effectue automatiquement pour vous si vous l’activez. Il y en a beaucoup, beaucoup d’autres, et vous pourriez envisager de lire un peu la théorie du compilateur si vous voulez apprendre à le faire à la main dans le code C.

En règle générale: utilisez votre carte de liens ou vos outils pour déterminer quels sont vos symboles les plus grands / les plus nombreux, puis examinez-les éventuellement à l’aide d’un désassembleur. Vous seriez surpris de ce que vous trouvez de cette façon.

Avec un peu de perl ou similaire, vous pouvez utiliser un fichier .xMAP ou les résultats de “objdump” ou “nm”, et le sortinger de différentes manières pour obtenir des informations pertinentes.


Spécifique aux petits jeux d’instructions: surveillez l’ utilisation du pool littéral . Lors du passage du jeu d’instructions ARM (32 bits par instruction) au jeu d’instructions THUMB (16 bits par instruction) peut être utile sur certains processeurs ARM, cela réduit la taille du champ “immédiat”.

Tout à coup, quelque chose qui serait une charge directe d’un global ou statique devient très indirect; il doit d’abord charger l’adresse du global / static dans un registre, puis charger à partir de celui-ci, plutôt que de simplement encoder l’adresse directement dans l’instruction. Vous obtenez donc quelques instructions supplémentaires et une entrée supplémentaire dans le pool littéral pour quelque chose qui aurait normalement été une instruction.

Une stratégie pour lutter contre cela consiste à regrouper des structures globales et statiques dans des structures; De cette façon, vous ne stockez qu’un seul littéral (l’adresse de votre structure globale) et calculez les compensations à partir de celui-ci, plutôt que de stocker de nombreux littéraux différents lorsque vous accédez à plusieurs statiques / globaux.

Nous avons converti nos classes “singleton” de la gestion de leurs propres pointeurs d’instance en membres d’une grande “struct GlobalTable”, ce qui entraîne une différence notable en termes de taille du code (quelques pour cent) et de performances dans certains cas.


Sinon: gardez un œil sur les structures statiques et les tableaux de données non construites de manière sortingviale. Chacune de celles-ci génère généralement d’énormes quantités de code .sinit (“fonctions invisibles”, si vous préférez) qui sont exécutées avant main () pour remplir correctement ces tableaux. Si vous ne pouvez utiliser que des types de données sortingviaux dans vos statistiques, vous serez bien mieux loti.

C’est encore quelque chose qui peut être facilement identifié en utilisant un outil sur les résultats de “nm” ou “objdump” ou similaire. Si vous avez une tonne de choses .sinit, vous voudrez enquêter!


Oh, et si votre compilateur / éditeur de liens le supporte, n’hésitez pas à activer de manière sélective l’optimisation ou des jeux d’instructions plus petits pour seulement certains fichiers ou fonctions!

Refactoriser le code en double devrait avoir le plus grand impact sur l’empreinte mémoire de votre programme.

Faites attention aux macros. Ils peuvent produire beaucoup de code à partir d’une seule expansion de macro. Si vous trouvez de telles macros, essayez de les réécrire afin de réduire leur taille et de déplacer la fonctionnalité vers des fonctions.

Faites attention à la duplication du code – copié-collé et dupliqué logiquement. Essayez de séparer le code en double en fonctions.

Vérifiez si le compilateur prend en charge l’inline et qu’il peut être désactivé.

Optimisation du compilateur qui déclenche un bug? C’est étrange. Obtenez une carte de votre programme et voyez si vous devriez cibler des données ou du code. Recherchez le code dupliqué. Rechercher du code avec un objective similaire. Un exemple en est le code busybox, qui vise une faible empreinte mémoire.

Il privilégie la taille à la lisibilité, il est donc parfois très moche, avec des gotos, etc.

Les réponses ci-dessus indiquent “Activer l’optimisation du compilateur [réduction de la taille du code]” “. Compte tenu de toute la documentation et de l’expérience que j’ai de la programmation TI DSP pour systèmes intégrés , je sais pertinemment que l’activation de l’optimisation AUGMENTERA la taille de votre code (pour la puce TI DSP)!


Laisse-moi expliquer:

Le DSP TI TMSCx6416 a 9 drapeaux de compilateur qui affecteront la taille de votre code.

  1. 3 drapeaux différents pour l’optimisation
  2. 3 drapeaux différents pour le débogage
  3. 3 drapeaux différents pour la taille du code

Pour mon compilateur, lorsque vous activez le niveau d’optimisation trois, la documentation indique:

  1. La mise en ligne automatique de certaines fonctions se produira -> augmentera la taille du code
  2. Le traitement en pipeline des logiciels est activé -> augmentera la taille du code

Qu’est-ce qu’un logiciel en pipeline?

C’est là que le compilateur fera en assembleur des choses qui feront que les boucles for s’exécuteront beaucoup plus rapidement (jusqu’à deux fois plus vite) mais au prix d’une plus grande taille de code. Je suggère de lire des informations sur les logiciels en pipeline sur wikipedia (recherchez le déroulement de boucle, le prolog et l’épilogue).

Consultez votre documentation pour vous assurer que l’optimisation ne rend pas votre code plus volumineux.


Une autre suggestion consiste à rechercher des indicateurs de compilation liés à la taille du code. Si vous avez des drapeaux de compilation de la taille du code, assurez-vous de les augmenter au maximum. Comstackr pour la taille du code signifie généralement que votre code s’exécutera plus lentement … mais vous devrez peut-être le faire.