c - site - seo off page
¿Cuántos niveles de optimización de GCC hay? (4)
Cuatro (0-3): Consulte el manual GCC 4.4.2. Cualquier cosa más alta es solo -O3, pero en algún momento se desbordará el límite de tamaño variable.
¿Cuántos niveles de optimización de GCC hay?
Probé gcc -O1, gcc -O2, gcc -O3 y gcc -O4
Si uso un número realmente grande, no funcionará.
Sin embargo, lo he intentado
gcc -O100
y compilado.
¿Cuántos niveles de optimización hay?
Para ser pedante, hay 8 opciones -O válidas diferentes que puedes dar a gcc, aunque hay algunas que significan lo mismo.
La versión original de esta respuesta indicó que había 7 opciones. Desde entonces, GCC ha agregado -Og
para llevar el total a 8
Desde la página man:
-
-O
(Igual que-O1
) -
-O0
(no hacer optimización, por defecto si no se especifica ningún nivel de optimización) -
-O1
(optimizar al mínimo) -
-O2
(optimizar más) -
-O3
(optimizar aún más) -
-Ofast
(optimizar de forma muy agresiva hasta el punto de romper el cumplimiento estándar) -
-Og
(Optimice la experiencia de depuración. -Og habilita optimizaciones que no interfieren con la depuración. Debe ser el nivel de optimización de elección para el ciclo de compilación-compilación-depuración estándar, que ofrece un nivel razonable de optimización manteniendo una compilación rápida y una buena depuración experiencia.) -
-Os
(Optimizar para el tamaño.-Os
habilita todas-O2
optimizaciones de-O2
que normalmente no aumentan el tamaño del código. También realiza optimizaciones adicionales diseñadas para reducir el tamaño del código.-Os
los siguientes indicadores de optimización:-falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version
)
También puede haber optimizaciones específicas de la plataforma, como notas de @pauldoo, OS X tiene -Oz
Siete niveles distintos:
-O0
(predeterminado): sin optimización.-O
o-O1
(lo mismo): optimiza, pero no gastes demasiado tiempo.-O2
: Optimizar más agresivamente-O3
: Optimizar de forma más agresiva-Ofast
: Equivalente a-O3 -ffast-math
.-ffast-math
activa optimizaciones de punto flotante que no cumplen con los estándares. Esto le permite al compilador pretender que los números de punto flotante son infinitamente precisos, y que el álgebra en ellos sigue las reglas estándar del álgebra de números reales. También le dice al compilador que le diga al hardware que purgue los denormales a cero y trate los denormales como cero, al menos en algunos procesadores, incluidos x86 y x86-64. Los denormales desencadenan un camino lento en muchas FPU, por lo que tratarlos como cero (que no desencadena la ruta lenta) puede ser una gran ganancia de rendimiento.-Os
: Optimizar para el tamaño del código. Esto en realidad puede mejorar la velocidad en algunos casos, debido a un mejor comportamiento de I-caché.-Og
: Optimiza, pero no interfiere con la depuración. Esto permite un rendimiento no embarazoso para las compilaciones de depuración y está destinado a reemplazar-O0
para-O0
de depuración.
También hay otras opciones que no están habilitadas por ninguno de estos y deben habilitarse por separado. También es posible utilizar una opción de optimización, pero deshabilitar los indicadores específicos habilitados por esta optimización.
Para obtener más información, consulte el sitio web de GCC.
Interpretemos el código fuente de GCC 5.1 para ver qué sucede en -O100
ya que no está claro en la página de manual.
Concluiremos que:
- cualquier cosa por encima de
INT_MAX
hastaINT_MAX
es lo mismo que-O3
, pero eso podría cambiar fácilmente en el futuro, así que no confíe en ello. - GCC 5.1 ejecuta un comportamiento indefinido si ingresa enteros más grandes que
INT_MAX
. - el argumento solo puede tener dígitos, o falla con gracia. En particular, esto excluye enteros negativos como
-O-1
Centrarse en los subprogramas
Primero recuerde que GCC es solo un front-end para cpp
, as
, cc1
, collect2
. Un rápido ./XXX --help
dice que solo collect2
y cc1
toman -O
, así que centrémonos en ellos.
Y:
gcc -v -O100 main.c |& grep 100
da:
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.
por lo tanto, se reenvió a cc1
y collect2
.
O en common.opt
common.opt es un formato de descripción de opción CLI específico de GCC descrito en la documentación interna y traducido a C por opth-gen.awk y optc-gen.awk .
Contiene las siguientes líneas interesantes:
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
que especifica todas las opciones O
Observe cómo -O<n>
está en una familia separada de los otros Os
, Ofast
y Og
.
Cuando construimos, esto genera un archivo options.h
que contiene:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Como beneficio adicional, mientras buscamos /bO/n
dentro de common.opt
notamos las líneas:
-optimize
Common Alias(O)
que nos enseña que --optimize
(doble guion porque comienza con un guion - -optimize
en el archivo .opt
) es un alias no documentado para -O
que se puede usar como --optimize=3
!
Donde se usa OPT_O
Ahora grep:
git grep -E ''/bOPT_O/b''
que nos señala dos archivos:
Busquemos primero opts.c
opts.c: optimización_opciones_optimización
Todos los usos opts.c
ocurren dentro de: default_options_optimization
.
Nos volvemos rápidamente para ver quién llama a esta función, y vemos que la única ruta de código es:
-
main.c:main
-
toplev.c:toplev::main
-
opts-global.c:decode_opts
-
opts.c:default_options_optimization
y main.c
es el punto de entrada de cc1
. ¡Bueno!
La primera parte de esta función:
- hace
integral_argument
que llamaatoi
en la cadena correspondiente aOPT_O
para analizar el argumento de entrada - almacena el valor dentro de
opts->x_optimize
dondeopts
es unastruct gcc_opts
.
struct gcc_opts
Después de desgranar en vano, notamos que esta struct
también se genera en options.h
:
struct gcc_options {
int x_optimize;
[...]
}
donde x_optimize
proviene de las líneas:
Variable
int optimize
presente en common.opt
, y esa options.c
:
struct gcc_options global_options;
así que supongo que esto es lo que contiene el estado global de la configuración completa, y int x_optimize
es el valor de optimización.
255 es un máximo interno
en opts.c:integral_argument
, atoi
se aplica al argumento de entrada, por lo que INT_MAX
es un límite superior. Y si pone algo más grande, parece que GCC ejecuta C comportamiento indefinido. ¿Ay?
integral_argument
también ajusta atoi
y rechaza el argumento si cualquier carácter no es un dígito. Entonces los valores negativos fallan con gracia.
Volviendo a opts.c:default_options_optimization
, vemos la línea:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
de modo que el nivel de optimización se trunca a 255
. Mientras leía opth-gen.awk
me opth-gen.awk
con:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
y en las options.h
generadas.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
lo que explica por qué el truncamiento: las opciones también deben reenviarse a cl_optimization
, que usa un char
para ahorrar espacio. Entonces 255 es un máximo interno en realidad.
opts.c: maybe_default_options
Volviendo a opts.c:default_options_optimization
, nos encontramos con maybe_default_options
que suena interesante. Lo ingresamos, y luego maybe_default_option
donde alcanzamos un gran cambio:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
No hay >= 4
controles, lo que indica que 3
es el mayor posible.
Luego buscamos la definición de OPT_LEVELS_3_PLUS
en 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. */
};
¡Decir ah! Este es un fuerte indicador de que solo hay 3 niveles.
opts.c: default_options_table
opt_levels
es tan interesante que grep OPT_LEVELS_3_PLUS
, y nos encontramos con 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 },
[...]
}
así que aquí es donde está codificada la asignación de optimización " -On
a la optimización específica mencionada en los documentos. ¡Bonito!
Asegúrate de que no hay más usos para x_optimize
El uso principal de x_optimize
fue establecer otras opciones de optimización específicas como -fdefer_pop
como se documenta en la página del manual. ¿Hay más?
Nos grep
, y encontramos algunos más. El número es pequeño, y luego de la inspección manual vemos que cada uso solo tiene un máximo de x_optimize >= 3
, por lo que nuestra conclusión es válida.
lto-wrapper.c
Ahora vamos por la segunda aparición de OPT_O
, que estaba en lto-wrapper.c
.
LTO significa Link Time Optimization, que como su nombre indica va a necesitar una opción -O
, y estará vinculado a collec2
(que básicamente es un enlazador).
De hecho, la primera línea de lto-wrapper.c
dice:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
En este archivo, las apariciones de OPT_O
parecen normalizar el valor de O
para pasarlo, por lo que deberíamos estar bien.