Gentoo Logo

Guía de Compilación Optimizada

Contenido:

1.  Introducción

¿Qué son CFLAGS y CXXFLAGS?

CFLAGS y CXXFLAGS son variables de entorno usadas para decirle a la Colección de Compiladores GNU, gcc, que tipo de parámetros usar cuando compila código fuente. Las CFLAGS son para código escrito en C, mientras que CXXFLAGS son para código escrito en C++.

Pueden usarse para disminuir la cantidad de mensajes de depuración para un programa, aumentar los niveles de aviso de errores, y por supuesto, optimizar el código producido. El Cuaderno de GNU gcc mantiene una completa lista de opciones disponibles y sus propósitos.

¿Cómo se usan?

CFLAGS y CXXFLAGS pueden ser usados de dos maneras. La primera, pueden usarse por programa con los Makefiles generados por automake.

Sin embargo, esto no debería usarse cuando instalamos paquetes encontrados en el árbol del Portage. En su lugar, establezca sus CFLAGS y CXXFLAGS en /etc/portage/make.conf. De esta manera todos los paquetes se compilaran con las opciones que especifique.

Listado de Código 1.1: CFLAGS en /etc/portage/make.conf

CFLAGS="-march=athlon64 -O2 -pipe"
CXXFLAGS="${CFLAGS}"

Como puede ver, CXXFLAGS se establece para usar todas las opciones presentes en CFLAGS. Esto es lo que deseara casi seguro. No debería necesitar especificar opciones adicionales en CXXFLAGS nunca.

Conceptos generales

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

CFLAGS no es una solución mágica; no hará que su sistema corra más rápido o sus binarios sean más pequeños automáticamente. Añadir más y más parámetros en un intento de optimización (o "rizar") su sistema es una receta segura para el fallo. Hay un punto en el cual permanecerá dando vueltas.

A pesar de la jactancia que pueden encontrar en Internet, unas variables CFLAGS y CXXFLAGS agresivas están más cerca de dañar sus programas que de hacerles algún bien. Recuerde que la razón para la cual existen los parámetros en primer lugar es porque están diseñadas para usarse en sitios específicos para propósitos específicos. ¡Solo porque una CFLAG particular sea buena para un fragmento de código no significa que esté diseñada para compilar todo lo que quiera instalar en su máquina¡.

¿Preparado?

Ahora que está advertido de algunos de los riesgos involucrados, echemos un vistazo a algo sano, optimizaciones seguras para su ordenador. Esto le será útil y lo agradecerán los desarrolladores la próxima vez que reporte un problema en Bugzilla. (Los desarrolladores suelen pedir que recompile un paquete con los CFLAGS mínimos para ver si el problema persiste. Recuerde que los parámetros agresivos pueden arruinar el código.)

2.  Optimizando

Lo básico

La meta detrás de usar CFLAGS y CXXFLAGS es crear código específico para su sistema; debería funcionar perfectamente mientra es ligero y rápido, si es posible. Algunas veces estás condiciones son mutuamente excluyentes, pero nosotros jugaremos con combinaciones que sabemos que funcionan bien. Idealmente, las mejores están disponibles para cada arquitectura de CPU. Mencionaremos más adelante los parámetros agresivos para que se sepa con cuales tener cuidado. No discutiremos cada opción listada en el manual de gcc (hay cientos), pero hablaremos de las básicas, los más comunes.

Nota: Si no está seguro qué hace el parámetro, revise el capítulo relevante en el manual de gcc y si aún continúa atascado, pruebe Google, 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 producirse para su arquitectura de procesador (o arch); dice 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. El parámetro -march mandará al compilador producir código específico para su CPU, tomando en cuenta todas sus capacidades, características, conjuntos de instrucciones, caprichos y demás.

A pesar que la variable CHOST en /etc/portage/make.conf especifica la arquitectura general usada, -march también se usa para que sus programas sean optimizados para su procesador específico. Las arquitecturas x86 y x86-64 (entre otras) también deberían hacer uso del parámetro -march.

¿Qué tipo de CPU tiene? Para averiguarlo, ejecute la siguiente orden:

Listado de Código 2.1: Examinando la información de la CPU

$ cat /proc/cpuinfo

Ahora veamos -march en acción. Este ejemplo es para un viejo Pentium III:

Listado de Código 2.2: /etc/portage/make.conf: Pentium III

CFLAGS="-march=pentium3"
CXXFLAGS="${CFLAGS}"

Aquí hay otro para una CPU de 64-bit AMD:

Listado de Código 2.3: /etc/portage/make.conf: AMD:64

