Combien de niveaux d'optimisation GCC existe-t-il?


101

Combien de niveaux d'optimisation GCC existe-t-il?

J'ai essayé gcc -O1, gcc -O2, gcc -O3 et gcc -O4

Si j'utilise un très grand nombre, cela ne fonctionnera pas.

Cependant, j'ai essayé

gcc -O100

et il a été compilé.

Combien de niveaux d'optimisation y a-t-il?


13
@minitech Quelle FM regardez-vous? Même avec man gccsur Cygwin (12000 lignes impaires), vous pouvez rechercher -Oet trouver tout ce que les réponses ci-dessous indiquent, et plus encore.
Jens

1
@minmaxavg après avoir lu la source, je ne suis pas d'accord avec vous: tout ce qui est plus grand que 3est le même que 3(tant qu'il ne intdéborde pas ). Voyez ma réponse .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
En fait, GCC a de nombreux autres indicateurs pour affiner les optimisations. -fomit-stack-pointer changera le code généré.
Basile Starynkevitch

Réponses:


141

Pour être pédant, il existe 8 options -O valides différentes que vous pouvez donner à gcc, bien qu'il y en ait qui signifient la même chose.

La version originale de cette réponse indiquait qu'il y avait 7 options. GCC a depuis ajouté -Ogpour porter le total à 8

