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

11 minutos de lectura

avatar de usuario
neuromante

Cuántos CCG ¿Qué niveles de optimización hay?

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

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

Sin embargo, he intentado

gcc -O100

y compiló.

¿Cuántos niveles de optimización hay?

  • @minitech ¿Qué FM estás mirando? Incluso con man gcc en Cygwin (12000 líneas impares) puedes buscar -O y encuentra todo lo que dicen las respuestas a continuación, y algo más.

    – Jens

    25 de julio de 2012 a las 13:32

  • @minmaxavg después de leer la fuente, no estoy de acuerdo contigo: cualquier cosa más grande que 3 es lo mismo que 3 (siempre y cuando no int Desbordamiento). Mira mi respuesta.

    – Ciro Santilli Путлер Капут 六四事

    18 mayo 2015 a las 16:17

  • En realidad, GCC tiene muchas otras banderas para optimizar las optimizaciones. -fomit-stack-pointer cambiará el código generado.

    – Basile Starynkevitch

    25 de junio de 2015 a las 16:27


avatar de usuario
Cañada

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 decía que había 7 opciones. GCC ha añadido desde entonces -Og para llevar el total a 8

Desde el página man:

  • -O (Igual que -O1)
  • -O0 (sin optimización, el valor predeterminado si no se especifica un nivel de optimización)
  • -O1 (optimizar mínimamente)
  • -O2 (optimizar más)
  • -O3 (optimizar aún más)
  • -Ofast (optimizar muy agresivamente hasta el punto de romper el cumplimiento estándar)
  • -Og (Optimizar la experiencia de depuración. -Og permite 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, que ofrece un nivel razonable de optimización mientras mantiene una compilación rápida y una buena experiencia de depuración. )
  • -Os (Optimizar para el tamaño. -Os habilita todo -O2 optimizaciones 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 deshabilita 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 señala @pauldoo, OS X tiene -Oz

  • Si está desarrollando en Mac OS X, hay un adicional -Oz configuración que es “optimizar para el tamaño más agresivamente que -Os“: desarrollador.apple.com/mac/library/DOCUMENTACIÓN/DeveloperTools/…

    – Pauldoo

    5 de mayo de 2010 a las 10:54

  • Nota: O3 no es necesariamente mejor que O2 incluso si el nombre lo sugiere. Prueba ambos.

    – johan d

    19 de septiembre de 2013 a las 14:04


  • @pauldoo página 404, reemplazar con archive.org

    – noɥʇʎ ʎzɐɹƆ

    6 de julio de 2016 a las 16:58

  • @pauldoo enlace de trabajo gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Optimize-Options.html

    –Max MacLeod

    9 de julio de 2021 a las 12:53

  • Llamar a “Os” optimizar para el tamaño es engañoso en mi opinión, ya que todavía está optimizando principalmente para la velocidad, pero simplemente omite o altera ciertas optimizaciones que, de lo contrario, pueden conducir a un aumento del tamaño del código. Explicaste esto lo suficientemente bien en tu texto, solo señalando un disgusto que tengo en general al decir que significa “optimizar para el tamaño”, lo que implica que es lo opuesto a optimizar para la velocidad. “O0” nunca debe usarse, ya que genera un código ridículo como algo de un compilador de la década de 1970, y prácticamente cualquier razón restante para usarlo se ha ido ahora que existe “Og”.

    – thomasrutter

    11 de agosto de 2021 a las 7:08


avatar de usuario
Ciro Santilli Путлер Капут 六四事

Interpretemos el código fuente de GCC 5.1

Trataremos de entender lo que sucede en -O100ya que no está claro en la página del manual.

Concluiremos que:

  • cualquier cosa por encima -O3 hasta INT_MAX es lo mismo que -O3pero 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 números enteros mayores 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 una interfaz para cpp, as, cc1, collect2. Un rápido ./XXX --help dice que solo collect2 y cc1 llevar -Oasí 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.

entonces -O fue enviado a ambos cc1 y collect2.

O en común.optar

común.optar es un formato de descripción de opción CLI específico de GCC descrito en el 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 todos los O opciones Tenga en cuenta cómo -O<n> está en una familia separada de la otra Os, Ofast y Og.

Cuando construimos, esto genera un options.h archivo 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 en el interior common.opt notamos las líneas:

-optimize
Common Alias(O)

que nos enseña que --optimize (doble guión porque comienza con un guión -optimize sobre el .opt archivo) es un alias no documentado para -O que se puede utilizar como --optimize=3!

Donde se usa OPT_O

Ahora hacemos grep:

git grep -E '\bOPT_O\b'

lo que nos apunta a dos archivos:

Primero busquemos opts.c

opts.c:opciones_predeterminadas_optimización

Todos opts.c los usos ocurren dentro: 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.c es el punto de entrada de cc1. ¡Bien!

La primera parte de esta función:

  • lo hace integral_argument que llama atoi en la cadena correspondiente a OPT_O para analizar el argumento de entrada
  • almacena el valor dentro opts->x_optimize donde opts es un struct gcc_opts.

estructura gcc_opts

Después de grepping en vano, notamos que este struct también se genera en options.h:

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

donde x_optimize viene de las lineas:

Variable
int optimize

presentar en common.opty eso options.c:

struct gcc_options global_options;

entonces suponemos que esto es lo que contiene el estado global de configuración completo, 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 un comportamiento indefinido de C. ¿Ay?

integral_argument también envuelve finamente atoi y rechaza el argumento si algún carácter no es un dígito. Así que los valores negativos fallan con gracia.

De regreso opts.c:default_options_optimizationvemos 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 leo opth-gen.awk me habia topado 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 lo generado options.h:

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

lo que explica por qué el truncamiento: las opciones también deben enviarse a cl_optimizationque utiliza un char para ahorrar espacio. Así que 255 es un máximo interno en realidad.

opts.c:quizás_opciones_predeterminadas

De regreso opts.c:default_options_optimizationnos encontramos maybe_default_options que suena interesante. Lo ingresamos y luego maybe_default_option donde 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 existen >= 4 cheques, 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: tabla_de_opciones_predeterminada

opt_levels es tan interesante, que hacemos grep OPT_LEVELS_3_PLUSy encontrarme 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 el -On Se 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_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?

Nosotros grep, y encontrar algunos más. El número es pequeño, y tras la inspección manual vemos que cada uso solo hace como máximo un x_optimize >= 3por lo que nuestra conclusión se mantiene.

lto-wrapper.c

Ahora vamos por la segunda aparición de OPT_Oque estaba en lto-wrapper.c.

LTO significa Optimización del Tiempo de Enlace, que como su nombre indica va a necesitar un -O opción, y estará vinculado a collec2 (que es básicamente 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, el OPT_O ocurrencias parece sólo normalizar el valor de O para pasarlo adelante, así que deberíamos estar bien.

  • Respuesta muy detallada, ¡impresionado! CCG bajo el capó.

    – pmor

    22 de diciembre de 2020 a las 22:48


avatar de usuario
Demi

Siete niveles distintos:

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

  • -O o -O1 (Lo mismo): Optimiza, pero no dediques demasiado tiempo.

  • -O2: optimizar de forma más agresiva

  • -O3: optimizar de forma más agresiva

  • -Ofast: Equivalente a -O3 -ffast-math. -ffast-math desencadena optimizaciones de coma 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 sobre ellos sigue las reglas estándar del álgebra de números reales. También le dice al compilador que le diga al hardware que elimine las anomalías a cero y las trate como cero, al menos en algunos procesadores, incluidos x86 y x86-64. Los valores anormales activan una ruta lenta en muchas FPU, por lo que tratarlos como cero (lo que no activa la ruta lenta) puede ser una gran ganancia de rendimiento.

  • -Os: Optimizar para 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: optimiza, pero no interfiere con la depuración. Esto permite un rendimiento no vergonzoso para compilaciones de depuración y está destinado a reemplazar -O0 para compilaciones 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 usar 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 CCG.

  • De hecho, aunque para ser justos con las otras respuestas, ni -Ofast ni -Og existían cuando se escribieron esas respuestas.

    – janneb

    17 de junio de 2013 a las 19:15

  • Entonces, ¿por qué -O100 compilar entonces?

    – einpoklum

    27 de febrero de 2016 a las 9:24

  • @einpoklum porque GCC trata todo lo que está por encima de -O3 como igual a -O3.

    – Demi

    27/02/2016 a las 19:25

  • Desafortunadamente, aún obtiene una tonelada de en el depurador con -Og. Stepping todavía salta al azar. Es inútil en mi humilde opinión.

    – doug65536

    23 oct 2017 a las 5:00

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad