web-dev-qa-db-fra.com

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

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 compilé.

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

86
neuromancer

Pour être pédant, il y a 8 différentes options -O valides que vous pouvez donner à gcc, bien que certaines signifient la même chose.

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

Depuis la page de manuel:

  • -O (Pareil que -O1)
  • -O0 (ne pas optimiser, la valeur par défaut si aucun niveau d'optimisation n'est spécifié)
  • -O1 (optimiser au minimum)
  • -O2 (optimisez davantage)
  • -O3 (optimisez encore plus)
  • -Ofast (optimisation très agressive au point de briser la conformité standard)
  • -Og (Optimiser l'expérience de débogage. -Og permet des optimisations qui n'interfèrent pas avec le débogage. Ce devrait être le niveau d'optimisation de choix pour le cycle d'édition-compilation-débogage standard, offrant un niveau d'optimisation raisonnable tout en maintenant une compilation rapide et un bon débogage. expérience.)
  • -Os (Optimiser pour la taille. -Os active tous les -O2 optimisations 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. -Os désactive les indicateurs d'optimisation suivants: -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

120
Glen

Interprétons le code source de GCC 5.1 pour voir ce qui se passe sur -O100 Car il n'est pas clair sur la page de manuel.

Nous conclurons que:

  • tout ce qui dépasse -O3 jusqu'à INT_MAX est identique à -O3, mais cela pourrait facilement changer à l'avenir, alors ne vous fiez pas à lui.
  • 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 gracieusement. En particulier, cela exclut les entiers négatifs comme -O-1

Focus sur les sous-programmes

Souvenez-vous d'abord que GCC n'est qu'un frontal pour cpp, as, cc1, collect2. Un rapide ./XXX --help Indique que seuls collect2 Et cc1 Prennent -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.

-O a donc été transféré à la fois cc1 et collect2.

O dans common.opt

common.opt est un format de description d'options 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 options O. Notez comment -O<n> Est dans une famille distincte des autres Os, Ofast et Og.

Lorsque nous construisons, cela génère un fichier options.h Qui contient:

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

En prime, pendant que nous recherchons \bO\n À l'intérieur de common.opt, Nous remarquons les lignes:

-optimize
Common Alias(O)

qui nous apprend que --optimize (double tiret car il commence par un tiret -optimize sur le fichier .opt) est un alias non documenté pour -O qui peut être utilisé comme --optimize=3!

Où OPT_O est utilisé

Maintenant on grep:

git grep -E '\bOPT_O\b'

ce qui nous pointe vers deux fichiers:

Voyons d'abord opts.c

opts.c: options_optimisation_par défaut

Toutes les utilisations de opts.c 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 de 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_argument qui appelle atoi sur la chaîne correspondant à OPT_O pour analyser l'argument d'entrée
  • stocke la valeur dans opts->x_optimizeopts est un struct gcc_opts.

struct gcc_opts

Après avoir salué en vain, nous remarquons que ce struct est également généré à options.h:

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

x_optimize vient des lignes:

Variable
int optimize

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

struct gcc_options global_options;

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

255 est un maximum interne

dans opts.c:integral_argument, atoi est appliqué à l'argument d'entrée, donc INT_MAX est une limite supérieure. Et si vous mettez quelque chose de plus grand, il semble que GCC exécute un comportement C indéfini. Aie?

integral_argument Enveloppe également finement atoi et 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.awk, J'é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 options.h généré:

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

ce qui explique pourquoi la troncature: les options doivent également être transmises à cl_optimization, qui utilise un char 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 tombons sur maybe_default_options Ce qui semble intéressant. Nous le saisissons, puis maybe_default_option Où nous 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 contrôle >= 4, Ce qui indique que 3 Est le plus grand possible.

Ensuite, nous recherchons la définition de OPT_LEVELS_3_PLUS Dans 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_levels Est si intéressant, que nous saluons 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 -On vers un mappage d'optimisation spécifique mentionné dans les documents 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 comme -fdefer_pop Comme indiqué sur la page de manuel. Y en a-t-il d'autres?

Nous grep, et en trouvons quelques autres. Le nombre est petit, et lors d'une inspection manuelle, nous constatons que chaque utilisation ne fait au plus qu'un x_optimize >= 3, Donc notre conclusion est valable.

lto-wrapper.c

Maintenant, nous allons pour la deuxième occurrence de OPT_O, Qui était dans lto-wrapper.c.

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

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

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

Dans ce fichier, les occurrences de OPT_O Semblent normaliser uniquement la valeur de O pour la transmettre, donc nous devrions être bien.

Sept niveaux distincts:

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

  • -O ou -O1 (même chose): Optimisez, mais ne passez pas trop de temps.

  • -O2: Optimiser de manière plus agressive

  • -O3: Optimiser le plus agressivement

  • -Ofast: Équivalent à -O3 -ffast-math. -ffast-math dé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 leur algèbre 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énormals à zéro et de traiter les dénormals comme zéro, au moins sur certains processeurs, y compris x86 et x86-64. Les dénormals déclenchent un chemin lent sur de nombreuses FPU, et donc les traiter comme zéro (ce qui ne déclenche pas le chemin lent) peut être un gros gain 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 du cache I.

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

Il existe également d'autres options qui ne sont activées par aucun d'entre eux et doivent être activées séparément. Il est également possible d'utiliser une option d'optimisation, mais désactivez les indicateurs spécifiques activés par cette optimisation.

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

38
Demi

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

3
Tom