Optimización de GCC

From Gentoo Wiki
Jump to: navigation, search
This page is a translated version of the page GCC optimization and the translation is 70% complete.

Other languages:
English • ‎español • ‎français • ‎italiano • ‎日本語 • ‎한국어 • ‎русский • ‎Türkçe

Esta guía ofrece una introducción al código compilado de forma óptima usando CFLAGS y CXXFLAGS seguras y sanas. También describe la teoría detrás de la optimización en general.

Introducción

¿Qué son CFLAGS y CXXFLAGS?

CFLAGS y CXXFLAGS son variables de entorno usadas para indicar a la Colección de Compiladores de GNU (GCC), qué tipo de opciones usar cuando compila código fuente. La variable CFLAGS se utiliza para compilar código escrito en C, mientras que la variable CXXFLAGS es para código escrito en C++.

Pueden usarse para disminuir la cantidad de mensajes de depuración de un programa, aumentar los niveles de aviso de errores, y por supuesto, optimizar el código producido. El manualde GCC ofrece una lista completa opciones disponibles y sus aplicaciones.

¿Cómo se utilizan?

CFLAGS y CXXFLAGS se pueden usar de dos formas. La primera, por programa con los ficheros Makefile generados por el programa automake.

However, this should not be done when installing packages found in the Portage tree. Instead, for Gentoo-based machines, set the CFLAGS and CXXFLAGS variables in /etc/portage/make.conf This way all packages will be compiled using the options specified in {{Path|make.conf}

CÓDIGO Ajustar CFLAGS en /etc/portage/make.conf
CFLAGS="-march=athlon64 -O2 -pipe"
CXXFLAGS="${CFLAGS}"
Importante
Aunque es posible tener varias líneas en los ajustes USE, hacer lo mismo en CFLAGS puede y dará problemas con programas como cmake. Asegúrese de que la declaración CFLAGS se realiza en una sola línea con el menor número posible de espacios en blanco para evitar estos problemas. Eche un vistazo a la incidencia bug #500034 a modo de ejemplo.

Como se puede observar en el ejemplo de arriba, CXXFLAGS se define para usar todas las opciones presentes en CFLAGS. La mayoría de los sistemas se configurarán de este modo ya que las opciones adicionales para CXXFLAGS son extremadamente raras en los casos de uso comunes.

Confusiones

Aunque CFLAGS y CXXFLAGS pueden ser muy efectivos tomando el código fuente para producir binarios pequeños o rápidos, también pueden deteriorar la función del código, inflar su tamaño, ralentizar su tiempo de ejecución. Ajustarlas incorrectamente ¡puede incluso causar errores de compilación!

CFLAGS no es una solución mágica; no hará que el sistema corra más rápido o se reduzca el tamaño de los binarios en el disco. Añadir demasiadas opciones en un intento de optimización (o "exprimir") el sistema es una receta segura para fracasar. El punto en el que se reduce el redimiento se alcanza más rápidamente si se toquetea CFLAGS.

A pesar de las recomendaciones y alardeos que se pueden encontrar en Internet, unas variables CFLAGS y CXXFLAGS agresivas están más cerca de dañar los binarios que de hacerles algún bien. Recuerde que la razón principal por la que existen las opciones es porque están diseñadas para usarse en sitios específicos para propósitos específicos. Hay pocos ajustes que funcionen de forma global tal y como se espera.

¿Preparado?

Conociendo los riesgos involucrados, echemos un vistazo a algunas optimizaciones sanas y seguras para su computadora. Esto le será útil y también alentador para los desarrolladores la próxima vez que se informe de un problema en Bugzilla. (Los desarrolladores suelen pedir al usuario que recompile un paquete con los CFLAGS mínimos para ver si el problema persiste. Recuerde: ¡Las opciones agresivas pueden arruinar el código!)

Optimización

Conceptos básicos

The goal behind CFLAGS and CXXFLAGS is to create code tailor-made to your system; it should function perfectly while being lean and fast, if possible. Sometimes these conditions are mutually exclusive, so this guide will stick to combinations known to work well. Ideally, they are the best available for any CPU architecture. For informational purposes, aggressive flag use will be covered later. No very option listed on the GCC manual (there are hundreds) will be discussed, but basic, most common flags will be reviewed.

Nota
Cuando no esté seguro de la función que realiza determinada opción, acuda al capítulo correspondiente del de opciones Options de GCC. Si aún continúa atascado después de mirar en el manual, pruebe con un motor de búsquega o revise las listas de correo de GCC

-march

La primera y más importante opción es -march. Esta le dice al compilador que código debería producir para su arquitectura de procesador (o arch), le indica a GCC que debería producir código para un cierto tipo de CPU. Diferentes CPUs tienen diferentes características, soportan diferentes conjunto de instrucciones y tienen diferentes formas de ejecutar código. La opción -march indicará al compilador que produzca código específico para la CPU del sistema, tomando en cuenta todas sus capacidades, características, conjuntos de instrucciones, caprichos y demás.

Even though the CHOST variable in /etc/portage/make.conf specifies the general architecture used, -march should still be used so that programs can be optimized for the system specific processor. x86 and x86-64 CPUs (among others) should make use of the -march flag.

What kind of CPU does the system have? To find out, run the following command:

user $cat /proc/cpuinfo

Para obtener más detalles, incluyendo valores march y mtune, utilice:

user $gcc -c -Q -march=native --help=target

Now lets see -march in action. This example is for an older Pentium III chip:

CÓDIGO Ejemplo para Pentium III
CFLAGS="-march=pentium3"
CXXFLAGS="${CFLAGS}"

Aquí hay otro para una CPU AMD de 64 bits:

ARCHIVO /etc/portage/make.conf Ejemplo para AMD64
CFLAGS="-march=athlon64"
CXXFLAGS="${CFLAGS}"

If the type of CPU is undetermined, or if the user does not know what setting to choose, it is possible use the -march=native setting. When this flag is used, GCC will attempt to detect the processor and automatically set appropriate flags for it. However, this should not be used when intending to compile packages for different CPUs!

Advertencia
No utilice -march=native o -mtune=native en las variables CFLAGS o CXXFLAGS de make.conf cuando compile con distcc.

If compiling packages on one computer in order to run them on a different computer (such as when using a fast computer to build for an older, slower machine), then do not use -march=native. "Native" means that the code produced will run only on that type of CPU. The applications built with -march=native on an AMD Athlon 64 CPU will not be able to run on an old VIA C3 CPU.

Also available are the -mtune and -mcpu flags. These flags are normally only used when there is no available -march option; certain processor architectures may require -mtune or even -mcpu. Unfortunately, GCC's behavior isn't very consistent with how each flag behaves from one architecture to the next.

On x86 and x86-64 CPUs, -march will generate code specifically for that CPU using its available instruction sets and the correct ABI; it will have no backwards compatibility for older/different CPUs. Consider using -mtune when generating code for older CPUs such as i386 and i486. -mtune produces more generic code than -march; though it will tune code for a certain CPU, it does not take into account available instruction sets and ABI. Do not use -mcpu on x86 or x86-64 systems, as it is deprecated for those arches.

Only non-x86/x86-64 CPUs (such as Sparc, Alpha, and PowerPC) may require -mtune or -mcpu instead of -march. On these architectures, -mtune / -mcpu will sometimes behave just like -march (on x86/x86-64) but with a different flag name. Again, GCC's behavior and flag naming is not consistent across architectures, so be sure to check the GCC manual to determine which one should be used.

Nota
For more suggested -march / -mtune / -mcpu settings, please read chapter 5 of the appropriate Gentoo Installation Handbook for the arch. Also, read the GCC manual's list of architecture-specific options, as well as more detailed explanations about the differences between -march, -mcpu, and -mtune.

-O

Next up is the -O variable. This variable controls the overall level of optimization. Changing this value will make the code compilation take more time and will use much more memory, especially as the level of optimization is increased.

There are seven -O settings: -O0, -O1, -O2, -O3, -Os, -Og, and -Ofast. Only use one of them in /etc/portage/make.conf

A excepción de -O0, la configuración de -O activa varias opciones adicionales, así que asegúrese de leer el capítulo del manual de gcc enopciones de optimización para aprender qué opciones se activan en cada nivel -O, así como algunas explicaciones sobre lo que hacen.

Let us examine each optimization level:

  • -O0: This level (that is the letter "O" followed by a zero) turns off optimization entirely and is the default if no -O level is specified in CFLAGS or CXXFLAGS. This reduces compilation time and can improve debugging info, but some applications will not work properly without optimization enabled. This option is not recommended except for debugging purposes.
  • -O1: the most basic optimization level. The compiler will try to produce faster, smaller code without taking much compilation time. It is basic, but it should get the job done all the time.
  • -O2: A step up from -O1. The recommended level of optimization unless the system has special needs. -O2 will activate a few more flags in addition to the ones activated by -O1. With -O2, the compiler will attempt to increase code performance without compromising on size, and without taking too much compilation time.
  • -O3: the highest level of optimization possible. It enables optimizations that are expensive in terms of compile time and memory usage. Compiling with -O3 is not a guaranteed way to improve performance, and in fact, in many cases, can slow down a system due to larger binaries and increased memory usage. -O3 is also known to break several packages. Using -O3 is not recommended.
  • -Os: optimizes code for size. It activates all -O2 options that do not increase the size of the generated code. It can be useful for machines that have extremely limited disk storage space and/or CPUs with small cache sizes.
  • -Og: En GCC 4.8 aparece un nuevo nivel del optimización general: -Og. Trata de solucionar la necesidad de realizar compilaciones más rápidas y obtener una experiencia superior en la depuración a la vez que ofrece un nivel razonable de rendimiento en la ejecución. La experiencia global en el desarrollo debería ser mejor que para el nivel de optimización -O0. Observe que -Og no implica -g, éste simplemente deshabilita optimizaciones que podrían interferir con la depuración.
  • -Ofast: Nuevo en GCC 4.7. Consiste en el ajuste -O3 más las opciones -ffast-math, -fno-protect-parens y -fstack-arrays. Esta opción rompe el cumplimiento de estándares estrictos y no se recomienda su utilización.

As previously mentioned, -O2 is the recommended optimization level. If package compilation fails and while not using -O2, try rebuilding with that option. As a fallback option, try setting the CFLAGS and CXXFLAGS to a lower optimization level, such as -O1 or even -O0 -g2 -ggdb (for error reporting and checking for possible problems).

-pipe

A common flag is -pipe. This flag has no effect on the generated code, but it makes the compilation process faster. It tells the compiler to use pipes instead of temporary files during the different stages of compilation, which uses more memory. On systems with low memory, GCC might get killed. In those cases do not use this flag.

-fomit-frame-pointer

This is a very common flag designed to reduce generated code size. It is turned on at all levels of -O (except -O0) on architectures where doing so does not interfere with debugging (such as x86-64), but it may need to activated. In that case add it to the flags. Though the GCC manual does not specify all architectures, it is turned on by using the -O option. Use the -O option to explicitly activate it on x86, with GCC up to version 4.6 or when using -Os. However, using this flag will make debugging hard or impossible.

In particular, it makes troubleshooting applications written in Java much harder, though Java is not the only code affected by using this flag. So while the flag can help, it also makes debugging harder; backtraces in particular will be useless. When not doing software debugging and no other debugging-related CFLAGS such as -ggdb have been used, then try using -fomit-frame-pointer.

Importante
No combine -fomit-frame-pointer con la opción de nombre similar -momit- leaf-frame-pointer. No se aconseja la utilización de esta última, ya que -fomit-frame-pointer ya hace el trabajo apropiado. Es más, -momit-leaf-frame-pointer ha demostrado que impacta negativamente en el rendimiento del código.

-msse, -msse2, -msse3, -mmmx, -m3dnow

These flags enable the Streaming SIMD Extentions (SSE), SSE2, SSE3, MMX, and 3DNow! instruction sets for x86 and x86-64 architectures. These are useful primarily in multimedia, gaming, and other floating point-intensive computing tasks, though they also contain several other mathematical enhancements. These instruction sets are found in more modern CPUs.

Importante
Be sure to see if the CPU supports these instruction sets by running cat /proc/cpuinfo. The output will include any supported additional instruction sets. Note that pni is just a different name for SSE3.

Normally none of these flags need to be added to /etc/portage/make.conf, as long as the system is using the correct -march (for example, -march=nocona implies -msse3). Some notable exceptions are newer VIA and AMD64 CPUs that support instructions not implied by -march (such as SSE3). For CPUs like these additional flags will need to be enabled where appropriate after checking /proc/cpuinfo.

Nota
Check the list of x86 and x86-64-specific flags to see which of these instruction sets are activated by the proper CPU type flag. If an instruction is listed, then it does not need to be separately specified; it will be turned on by using the proper -march setting.

Preguntas frecuentes sobre optimización

Sin embargo, ¡Consigo mejor rendimiento con -funroll-loops -fomg-optimize!

No, you only think you do because someone has convinced you that more flags are better. Aggressive flags will only hurt applications when used system-wide. Even the GCC manual says that using -funroll-loops and -funroll-all-loops will make code larger and run more slowly. Yet for some reason, these two flags, along with -ffast-math, -fforce-mem, -fforce-addr, and similar flags, continue to be very popular among ricers who want the biggest bragging rights.

La verdad es que son opciones peligrosamente agresivas. Eche un vistazo a los Foros de Gentoo y a Bugzilla para ver que hacen estas variables: ¡Nada bueno!

You do not need to use those flags globally in CFLAGS or CXXFLAGS. They will only hurt performance. They may make you sound like you have a high-performance system running on the bleeding edge, but they don't do anything but bloat the code and get your bugs marked INVALID or WONTFIX.

No necesita opciones peligrosas como estas. No las utilice. Quédese con las básicas: -march, -O y -pipe.

¿Qué pasa con los niveles -O mayores que 3

Algunos usuarios alardean de que obtienen mejor rendimiento usando -O4, -O9 y similares, pero la realidad es que niveles de -O mayores que 3 no tienen efecto. El compilador puede aceptar CFLAGS como -O4, pero realmente no hace nada con él. Solo realiza la optimización para -O3, nada más.

¿Necesita más pruebas? Eche un vistazo al código fuente:

CÓDIGO Código fuente -O
if (optimize >= 3)
  {
   flag_inline_functions = 1;
   flag_unswitch_loops = 1;
   flag_gcse_after_reload = 1;
   /* Permitir más operadores virtuales. */
   set_param_value ("max-aliased-vops", 1000);
   set_param_value ("avg-aliased-vops", 3);
  }

Como puede observar, cualquier valor mayor que 3 se trata como -O3.

¿Qué ocurre cuando compilamos fuera de la máquina destino?

Algunos lectores se pueden preguntar si el hecho de compilar fuera de la máquina destino usando una CPU estrictamente inferior o una subarquitectura en GCC generará unos resultados de optimización inferiores. La respuesta es simple: No. Independientemente del hardware en el que realmente se realiza la compilación y el CHOST con el que se construyó GCC, si se utilizan los mismos argumentos (excepto para -march=native) y la misma versión de GCC (aunque la versión menor puede ser distinta), las optimizaciones resultantes son estrictamente las mismas.

Como ejemplo, si Gentoo se instala en una máquina en el que el CHOST de GCC es i686-pc-linux-gnu, y se utiliza un servidor Distcc/es en otro equipo en el que el CHOST de GCC es i486-linux-gnu entonces no hay porqué preocuparse de que los resultados sean menos óptimos ya que la subarquitectura del compilador o el hardware del equipo remoto son estrictamente inferiores. El resultado sería igual de óptimo que una construcción en una máquina nativa siempre que se pasen las mismas opciones a ambos compiladores (y no se defina el argumento -march como native). En este caso en particular se necesita especificar la aquitectura destinotal y como se indica en Distcc y -march=native.

La única diferencia en el comportamiento entre dos versiones de GCC construidas con diferentes subarquitecturas es el valor implícito por defecto para el parámetro -march que se deriva del CHOST de GCC cuando no se ha indicado uno de forma explícita en la línea de órdenes.

¿Qué pasa con las opciones redundantes?

A menudo CFLAGS y CXXFLAGS que se han activado en varios niveles de -O están especificadas de forma redundante en /etc/portage/make.conf. A veces esto ocurre por ignorancia, pero también se hace para permitir el filtrado o el reemplazo de opciones.

El filtrado y el reemplazo de opciones se realiza en muchos ebuilds del árbol Portage. Normalmente se realiza debido a que algunos paquetes no compilan con determinados niveles -O o cuando el código fuente es tan sensible que no se pueden utilizar opciones adicionales. El ebuild bien filtrará algunas opciones o todas las opciones CFLAGS y CXXFLAGS, bien reemplazará -O con un nivel diferente.

El Manual del Desarrollador de Gentoo indica dónde y cómo funciona el filtrado y el reemplazo de opciones.

Es posible evitar el filtrado de -O filtrando mediante el listado redundante de opciones para un cierto nivel, como -O3, haciendo cosas como:

CÓDIGO Especificar CFLAGS redundantes
CFLAGS="-O3 -finline-functions -funswitch-loops"

Sin embargo, hacer esto no es algo acertado. ¡Las CFLAGS se filtran por alguna razón! Cuando estas opciones se filtran es porque es inseguro construir paquetes con ellos. Claramente, no es seguro compilar su sistema completo con -O3 si alguna de estas opciones está activada para este nivel causará problemas con ciertos paquetes. Por lo tanto, no debería intentar "saber más" que los desarrolladores que mantienen estos paquetes. Confíe en ellos. ¡El filtrado y reemplazo de opciones se hace por su bien!. Si un ebuild especifica opciones alternativas, entonces no intente evitarlas.

No encontrará más que problemas cuando construya un paquete con opciones inaceptables. Cuando informe de sus problemas en Bugzilla, las opciones que usó en /etc/portage/make.conf serán fácilmente visibles y se le instará a recompilar sin ellas. ¡Protéjase de los problemas de recompilar evitando el uso de opciones redundantes! No asuma automáticamente que sabe más que los desarrolladores.

¿Qué pasa con LDFLAGS?

The Gentoo developers have already set basic, safe LDFLAGS in the base profiles, so they do not need changed.

¿Puedo usar opciones para cada paquete?

Advertencia
El uso de opciones específicas de paquetes complica la depuración y el soporte. Asegúrese mencionarlo en los informes de fallos si está usando esta característica y los cambios que haya realizado.

Puede encontrarse información acerca de como utilizar las variables de entorno por paquete (incluyendo CFLAGS) en el manual de Gentoo "Variables de entorno por paquete".

Recursos

Los siguientes recursos pueden ser de ayuda para comprender la optimización:

  • man make.conf

This article is based on a document formerly found on our main website gentoo.org.
The following people have contributed to the original document: nightmorph
They are listed here as the Wiki history does not provide for any attribution. If you edit the Wiki article, please do not add yourself here, your contributions are recorded on the history page.