2009-02-24 18 views
22

Las plantillas de C++ han sido una bendición en mi trabajo diario debido a su poder. Pero no se puede ignorar el tiempo de compilación (muy, muy, muy largo) que resulta del uso intensivo de plantillas (metaprogramación de hello y bibliotecas de Boost). He leído y probado bastantes posibilidades para reorganizar y modificar manualmente el código de la plantilla para que se compile lo más rápido posible.¿Hay compiladores optimizados de C++ para el uso de plantillas?

Ahora me pregunto si hay compiladores de C++ que intenten minimizar el tiempo necesario para interpretar las clases de plantillas. Podría estar equivocado, pero creo que los compiladores que conozco solo han agregado la interpretación de la plantilla a sus versiones anteriores.

Mis preguntas son:

  • es C++ código de la plantilla tan difícil de interpretar que no hay mucho para optimizar? (lo dudo mucho)
  • ¿Hay compiladores de C++ que realmente optimicen la interpretación de las "plantillas de C++"?
  • ¿Existen proyectos para desarrollar una nueva generación de compiladores de C++ que optimicen esto?
  • Si tuviera que participar en un proyecto de este tipo, ¿cuáles serían sus directrices?
+0

Prefiero que los desarrolladores de compiladores se concentren en la optimización del código generado y aprovechen el paralelismo (SMP, distcc, Xoreax IncrediBuild, etc.) para acelerar las compilaciones. – bk1e

+4

¿Por qué no hacer que trabajen en ambos problemas? La ganancia que espero de un compilador de C++ que ha sido optimizado para plantillas es mucho más alta que la que obtengo al usar el paralelismo (y ya lo hago), a menos que esté rodeado por un trillón de computadoras esperando que compile el código (no lo hago). t)! –

Respuesta

4

Parece que g ++ 4.5 ha hecho un gran progreso al tratar con plantillas. Aquí están los dos cambios inevitables.

  • "Cuando se imprime el nombre de una especialización de plantilla de clase, G ++ ahora omitir cualquier argumentos de plantilla que provienen de argumentos de plantilla por defecto." Eso podría considerarse una modificación sutil, pero tendrá un enorme impacto en el desarrollo con las plantillas de C++ (¿Alguna vez se han escuchado mensajes de error ilegibles ...? ¡No más!)

  • "El tiempo de compilación para el código que usa plantillas debería ahora escalarse linealmente con el número de instancias en lugar de cuadráticamente." Esto va a socavar seriamente los argumentos de tiempo de compilación contra el uso de plantillas de C++.

Ver en el gnu site para obtener información completa

En realidad, ya estoy preguntando si todavía hay problemas con las plantillas de C++! Mmm, sí, hay, pero centrémonos en el lado positivo por el momento.

2

No va a ser la respuesta que desea, pero Walter Bright fue el principal desarrollador del primer compilador C++ nativo y un compilador optimizado de C++. Después de todo, él escribió su propio lenguaje de programación llamado D. Básicamente es una mejora en C++ y se adapta mejor a las plantillas.

No conozco ningún compilador de C++ que haya sido optimizado para el uso de la plantilla.

+0

IIRC alguien hizo una gramática de 50 producciones con Boost :: Spirit (un generador de analizador de metaprogramación) y tardó 17 horas en compilarse. Tengo una gramática de 250 producciones que se compila con un equivalente D en 7 * minutos * – BCS

+0

¡Ese es el tipo de ganancia que estoy esperando! ¡Pero no puedo cambiar todos los códigos existentes al lenguaje D! –

0

Creo que las plantillas en sí mismas no son tan complejas. Veremos cuándo se introducen los conceptos en C++ 0x, etc., pero por el momento, las plantillas son simplemente (casi) como macros, por lo que el problema real no es que haya optimizado los compiladores de C++ para las plantillas. El problema es que las plantillas generan una gran cantidad de código al compilar, lo que hace que la compilación sea más lenta.

+0

¿Puede explicar lo que cree que hace que la compilación sea más lenta? Yo personalmente uso plantillas como una forma de aislar el desarrollo de clases en mis proyectos. Si hubiera un solo proyecto, podría hacer exactamente lo mismo sin plantillas. Pero hay muchos proyectos, ¡muchas plantillas! –

+0

Benoît, la compilación ** es ** más lenta con las plantillas. Tenga en cuenta que cuando utiliza, por ejemplo, vector y llama a algunas funciones, el compilador toma el código de plantilla y lo compila para el tipo int. Si usa, por ejemplo, vector , lo mismo. Sin embargo, normalmente la velocidad de compilación normalmente debería ser ... –

+0

... segunda preocupación, como muchas veces, con las plantillas puede desarrollar una solución más limpia a un problema, o incluso resolver cosas que no puede hacer sin plantillas. Así que resumiendo: las plantillas hacen que la compilación sea más lenta, pero son una abstracción clave en C++. –

1

Probar Incredibuild. Se reduce drásticamente el tiempo de compilación/compilación.

Este producto básicamente permite a Visual C++ construir en varias máquinas de su organización aprovechando los ciclos de inactividad. Utilicé Incredibuild en grandes proyectos (500 kloc) con muchos códigos de plantilla y obtuve una buena aceleración en los tiempos de construcción.

9

Esto realmente no es una respuesta a su pregunta. Es más una observación lateral.

No soy abogado de C++, por lo que podría estar fuera de lugar con algunos de los detalles.

Pero, la idea aproximada debería ser correcta.

La razón principal por la que los compiladores de C++ tardan tanto tiempo en compilar los metaprogramas de plantillas es por la forma en que se especifican los metaprogramas de las plantillas.

No se especifican directamente como código que desea que el compilador ejecute en tiempo de compilación. Tome el ejemplo de calcular la longitud de una lista de tipos.

Si usted podría escribir código como este:

compile_time size_t GetLength(TypeList * pTypeList) 
{ 
    return DoGetLength(pTypeList, 0); 
} 

compile_time size_t DoGetLength(TypeList * pTypeList, size_t currentLength) 
{ 
    if (pTypeList) 
    { 
     return DoGetLength(pTypeList->Next, ++currentLength); 
    } 
    else 
    { 
     return currentLength; 
    } 
} 

Eso era de alguna forma compilada por separado del código donde fue utilizado, y fue expuesto a la lengua a través de una sintaxis, entonces el compilador sería capaz de ejecutarlo muy rápido.

Sería una simple llamada a función recursiva.

Es posible diseñar un lenguaje que permita ese tipo de cosas. La mayoría de los que hacen esto (como Lisp) se tipean dinámicamente, pero es posible hacerlo con tipeo estático. Sin embargo, es probable que nunca sea algo que verías implementado en C++.

El problema en C++, sin embargo, es que el código se escribe así:

template <typename First, typename Second> 
struct TypeList 
{ 
    typedef First Head; 
    typedef Second Tail; 
}; 

template <> 
struct ListSize<NullType> 
{ 
    enum { size = 0 }; 
}; 

template <typename Head, typename Tail> 
struct ListSize<TypeList<Head, Tail> > 
{ 
    enum { size = 1 + ListSize<Tail>::size }; 
}; 

Para que el compilador para "ejecutar" el meta-programa que tiene que:

  1. Construct un gráfico de dependencia para los valores iniciales del valor de enumeración "tamaño"
  2. Construir un tipo de plantilla para cada borde en el gráfico
  3. Enlazar todos los símbolos referenciados por cada construcción tipo de plantilla
  4. ordenar Topologically la gráfica de dependencia
  5. Traverse el gráfico y evaluar las constantes

Esto es mucho más caro que simplemente la ejecución de un O (N) algoritmo recursivo.

El peor caso sería algo así como O (N * M * L), con N igual a la longitud de la lista, M es el nivel de anidación del alcance y L es el número de símbolos en cada ámbito.

Mi consejo sería minimizar la cantidad de meta-programación de plantilla C++ que utiliza.

+0

+1. Me gusta tu ejemplo. Es exactamente lo que tengo en mente. La meta-programación de plantillas es "solo" una secuencia de comandos con el compilador como intérprete. Aunque no se puede procesar en O (N), no creo que podamos acercarnos a tu peor de los casos ... –

14

Espero que la compilación del código de plantilla se acelere al tener plantillas variadicas/referencias de valores. Hoy, si queremos escribir un código de plantilla que haga algo en tiempo de compilación, abusamos de las reglas del lenguaje. Creamos docenas de sobrecargas y especializaciones de plantillas que resultan en lo que queremos, pero no de una manera que le indique al compilador nuestra intención. Así que hay muy poco atajo para el compilador en tiempo de compilación. Ver Motivation for variadic templates

¿Existen proyectos para desarrollar una nueva generación de compiladores C++ que optimicen esto?

Sí, hay CLang que es un frontend de lenguaje C para la infraestructura del compilador LLVM. Tanto CLang como LLVM están codificados usando C++. Entre los desarrolladores de CLang se encuentra Douglas Gregor, autor de varias propuestas de lenguaje de C++ 1x como plantillas variadas y conceptos. Para referencia, ver esta prueba por Douglas Gregor de sonido metálico contra GCC

http://www.freeimagehosting.net/uploads/a2e6f1dc27.png

Aquí están algunos resultados de rendimiento sucio Quick-n-para instancias de plantilla en Clang y GCC 4.2.La prueba es muy simple: mida el tiempo de compilación (-fsyntax-only) para una unidad de traducción que calcule el N-ésimo número de Fibonacci a través de un metaprograma de plantilla. Clang parece estar escalando linealmente (o cerca de él) con el número de instancias. Y, aunque no puede verlo en el gráfico, Clang es un poco más de 2 veces más rápido que GCC al principio (Fibonacci<100>).

CLang todavía está en su early days pero creo que tiene buenas posibilidades de convertirse en un gran compilador de C++.

7

El principal problema con plantillas es la siguiente:

Usted no puede (por lo general) separar la definición de la clase de las plantillas de su declaración y ponerlo dentro de un archivo .cpp.

La consecuencia: Todo está en archivos de encabezado. Cuando incluye un encabezado, incluye una gran cantidad de código que, en circunstancias normales, se separaría muy bien en archivos .cpp y se compilaría por separado. Cada unidad de compilación incluye algunos encabezados, por lo que, con las plantillas, cada unidad de compilación contiene mucho de código, o casi todo su proyecto, a través de los encabezados incluidos.

Si ese es su problema, entonces mira aquí, a una pregunta relacionada:

Se puso un very good answer, lo que resolver ese problema.

Básicamente, implica crear instancias de las plantillas que necesita una vez y compilarlas en un archivo objeto. Más tarde puede vincularlo y no tiene que incluir ese código en todas partes. Está separado en un archivo de objeto compilado. Nota: Esto solo tiene sentido si usa solo algunos tipos de plantillas creadas con su instancia (por ejemplo, solo necesita MyType<int> y MyType<double> en su programa).

Utiliza la bandera g++ .

Esa técnica es tan útil que creo que debe ser incorporado en el FAQ de C++: [35.12] Why can't I separate the definition of my templates class from it's declaration and put it inside a .cpp file?

+0

Por supuesto que tienes razón. Todo está en archivos de encabezado. Pero eso no significa que no pueda estar en archivos de encabezado separados. Trabajo todos los días con clases de plantillas separadas en dos conjuntos de archivos de encabezado: declaración e implementación ... –

+0

... ¿Por qué no agregar otro para la declaración de reenvío? De todos modos, los archivos cpp reales contienen parámetros de implementación e instancia de plantilla. Funciona muy bien, pero desafortunadamente no ayuda mucho en lo que respecta a la velocidad de compilación. –

+0

Mi primer comentario: simplemente poner declaraciones de plantillas e implementaciones en archivos de encabezado separados no ayudará a la velocidad de compilación. Aún debe incluir ambos para cada unidad de compilación, si no utiliza el truco descrito en mi respuesta. – Frank

2

El gold linker puede ayudar a disminuir el enlace en tiempo de aproximadamente 5 veces, lo que puede reducir el tiempo total de compilación. Es particularmente útil ya que los enlaces no se pueden paralelizar de la misma manera que la compilación.

(No es una respuesta directa, pero espero que esto sea útil).

Cuestiones relacionadas