IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Optimisation de taille du code compilé


Sujet :

C

  1. #1
    Membre averti
    Inscrit en
    Février 2009
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 44
    Par défaut Optimisation de taille du code compilé
    Bonjour,

    Je suis entrain de développer un bout de code, et je souhaiterais que celui-ci soit le plus petit possible en terme de taille (j'ai pas le choix c'est une contrainte qu'on m'a fixé!).

    Bref, notre cher gcc admet le flag -Os spécialement prévu à cette effet et cela me permet de gagner quelques ko par rapport à une version standard.

    Egalement les outils strip et gzexe me permettent de compresser le tout, mais cela est fait après compilation du code.

    Je souhaiterai donc savoir quelles sont les bonnes pratiques (s'il y en a!) pour aboutir à un code optimisé pour la taille. Par exemple j'ai factorisé un grand nombre d'opération par des fonctions, mais au final je ne gagne rien (voir meme le contraire!).


    Donc deux questions :
    1. Comment ça se fait que quand je fais une fonction mon code est plus gros (de qq octets) alors que logiquement (pour moi!) il devrait etre plus petit ?

    2. Avez-vous des recommandations (algorithmie, outils, options de compilation, etc) pour réduire la taille d'un code ?

    Merci
    n0mad

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 105
    Billets dans le blog
    146
    Par défaut
    Bonjour,

    Je vais beaucoup m'interesser à cette question, car je cherche la même chose.
    J'apporte quand même une première pierre à l'édifice.

    Premièrement compilé avec l'option -Os, ( et surtout ne pas oubliez d'enlever le -g )
    Deuxièmement strip , c'est bien , mais il existe un gars qui à fait une version plus approfondie qui s'apelle sstrip ( il a aussi fait d'autre outils ). Pour les distributions debian-like, un paquet qui s'apelle elf-kickers contient sstrip.
    Je connaissais pas gzexe
    J'ai vu une autre technique spécial linux, mais je ne serai pas l'appliquer entièrement. Le principe c'est de :
    - Compresser ses propres fichiers sources ( d'ailleurs il faut enlever tout espaces et autre mises en forme pour gagner des octets , cette fois )
    - Faire un script, qui permet de décompresser les sources, et lancé une compilation puis lancé le programme.

    Je suis d'accord que cette technique est assez loin d'être bonne, et encore plus d'une chose que tu attendais, mais sur le principe, comme un fichier texte est plus facile à compresser, on gagnerai plus... Mais sur la machine hote , il faut un compilateur ... :s

    Donc deux questions :
    1. Comment ça se fait que quand je fais une fonction mon code est plus gros (de qq octets) alors que logiquement (pour moi!) il devrait etre plus petit ?
    2. Avez-vous des recommandations (algorithmie, outils, options de compilation, etc) pour réduire la taille d'un code ?
    Parce que le compilateur transforme ton code en assembleur. Donc certes, tu peux avoir moins de code C/C++ ( ou autre ) mais tu en aura plus en assembleur.
    J'ai vu plusieurs fois que la technique c'est d'aider le compilateur le plus possible. Mais sur ce point je ne m'y connait pas non plus.

    un man gcc , peut te faire découvrir un tas d'option miraculeuse qui peuvent certainement gagner de la place. ( une section entière pour l'optimisation ... des tas de trucs que l'on utilise jamais je vais dire )

    ( J'ai présumé que tu étais sous linux )...
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre émérite
    Inscrit en
    Avril 2007
    Messages
    667
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Avril 2007
    Messages : 667
    Par défaut
    Salut,
    Citation Envoyé par LittleWhite Voir le message
    J'ai vu une autre technique spécial linux, mais je ne serai pas l'appliquer entièrement. Le principe c'est de :
    - Compresser ses propres fichiers sources ( d'ailleurs il faut enlever tout espaces et autre mises en forme pour gagner des octets , cette fois )
    - Faire un script, qui permet de décompresser les sources, et lancé une compilation puis lancé le programme.

    Je suis d'accord que cette technique est assez loin d'être bonne, et encore plus d'une chose que tu attendais, mais sur le principe, comme un fichier texte est plus facile à compresser, on gagnerai plus...
    Euh ... prend un fichier source quelconque, ajoute 100000 lignes blanches et compare le resultat avec le fichier sans les lignes blanches Compresser les sources, indenter differement, ajouter des commentaires, changer la couleur ou la police, tout ce genre de trucs n'ont aucun impact sur la taille du binaire

    Pour gagner de la place, comme deja dit on peut jouer avec les parametres du compilateur: -Os pour gcc, mais aussi des parametres plus exotiques et qui peuvent impacter negativement les performances et la portabilite: empecher le deroulement des boucles, forcer l'alignement / packer les structures, empecher l'inlining...

    Dans le code on peut aussi gagner de la place avec les variables: toujours prendre le plus petit type necessaire (evident mais bon ), utiliser des champs de bits ou des bitmask a la place des booleens ou des tableaux de parametres (quand c'est possible evidemment).

  4. #4
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par n0mad Voir le message
    Donc deux questions :
    1. Comment ça se fait que quand je fais une fonction mon code est plus gros (de qq octets) alors que logiquement (pour moi!) il devrait etre plus petit ?

    2. Avez-vous des recommandations (algorithmie, outils, options de compilation, etc) pour réduire la taille d'un code ?

    1. Eh non, ta réponse n'est pas logique... Quand tu fais une fonction, tu ajoutes du code : déclaration (donc en assembleur un label), plus un return.. Donc le même code porté dans une fonction a au moins 3 instructions supplémentaires (ces 2 + le jmp nécessaire pour aller au label), plus les variables locales..

    2. On t'a déjà donné des pistes plus haut. Sinon, en gros c'est : allocations dynamiques ou tableaux dimensionnés correctement, ré-utilisations de variables (si non signifcatives), usage de biblothèques, évnetuellement bibliothèques dynamiques (DLL). "strip" ne fait qu'enlever les liens de debug ou les chaînes de caractères. Oui cela réduit la taille de l'exécutable. Compiler avec les options -Ox comprend des failles (par exemple à partir de -O3 c'est quasi sûr qu'un certain nombre de fonctions ne marcheront plus correctement, des fois même à partir de -O2). Mais surtout c'est optimisation de la conception et de l'algorithmie. Enfin, les "espaces", "lignes", "indentations", ou "raccourcis d'écriture" (style incrémenter 5 variables dans la ligne for) etc dans le source sont des absurdités totales : la présentation du source n'a rien à voir avec l'exécutable : le compilateur se fiche pas mal des espaces, des tabulations, etc etc.. Et quand il voit "i++", de toutes façons il fait "i = i+1", donc faire "for (i=0,j=0,k=1; i<8,j<5,k<12; i++,j+2,k+3)" sera décomposé par le compilateur... Tout ce que ça fait c'est rendre le code illisible.. (obfuscation).

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 461
    Par défaut
    Citation Envoyé par n0mad Voir le message
    Bref, notre cher gcc admet le flag -Os spécialement prévu à cette effet et cela me permet de gagner quelques ko par rapport à une version standard. Egalement les outils strip et gzexe me permettent de compresser le tout, mais cela est fait après compilation du code.
    Si tu veux essayer d'aller jusqu'au bout sans avoir peur de trop bidouiller, tu peux regarder ce document, par exemple.

    D'ailleurs, cela me rappelle qu'il y a une quinzaine d'années, je me posais déjà la question, alors que je travaillais sous D.O.S., et que mon disque dur ne dépassait pas 170 Mo, et ma mémoire vive 4 Mo. C'était d'ailleurs une bête de course toute neuve (un 486 DX 33), surtout par rapport aux précédentes machines qui avaient occupé le salon.

    À cette époque, les compilateurs produisaient déjà des exécutables d'une taille comparable, ce qui posait plus de problème étant donné l'environnement plus restreint. Je me suis demandé quel pouvait être la taille minimum sous DOS d'un exécutable qui ne faisait rien. On s'est aperçu que le Turbo Pascal, par exemple, porduisait par défaut un exécutable de 6 Ko.

    J'avais émis le postulat qu'on pourrait descendre jusqu'à deux octets en produisant un programme *.COM qui contiendrait uniquement « INT 20h ». Je me suis quand même fait battre : quelqu'un a remarqué que le DOS initialisait, par convention, la pile avec un 0000h. Un « RET » aurait alors eu pour effet de ramener le compteur programme au début du segment, soit sur le PSP. Or, le PSP débutait toujours, par convention, lui aussi, par « INT 20h ». On a donc réussi à faire un exécutable légal long d'un seul et unique octet.

    Donc deux questions :
    1. Comment ça se fait que quand je fais une fonction mon code est plus gros (de qq octets) alors que logiquement (pour moi!) il devrait etre plus petit ?
    Ça dépend de plusieurs choses : si tu n'appelles ta fonction qu'une seule fois, alors ce sera forcément plus coûteux. Il y a évidemment la taille du saut et celle du retour en plus, mais aussi toute la mise en place du cadre de pile. Choses que tu peux éventuellement faire disparaître avec l'option idoine, mais qui rendra bien sûr ton code nettement plus difficile à débugger, et favorisera l'apparition des « schrödinbugs ».

    2. Avez-vous des recommandations (algorithmie, outils, options de compilation, etc) pour réduire la taille d'un code ?
    À partir d'un certain stade, ça dépend énormément du code lui-même., les méthodes « universelles » étant déjà appliquées par ton compilateur. En outre, plus tu vas descendre « bas », moins ces techniques seront portables, puisqu'elles seront dépendantes à la fois de ton système d'exploitation et du processeur que tu utilises.

  6. #6
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    [en même temps]

  7. #7
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 105
    Billets dans le blog
    146
    Par défaut
    Citation Envoyé par tonton fred Voir le message
    Salut,

    Euh ... prend un fichier source quelconque, ajoute 100000 lignes blanches et compare le resultat avec le fichier sans les lignes blanches Compresser les sources, indenter differement, ajouter des commentaires, changer la couleur ou la police, tout ce genre de trucs n'ont aucun impact sur la taille du binaire
    Je me suis fais reprendre deux fois. Je sais bien que dans un cadre normal, toutes les mises en page ne compte pas pour le compilateur. Ce qui est normal car pas du code.
    Mais, je ne sais pas si vous m'avez mal lu , ou je me suis très mal expliquer ( très probable ) , mais c'est que j'expliquai une méthode ( très bizarre ), que j'ai vu, qui est de compresser les sources, puis de les recompiler ( une fois décompresser ) sur la machine de destination.
    Comme il faut mieux un exemple que mes explications vaseuses : http://www.pouet.net/prod.php?which=51725
    Vous telechargez, decompresser...
    Supprimez les deux executables déjà près.
    Vous lancer le stream2.make
    Vous voyez qu'il vous sors un executable. Vous regardez le contenu de stream2.make et unpack.header2.

    Et vous me comprendrez ( normalement )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  8. #8
    Membre émérite
    Inscrit en
    Avril 2007
    Messages
    667
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Avril 2007
    Messages : 667
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Mais, je ne sais pas si vous m'avez mal lu , ou je me suis très mal expliquer ( très probable ) , mais c'est que j'expliquai une méthode ( très bizarre ), que j'ai vu, qui est de compresser les sources, puis de les recompiler ( une fois décompresser ) sur la machine de destination.
    Tu as mal compris ce qu'il se passe dans l'exemple que tu donnes:
    - stream2.make concatene deux fichiers: un script de decompression / compilation et le fichier source compresse dans le fichier steam2
    - ensuite il execute le fichier cree (stream2) qui decompresse les sources (x.c), les compile et execute le binaire (./y)

    Donc oui le "programme" prend moins de place mais ce n'est pas un binaire: c'est un script qui decompresse, compile et execute les sources compressees. La particularite c'est que les sources compressee et le script sont dans le meme fichier.

  9. #9
    Membre chevronné Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Par défaut
    Bonjour,

    Essaie l'optimisation globale (-combine et -fwhole-program) et la profile-guided optimization.

  10. #10
    Membre averti
    Inscrit en
    Février 2009
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 44
    Par défaut
    Bonjour,

    Merci pour vos réponses elles contiennent pleins d'éléments que je ne connaissait pas.

    Pour le coup du code plus gros après ajout de fonctions, effectivement si on réfléchit en assembleur ça semble évident ! Merci


    Juste pour alimenter ce thread, j'ai fait un test très rapide de compilation avec gcc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    # gcc scheduler.c -o scheduler
    # ls -l scheduler
    -rwxr-xr-x 1 root root 24715 Feb 18 12:39 scheduler
     
    # gcc scheduler.c -o scheduler -Os
    # ls -l scheduler
    -rwxr-xr-x 1 root root 20575 Feb 18 12:40 scheduler
     
    # gcc scheduler.c -o scheduler -s
    # ls -l scheduler
    -rwxr-xr-x 1 root root 22192 Feb 18 12:40 scheduler
     
    # gcc scheduler.c -o scheduler -Os -s
    # ls -l scheduler
    -rwxr-xr-x 1 root root 18064 Feb 18 12:40 scheduler
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    # gcc scheduler.c -o scheduler -Os 
    # ls -l scheduler
    -rwxr-xr-x 1 root root 20575 Feb 18 12:44 scheduler
    # strip scheduler
    # ls -l scheduler
    -rwxr-xr-x 1 root root 18064 Feb 18 12:44 scheduler
    #
    En d'autres termes, l'options "-s" de gcc fait la même chose que "strip".

  11. #11
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    les options d'optimisations (-O2, -O3, etc) sont à mettre AVANT le .c

  12. #12
    Membre averti
    Inscrit en
    Février 2009
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 44
    Par défaut
    Oui certes.....mais les développeurs de GCC étant des personnes très sages ce sont dit "tiens il existe des gros boulets qui vont pas forcément le mettre avant..." donc il l'ont pris en compte :p

  13. #13
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 105
    Billets dans le blog
    146
    Par défaut
    Toujours que tu pouvait faire aussi le test avec un sstrip :p
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

Discussions similaires

  1. Quelle optimisation en taille d'écran pour les sites
    Par JeanMi66 dans le forum Webdesign & Ergonomie
    Réponses: 26
    Dernier message: 16/09/2008, 21h37
  2. Réponses: 2
    Dernier message: 25/07/2006, 11h52
  3. Code compilable sous Windows et Unix
    Par xzed dans le forum C
    Réponses: 9
    Dernier message: 16/05/2006, 16h06
  4. Experts Mysql : Optimiser une requete sur codes postaux
    Par El Riiico dans le forum Requêtes
    Réponses: 6
    Dernier message: 20/01/2006, 18h00
  5. [CODE] Compilation conditionnelle ?
    Par Cornell dans le forum Langage
    Réponses: 3
    Dernier message: 16/09/2003, 18h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo