¿Cuántos niveles de optimización de GCC hay?

101

¿Cuántos niveles de optimización de GCC hay?

Probé gcc -O1, gcc -O2, gcc -O3 y gcc -O4

Si utilizo un número realmente grande, no funcionará.

Sin embargo, he intentado

gcc -O100

y compiló.

¿Cuántos niveles de optimización hay?

neuromante
fuente
13
@minitech ¿Qué FM estás mirando? Incluso con man gccCygwin (12000 líneas impares) puede buscar -Oy encontrar todo lo que indican las respuestas a continuación, y más.
Jens
1
@minmaxavg después de leer la fuente, no estoy de acuerdo contigo: cualquier cosa más grande que 3es igual que 3(siempre que no se intdesborde). Mira mi respuesta .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
En realidad, GCC tiene muchos otros indicadores para ajustar las optimizaciones. -fomit-stack-pointer cambiará el código generado.
Basile Starynkevitch

Respuestas:

141

Para ser pedante, hay 8 opciones -O válidas diferentes que puedes darle 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 -Ogpara llevar el total a 8

Desde la página del manual:

  • -O (Igual que -O1)
  • -O0 (no realizar optimización, el valor predeterminado si no se especifica ningún nivel de optimización)
  • -O1 (optimizar mínimamente)
  • -O2 (optimizar más)
  • -O3 (optimizar aún más)
  • -Ofast (optimice 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. Debería ser el nivel de optimización elegido para el ciclo estándar de edición-compilación-depuración, ofreciendo un nivel razonable de optimización mientras se mantiene una compilación rápida y una buena experiencia de depuración. )
  • -Os(. Optimizar para el tamaño -Ospermite que todas las -O2optimizaciones que típicamente no aumentan el tamaño del código También realiza optimizaciones adicionales diseñadas para reducir el tamaño del código.. -OsDesactiva los siguientes parámetros 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 señala @pauldoo, OS X tiene -Oz

Cañada
fuente
23
Si está desarrollando en Mac OS X, hay una -Ozconfiguración adicional que es "optimizar el tamaño de forma más agresiva que -Os": developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo
6
Nota: O3 no es necesariamente mejor que O2 incluso si el nombre lo sugiere. Prueba ambos.
johan d
1
@pauldoo 404 página, reemplazar con archive.org
noɥʇʎԀʎzɐɹƆ
También hay -Ogopciones de optimización que no interfieren con la depuración
einpoklum
47

Vamos a interpretar el código fuente de GCC 5.1 para ver lo que ocurre en -O100ya que no está claro en la página del manual.

Concluiremos que:

  • todo lo anterior -O3hasta INT_MAXes lo mismo que -O3, pero eso podría cambiar fácilmente en el futuro, así que no confíe en él.
  • GCC 5.1 ejecuta un comportamiento indefinido si ingresa números enteros mayores que INT_MAX.
  • el argumento solo puede tener dígitos, o falla correctamente. En particular, esto excluye enteros negativos como-O-1

Centrarse en subprogramas

En primer lugar, recuerde que GCC es sólo un front-end para cpp, as, cc1, collect2. Un rápido ./XXX --helpdice eso solo collect2y cc1toma -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 que -Ose reenvió a ambos cc1y 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 especifican todas las Oopciones. Tenga -O<n>en cuenta cómo está en una familia separada de la otra Os, Ofasty Og.

Cuando construimos, esto genera un options.harchivo que contiene:

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

Como beneficio adicional, mientras buscamos \bO\ndentro common.opt, notamos las líneas:

-optimize
Common Alias(O)

lo que nos enseña que --optimize(doble guión porque comienza con un guión -optimizeen el .optarchivo) es un alias indocumentado para el -Ocual se puede usar como --optimize=3!

Donde se usa OPT_O

Ahora hacemos grep:

git grep -E '\bOPT_O\b'

que nos apunta a dos archivos:

Primero busquemos opts.c

opts.c: optimización_opciones_predeterminadas

Todos los opts.cusos suceden en el interior: default_options_optimization.

Hacemos grep backtrack 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.ces el punto de entrada de cc1. ¡Bueno!

La primera parte de esta función:

  • hace integral_argumentque llama atoia la cadena correspondiente a OPT_Opara analizar el argumento de entrada
  • almacena el valor dentro de opts->x_optimizedonde optsestá a struct gcc_opts.

struct gcc_opts

Después de hacer grepping en vano, notamos que esto structtambién se genera en options.h:

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

de donde x_optimizeviene de las lineas:

Variable
int optimize

presente en common.opt, y que options.c:

struct gcc_options global_options;

por lo que suponemos que esto es lo que contiene todo el estado global de la configuración y int x_optimizees el valor de optimización.

255 es un máximo interno

in opts.c:integral_argument, atoise aplica al argumento de entrada, por lo que INT_MAXes un límite superior. Y si pones algo más grande, parece que GCC ejecuta un comportamiento indefinido de C. ¿Ay?

integral_argumenttambién envuelve atoiy rechaza el argumento si algún carácter no es un dígito. Así que los valores negativos fallan con gracia.

De vuelta 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.awkme encontré 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 sobre el generado options.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 a charpara 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 lo maybe_default_optionsque suena interesante. Lo ingresamos, y luego maybe_default_optiondonde llegamos a un gran interruptor:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

No hay >= 4cheques, lo que indica que 3es el más grande posible.

Luego buscamos la definición de OPT_LEVELS_3_PLUSen 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: tabla_opciones_predeterminadas

opt_levelses tan interesante, que hacemos grep OPT_LEVELS_3_PLUSy encontramos 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 },
    [...]
}

por lo que aquí es donde -Onse codifica el mapeo de optimización específico mencionado en los documentos. ¡Agradable!

Asegúrese de que no haya más usos para x_optimize

El uso principal de x_optimizefue establecer otras opciones de optimización específicas -fdefer_popcomo se documenta en la página de manual. ¿Hay más?

Nosotros grep, y encontramos algunos más. El número es pequeño y, tras una inspección manual, vemos que cada uso solo hace como máximo a x_optimize >= 3, por lo que nuestra conclusión es válida.

lto-wrapper.c

Ahora vamos a la segunda aparición de OPT_O, que estaba en lto-wrapper.c.

LTO significa Optimización de tiempo de enlace, que, como su nombre indica, necesitará una -Oopción y estará vinculada collec2(que es básicamente un enlazador).

De hecho, la primera línea de lto-wrapper.cdice:

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

En este archivo, las OPT_Oocurrencias parecen solo normalizar el valor de Opara pasarlo hacia adelante, así que deberíamos estar bien.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
38

Siete niveles distintos:

  • -O0 (predeterminado): sin optimización.

  • -Oo -O1(lo mismo): Optimiza, pero no dediques demasiado tiempo.

  • -O2: Optimice de forma más agresiva

  • -O3: Optimice de forma más agresiva

  • -Ofast: Equivalente a -O3 -ffast-math. -ffast-mathactiva optimizaciones de punto flotante que no cumplen con los estándares. Esto permite al compilador pretender que los números de coma 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 descargue los desnormales a cero y trate los desnormales como cero, al menos en algunos procesadores, incluidos x86 y x86-64. Los desnormales desencadenan una ruta lenta en muchas FPU, por lo que tratarlos como cero (que no desencadena la ruta lenta) puede ser una gran ganancia de rendimiento.

  • -Os: Optimice el tamaño del código. En realidad, esto puede mejorar la velocidad en algunos casos, debido a un mejor comportamiento de I-cache.

  • -Og: Optimice, pero no interfiera con la depuración. Esto permite un rendimiento no embarazoso para las compilaciones de depuración y está destinado a reemplazar las -O0compilaciones 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 indicadores específicos habilitados por esta optimización.

Para obtener más información, consulte el sitio web de GCC.

Demi
fuente
De hecho, aunque para ser justos con las otras respuestas, ni -Ofast ni -Og existían cuando se escribieron esas respuestas.
Janneb
Entonces, ¿por qué -O100compila entonces?
einpoklum
3
@einpoklum porque GCC trata todo lo que esté por encima de -O3 como igual a -O3.
Demi
Desafortunadamente, todavía obtienes un montón de <optimizado> en el depurador con -Og. Caminar todavía salta al azar. En mi humilde opinión es inútil.
doug65536
3

Cuatro (0-3): consulte el manual de GCC 4.4.2 . Cualquier valor superior es solo -O3, pero en algún momento sobrepasará el límite de tamaño variable.

Tom
fuente
He explorado el código fuente en mi respuesta y estoy de acuerdo con usted. De manera más pedante, GCC parece depender de atoiun comportamiento indefinido, seguido de un 255límite interno.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
4
Considere eliminar su respuesta, ya que es (al menos en estos días) incorrecta.
einpoklum