Depuis la page de manuel:

  • -O (Identique à -O1)
  • -O0 (ne pas optimiser, la valeur par défaut si aucun niveau d'optimisation n'est spécifié)
  • -O1 (optimiser au minimum)
  • -O2 (optimiser davantage)
  • -O3 (optimiser encore plus)
  • -Ofast (optimiser de manière très agressive au point de rompre la conformité aux normes)
  • -Og (Optimiser l'expérience de débogage. -Og permet des optimisations qui n'interfèrent pas avec le débogage. Cela devrait être le niveau d'optimisation de choix pour le cycle standard d'édition-compilation-débogage, offrant un niveau d'optimisation raisonnable tout en maintenant une compilation rapide et une bonne expérience de débogage. )
  • -Os (Optimiser pour la taille. -Os permet à toutes les -O2optimisations qui n'augmentent généralement pas la taille du code Il effectue également d' autres optimisations conçues pour réduire la taille du code.. -OsDésactive les options d'optimisation suivantes: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

Il peut également y avoir des optimisations spécifiques à la plate-forme, comme le note @pauldoo, OS X a -Oz


23
Si vous développez sur Mac OS X, il existe un -Ozparamètre supplémentaire qui est "optimiser la taille de manière plus agressive que -Os": developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo

6
Remarque: O3 n'est pas nécessairement meilleur que O2 même si son nom l'indique. Essayez les deux.
johan d

1
@pauldoo 404 page, remplacez par archive.org
noɥʇʎԀʎzɐɹƆ

Il y a aussi -Ogtoutes les options d'optimisation qui n'interfèrent pas avec le débogage
einpoklum

47

Nous allons interpréter le code source de GCC 5.1 pour voir ce qui se passe sur-O100 , car il est pas clair sur la page de manuel.

Nous conclurons que:

  • quoi que ce soit au- dessus -O3jusqu'à INT_MAXest le même que -O3, mais que , dans l'avenir pourrait facilement changer, alors ne comptez pas sur elle.
  • GCC 5.1 exécute un comportement non défini si vous entrez des entiers supérieurs à INT_MAX.
  • l'argument ne peut avoir que des chiffres, ou il échoue normalement. En particulier, cela exclut les entiers négatifs comme-O-1

Focus sur les sous-programmes

Tout d' abord se rappeler que le GCC est juste un front-end pour cpp, as, cc1, collect2. Un rapide ./XXX --helpdit cela seulement collect2et cc1prenons -O, alors concentrons-nous sur eux.

Et:

gcc -v -O100 main.c |& grep 100

donne:

COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.

donc a -Oété transmis à la fois cc1et collect2.

O en commun.opt

common.opt est un format de description d'option CLI spécifique à GCC décrit dans la documentation interne et traduit en C par opth-gen.awk et optc-gen.awk .

Il contient les lignes intéressantes suivantes:

O
Common JoinedOrMissing Optimization
-O<number>  Set optimization level to <number>

Os
Common Optimization
Optimize for space rather than speed

Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance

Og
Common Optimization
Optimize for debugging experience rather than speed or size

qui spécifient toutes les Ooptions. Notez comment se -O<n>trouve dans une famille distincte de l'autre Os, Ofastet Og.

Lorsque nous construisons, cela génère un options.hfichier qui contient:

OPT_O = 139,                               /* -O */
OPT_Ofast = 140,                           /* -Ofast */
OPT_Og = 141,                              /* -Og */
OPT_Os = 142,                              /* -Os */

En prime, pendant que nous cherchons à l' \bO\nintérieur, common.optnous remarquons les lignes:

-optimize
Common Alias(O)

ce qui nous apprend que --optimize(double tiret car il commence par un tiret -optimizesur le .optfichier) est un alias non documenté pour -Olequel peut être utilisé comme --optimize=3!

Où OPT_O est utilisé

Maintenant, nous grep:

git grep -E '\bOPT_O\b'

ce qui nous renvoie à deux fichiers:

Commençons par traquer opts.c

opts.c: default_options_optimization

Tout opts.c les usages se produisent à l' intérieur: default_options_optimization.

Nous faisons un retour en arrière pour voir qui appelle cette fonction, et nous voyons que le seul chemin du code est:

  • main.c:main
  • toplev.c:toplev::main
  • opts-global.c:decode_opts
  • opts.c:default_options_optimization

et main.c est le point d'entrée de cc1. Bien!

La première partie de cette fonction:

  • fait integral_argumentqui appelleatoi la chaîne correspondant à OPT_Opour analyser l'argument d'entrée
  • stocke la valeur à l'intérieur opts->x_optimizeoptsest a struct gcc_opts.

struct gcc_opts

Après avoir vainement greffé, nous remarquons que ceci structest également généré à options.h:

struct gcc_options {
    int x_optimize;
    [...]
}

d'où x_optimizevient les lignes:

Variable
int optimize

présent dans common.opt, et que options.c:

struct gcc_options global_options;

on suppose donc que c'est ce qui contient tout l'état global de la configuration, et int x_optimize la valeur d'optimisation.

255 est un maximum interne

in opts.c:integral_argument, atoiest appliqué à l'argument d'entrée, de même INT_MAXqu'une limite supérieure. Et si vous mettez quelque chose de plus gros, il semble que GCC exécute un comportement C indéfini. Aie?

integral_argumentencapsule également finement atoiet rejette l'argument si un caractère n'est pas un chiffre. Les valeurs négatives échouent donc gracieusement.

De retour opts.c:default_options_optimization, nous voyons la ligne:

if ((unsigned int) opts->x_optimize > 255)
  opts->x_optimize = 255;

afin que le niveau d'optimisation soit tronqué à 255. En lisant, opth-gen.awkj'étais tombé sur:

# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.

et sur le généré options.h:

struct GTY(()) cl_optimization
{
  unsigned char x_optimize;

ce qui explique pourquoi la troncature: les options doivent également être transmises vers cl_optimization, qui utilise unchar pour économiser de l'espace. Donc, 255 est en fait un maximum interne.

opts.c: peut-être_default_options

De retour à opts.c:default_options_optimization, nous trouvons maybe_default_optionsce qui semble intéressant. Nous y entrons, puis maybe_default_optionnous atteignons un gros interrupteur:

switch (default_opt->levels)
  {

  [...]

  case OPT_LEVELS_1_PLUS:
    enabled = (level >= 1);
    break;

  [...]

  case OPT_LEVELS_3_PLUS:
    enabled = (level >= 3);
    break;

Il n'y a pas de >= 4contrôle, ce qui indique que 3c'est le plus grand possible.

Ensuite, nous recherchons la définition de OPT_LEVELS_3_PLUSin common-target.h:

enum opt_levels
{
  OPT_LEVELS_NONE, /* No levels (mark end of array).  */
  OPT_LEVELS_ALL, /* All levels (used by targets to disable options
                     enabled in target-independent code).  */
  OPT_LEVELS_0_ONLY, /* -O0 only.  */
  OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og.  */
  OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og.  */
  OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og.  */
  OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os.  */
  OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og.  */
  OPT_LEVELS_3_PLUS, /* -O3 and above.  */
  OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os.  */
  OPT_LEVELS_SIZE, /* -Os only.  */
  OPT_LEVELS_FAST /* -Ofast only.  */
};

Ha! C'est un indicateur fort qu'il n'y a que 3 niveaux.

opts.c: default_options_table

opt_levelsest si intéressant, que nous grep OPT_LEVELS_3_PLUS, et tombons sur opts.c:default_options_table:

static const struct default_options default_options_table[] = {
    /* -O1 optimizations.  */
    { OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
    [...]

    /* -O3 optimizations.  */
    { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
    [...]
}

c'est donc là que le -Onmappage d'optimisation spécifique mentionné dans la documentation est codé. Agréable!

Assurez-vous qu'il n'y a plus d'utilisations pour x_optimize

L'utilisation principale de x_optimizeétait de définir d'autres options d'optimisation spécifiques telles -fdefer_popque décrites dans la page de manuel. Y en a-t-il plus?

Nous grep, et en trouver quelques autres. Le nombre est petit, et après une inspection manuelle, nous voyons que chaque utilisation ne fait qu'au plus un x_optimize >= 3, donc notre conclusion est valable.

lto-wrapper.c

Nous passons maintenant à la deuxième occurrence de OPT_O, qui était enlto-wrapper.c .

LTO signifie Link Time Optimization, qui, comme son nom l'indique, aura besoin d'une -Ooption et sera lié àcollec2 (qui est essentiellement un éditeur de liens).

En fait, la première ligne de lto-wrapper.cdit:

/* Wrapper to call lto.  Used by collect2 and the linker plugin.

Dans ce fichier, les OPT_Ooccurrences semblent ne normaliser que la valeur de Opour la transmettre, donc ça devrait aller.


38

Sept niveaux distincts:

  • -O0 (par défaut): aucune optimisation.

  • -Oou -O1(même chose): Optimiser, mais ne passez pas trop de temps.

  • -O2: Optimiser plus agressivement

  • -O3: Optimiser le plus agressivement

  • -Ofast: Équivalent à -O3 -ffast-math. -ffast-mathdéclenche des optimisations en virgule flottante non conformes aux normes. Cela permet au compilateur de prétendre que les nombres à virgule flottante sont infiniment précis, et que l'algèbre sur eux suit les règles standard de l'algèbre des nombres réels. Il indique également au compilateur de dire au matériel de vider les dénormalités à zéro et de traiter les dénormalités comme zéro, au moins sur certains processeurs, y compris x86 et x86-64. Les dénormalités déclenchent un chemin lent sur de nombreux FPU, et donc les traiter comme zéro (ce qui ne déclenche pas le chemin lent) peut être une grande victoire en termes de performances.

  • -Os: Optimiser pour la taille du code. Cela peut en fait améliorer la vitesse dans certains cas, en raison d'un meilleur comportement I-cache.

  • -Og: Optimisez, mais n'interférez pas avec le débogage. Cela permet des performances non gênantes pour les versions de débogage et est destiné à remplacer les -O0versions de débogage.

Il existe également d'autres options qui ne sont activées par aucune de celles-ci et qui doivent être activées séparément. Il est également possible d'utiliser une option d'optimisation, mais de désactiver des indicateurs spécifiques activés par cette optimisation.

Pour plus d'informations, consultez le site Web de GCC.


En effet, bien que pour être juste avec les autres réponses, ni -Ofast ni -Og n'existaient lorsque ces réponses ont été écrites.
janneb

Alors pourquoi -O100compile-t-il alors?
einpoklum

3
@einpoklum car GCC traite tout ce qui est au-dessus de -O3 comme égal à -O3.
Demi

Malheureusement, vous obtenez toujours une tonne de <optimisé> dans le débogueur avec -Og. Le pas saute toujours au hasard. C'est inutile à mon humble avis.
doug65536

3

Quatre (0-3): voir le manuel GCC 4.4.2 . Tout ce qui est supérieur est juste -O3, mais à un moment donné, vous dépasserez la limite de taille variable.


J'ai exploré le code source dans ma réponse et je suis d'accord avec vous. Plus pédantiquement, GCC semble s'appuyer sur atoiun comportement indéfini, suivi d'une 255limite interne.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

4
Veuillez envisager de supprimer votre réponse, car elle est (au moins ces jours-ci) incorrecte.
einpoklum
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.