CFLAGS="-march=athlon64"
CXXFLAGS="${CFLAGS}"

Si todavía no está seguro qué tipo de CPU tiene, tal vez quiera usar la opción -march=native. Al usarla, GCC detectará el procesador y automáticamente usará las opciones apropiadas.Sin embargo, no use esta opción si la intención es ¡compilar paquetes para un CPU diferente!

De manera que, si está compilando paquetes en una computadora, pero piensa ejecutarlos en una computadora diferente (usando, por ejemplo, una computadora rápida para construir paquetes para una máquina más vieja y lenta), entonces no use la opción -march=native. La palabra "native" significa que el código producido podrá ejecutarse solamente en ese tipo de CPU. Las aplicaciones construidas con -march=native en un CPU AMD Athlon 64 CPU no podrán ejecutarse en un CPU VIA C3 más antiguo.

También están disponibles los parámetros -mcpu y -mtune. Cada uno de ellos solo se usará cuando no haya otra opción -march disponible. Ciertas arquitecturas de procesador pueden requerir -mtune o incluso de -mcpu. Desgraciadamente, el comportamiento de gcc no es muy consistente con la manera que cada parámetro se comporta de una arquitectura a la otra.

En CPUs x86 y x86-64, -mcpu generará código específico para esta CPU usando todas sus instrucciones disponibles y el ABI correcto; no tendrá compatibilidad hacia atrás para CPUs antiguas/diferentes. Si no necesita ejecutar código en otro sitio que en el sistema que está corriendo Gentoo, continúe para usar -march. Solo debería considerar usar -mtune cuando necesite generar código para CPUs antiguas como i386 e i486. -mtune produce un código más genérico que -march; aunque afinará el código para cierto CPU, no tendrá en cuenta los conjuntos de instrucciones disponibles y ABI. No use -mcpu en sistemas x86 o x86-64, ya que está obsoleto para estas arquitecturas.

Solo CPUs no x86/x86-64 (como Sparc, Alpha y PowerPC) pueden requerir -mtune o -mcpu en lugar de -march. En estas arquitecturas, -mtune/-mcpu algunas veces se comportará como -march en (x86/x86-64) ... pero con un nombre distinto. De nuevo, el comportamiento de gcc y los nombres de los parámetros no es consistente entre arquitecturas, así que asegúrese de revisar el manual de gcc para determinar cual de ellos se ajusta a su sistema.

Nota: Para más sugerencias de configuraciones de -march/-mtune/ -mcpu, por favor lea el capítulo 5 de la Guía de Instalación de Gentoo apropiada a su arquitectura. También, lea el manual de gcc listado en la página opciones específicas por arquitectura, con explicaciones más detalladas sobre las diferencias entre -march, -mcpu, y -mtune.

-O

Lo siguiente es la variable -O. Controla el total de niveles de optimización. Hace que la compilación de código tome algo más de tiempo, y puede tomar mucha más memoria, especialmente al incrementar el nivel de optimización.

Hay cinco configuraciones para -O: -O0, -O1, -O2, -O3 y -Os. Debería usar solamente una de ellas en /etc/portage/make.conf.

Con la excepción de -O0, la configuración de -O activa varios parámetros adicionales, así que asegúrese de leer el capítulo del manual de gcc en opciones de optimización para aprender cuales parámetros se activan en cada nivel -O, así como algunas explicaciones sobre lo que hacen.

Examinemos cada nivel de optimización:

  • -O0: Este nivel (la letra "O" seguida de un cero) desconecta por completo la optimización y es el predeterminado si no se especifica ningún nivel -O en CFLAGS o CXXFLAGS. El código no será optimizado. Esto, normalmente, no es lo que se desea.
  • -O1: Este es el nivel de optimización más básico. El compilador intentará producir un código rápido y pequeño sin tomar mucho tiempo de compilación. Es bastante básico, pero conseguirá acabar el trabajo siempre.
  • -O2: Un paso por encima de -O1. Este es el nivel recomendado de optimización, a no ser que tenga necesidades especiales. -O2 activará unos pocos parámetros añadidos a los que se activan con -O1. Con -O2, el compilador intentará aumentar el rendimiento del código sin comprometer el tamaño y sin tomar mucho más tiempo de compilación.
  • -O3: Este es el más alto nivel de optimización posible, y también el más arriesgado. Tomará muchísimo tiempo compilar su código con esta opción, y de hecho, no debería usarse a través de todo el sistema con gcc 4.x. El comportamiento de gcc ha cambiado significativamente desde la versión 3.x, donde con -O3 se había demostrado producir código con tiempos de ejecución marginalmente menores sobre -O2, pero este ya no es el caso con gcc 4.x. Compilar todos sus paquetes con -O3 resultará en grandes binarios que requerirán mucha memoria e incrementará significativamente los extraños fallos de compilación o los comportamientos inesperados de los programas (incluidos los errores). Las desventajas compensan las ventajas. No se recomienda usar -O3 con gcc 4.x.
  • -Os: Este nivel optimizará su código para el tamaño. Activa todas las opciones de -O2 que no aumenten el tamaño del código generado. Es útil para máquinas con capacidad limitada de disco y/o con CPUs con poca caché. Sin embargo, puede causar algunos problemas porque es filtrado por muchos ebuilds del árbol. No aconsejamos usar -Os.

Como se comentó anteriormente, -O2 es el nivel de optimización recomendado. Si un paquete muestra errores de compilación, asegúrese que no está usando -O3. Como opción de marcha atrás, pruebe configurando CFLAGS y CXXFLAGS a un nivel de optimización inferior, como -O1 o incluso -O0 -g2 -ggdb (para reportar errores y comprobar posibles problemas) y recompile el paquete.

-pipe

-pipe es un parámetro común. Realmente no tiene efecto sobre el código que se produce, pero hace que el proceso de compilación sea más rápido. Indica al compilador que use tuberías en lugar de archivos temporales durante los diferentes estados de compilación, lo cual usa más memoria. En sistemas con poca memoria, el proceso de gcc podría ser terminado. En este caso no use este parámetro.

-fomit-frame-pointer

Esta es un parámetro muy común diseñada para reducir el tamaño del código generado. Está activado para todos los niveles de -O (excepto -O0) en arquitecturas donde no interfiera con el depurado (como x86-64), pero puede hacer falta activarlo uno mismo, añadiéndolo a sus parámetros. Aunque el manual de GNU gcc no especifica todas las arquitecturas en las que está activado al usar -O, hay que activarlo explícitamente en un x86. Sin embargo, usando este parámetro hará que la depuración sea de dura a imposible.

En particular, provoca que localizar problemas en aplicaciones escritas en Java sea mucho más complicada, aunque Java no es el único código afectado al usar este parámetro. Así, aunque este parámetro puede ayudar, el depurado será duro; los "backtraces" en particular serán inútiles. Sin embargo, si no planea hacer muchas depuraciones y no tiene añadida ninguna otra CFLAG relacionada con la depuración como -ggdb (y no está instalando paquetes con la variable USE debug), entonces intente usar -fomit-frame-pointer.

Importante: No combine -fomit-frame-pointer con el parámetro de nombre similar -momit- leaf-frame-pointer. El uso de este último está desaconsejado, 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

Estos parámetros activan los conjuntos de instrucciones SSE, SSE2, SSE3, MMX, and 3DNow! para arquitecturas x86-64. Son útiles principalmente en multimedia, juegos y otras tareas intensivas de computación en punto flotante, aunque también contienen muchos otros realces matemáticos. Estos conjuntos de instrucciones se encuentran en las más modernas CPUs.

Importante: Asegúrese de verificar si su CPU los soporta ejecutando cat /proc/cpuinfo. La salida incluirá cualquier conjunto de instrucciones adicionales. Note que pni es solo otro nombre para SSE3.

Normalmente no necesita añadir ninguno de estos parámetros a /etc/portage/make.conf mientras esté usando la -march correcta (por ejemplo, -march= nocona implica -msse3). Algunas excepciones notables son los CPUs nuevos VIA y AMD64 que soportan instrucciones no implicadas por -march (como SSE3). Para CPUs como estos necesitará habilitar parámetros adicionales donde sea apropiado después de verificar la salida de cat /proc/cpuinfo.

Nota: Revise la lista de parámetros específicos para x86 y x86-64 para ver cuales de estos conjuntos de instrucciones son activados por la propia configuración del tipo de CPU. Si una instrucción está listada, entonces no necesita especificarla; se activará al usar la configuración de -march apropiada.

3.  PUFs de Optimización

¡Pero tengo un mejor rendimiento con -funroll-loops -fomg-optimize!

No, solo piensa que lo hace porque alguien le ha convencido que más parámetros es mejor. Los parámetros agresivos solo dañaran sus aplicaciones cuando use un sistema completo. Incluso el manual de gcc dice que usar -funroll-loops y -funroll-all-loops crea código más grande y que corre más lento. Aún por algunas razones, estos dos parámetros, junto con -ffast-math, -fforce-mem, -fforce-addr, y similares, continúan siendo muy populares entre pardillos que quieren saber más que nadie.

