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?
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
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:
-O3
jusqu'à INT_MAX
est identique à -O3
, mais cela pourrait facilement changer à l'avenir, alors ne vous fiez pas à lui.INT_MAX
.-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:
integral_argument
qui appelle atoi
sur la chaîne correspondant à OPT_O
pour analyser l'argument d'entréeopts->x_optimize
où opts
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;
[...]
}
où 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.
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.