La verdad es que son parámetros peligrosamente agresivos. Eche un vistazo a los Foros de Gentoo y Bugzilla para ver que hacen estas variables: ¡nada bueno!

No necesita usar estos parámetros globalmente en CFLAGS o CXXFLAGS. Solo dañarán el rendimiento. Puede sonarle como que tiene un sistema avanzado de alto rendimiento, pero no hará más que inflar su código y marcar sus informes de errores como INVALID o WONTFIX.

No necesita parámetros peligrosos como estas. No las use. Quédese con las básicas: -march, -O, y -pipe.

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

Algunos usuarios alardean que obtienen mejor rendimiento usando -O4, -O9, y así, 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 el. Solo realiza la optmización para -O3, nada más.

¿Necesita más pruebas? Examine el código fuente de gcc:

Listado de Código 3.1: Código fuente de -O

if (optimize >= 3)
    {
      flag_inline_functions = 1;
      flag_unswitch_loops = 1;
      flag_gcse_after_reload = 1;
      /* Allow even more virtual operators.  */
      set_param_value ("max-aliased-vops", 1000);
      set_param_value ("avg-aliased-vops", 3);
    }

Como puede ver, cualquier valor por encima de 3 es tratado como solo -O3.

¿Qué pasa con los parámetros redundantes?

A menudo CFLAGS y CXXFLAGS que están activadas en varios niveles de -O están especificadas redundantemente en /etc/portage/make.conf. Algunas veces esto ocurre por ignorancia, pero también ocurre para permitir el filtrado o el reemplazo de parámetros.

Muchos de los ebuilds del árbol del Portage contienen filtrado/reemplazo de parámetros. Suele hacerse porque hay paquetes que fallan en ciertos niveles de -O, o cuando el código fuente es muy sensible para ser usado para cualquier parámetro adicional. El ebuild podrá cada vez filtrar para algunas o todas las CFLAGS y CXXFLAGS, o puede reemplazar -O con un nivel diferente.

El Manual del Desarrollador de Gentoo resume dónde y cómo trabaja el filtrado/reemplazo de parámetros.

Es posible evitar el filtrado de -O por el listado redundante de parámetros para un cierto nivel, como -O3, haciendo cosas como:

Listado de Código 3.2: Especificando CFLAGS redundantes

CFLAGS="-O3 -finline-functions -funswitch-loops"

Sin embargo, hacer esto no es inteligente. ¡Las CFLAGS son filtradas por una razón! Cuando estos parámetros son filtrados es porque es inseguro construir paquetes con ellos. Claramente, no es seguro compilar su sistema completo con -O3 si alguno de estos parámetros 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 parámetros se hace por su bien! Si un ebuild especifica parámetros alternativos, entonces no intente convencerlo.

No encontrará más que problemas cuando construya un paquete con parámetros inaceptables. Cuando reporte sus problemas en Bugzilla, los parámetros que usó en /etc/portage/make.conf serán fácilmente visibles y se le instará a recompilar sin ellos. ¡Protéjase de los problemas de recompilar no usando parámetros redundantes en primer lugar! No asuma automáticamente que sabe más que los desarrolladores.

¿Qué pasa con LDFLAGS?

Los desarrolladores de Gentoo ya han configurado LDFLAGS básicas y seguras en los perfiles base, de tal manera que no necesita cambiarlas.

¿Puedo usar parámetros por paquete?

Aviso: El uso de parámetros por paquetes complica la depuración y el soporte. Asegúrese de mencionarlo en los reportes de fallos si está usando esta característica y los cambios realizados.

Información acerca de como utilizar las variables de entorno por paquete (incluyendo CFLAGS) puede encontrarse en el Manual Gentoo, "Variables de entorno por paquete".

4.  Recursos

Los siguientes recursos son un poco de ayuda en aras de comprender la optimización:



Imprimir

Página actualizada 25 de diciembre, 2012

Sumario: Esta guía proporciona una introducción a la compilación optimizada usando CFLAGS y CXXFLAGS seguras y sanas. Al tiempo que se describe la teoria detrás de la optimización en general.

Joshua Saddler
Autor

John Christian Stoddart
Traductor

Federico Díaz
Traductor

Sergio D. Rodríguez Inclan
Traductor

José María Alonso
Traductor

Donate to support our development efforts.

Copyright 2001-2013 Gentoo Foundation, Inc. Questions, Comments? Contact us.