meaning installed instalar for optimization gcc compiler-construction clang benchmarking

optimization - installed - llvm



Clang vs GCC-¿Qué produce mejores binarios? (7)

Actualmente estoy usando GCC, pero descubrí Clang recientemente y estoy considerando cambiarme. Sin embargo, hay un factor decisivo: la calidad (velocidad, huella de memoria, confiabilidad) de los binarios que produce: si gcc -O3 puede producir un binario que se ejecute un 1% más rápido o que requiera un 1% menos de memoria, es un factor decisivo.

Clang cuenta con mejores velocidades de compilación y menor huella de memoria en tiempo de compilación que GCC, pero estoy realmente interesado en los puntos de referencia / comparaciones del software compilado resultante. ¿Podría señalar algunas o describir sus experiencias?


Aquí hay algunos hallazgos actualizados, aunque limitados, de la mina con GCC 4.7.2 y Clang 3.2 para C ++.

ACTUALIZACIÓN: GCC 4.8.1 v clang 3.3 comparación adjunta a continuación.

ACTUALIZACIÓN: GCC 4.8.2 v clang 3.4 comparación se adjunta a eso.

Mantengo una herramienta OSS construida para Linux con GCC y Clang, y con el compilador de Microsoft para Windows. La herramienta, coan, es un preprocesador y analizador de archivos fuente y líneas de código de C / C ++ de tales: su perfil computacional se enfoca en el análisis y manejo de archivos de origen recursivo. La rama de desarrollo (a la que pertenecen estos resultados) comprende actualmente alrededor de 11K LOC en aproximadamente 90 archivos. Está codificado, ahora, en C ++ que es rico en polimorfismo y plantillas y que todavía está atascado en muchos parches por su pasado no tan lejano en la semántica hackeada. C. La semántica de Move no se explota expresamente. Es de un solo hilo. No he dedicado ningún esfuerzo serio a optimizarlo, mientras que la "arquitectura" sigue siendo en gran medida ToDo.

Empleé Clang antes de 3.2 solo como compilador experimental porque, a pesar de su velocidad de compilación y diagnósticos superiores, su soporte estándar de C ++ 11 se retrasó con respecto a la versión contemporánea de GCC en los aspectos ejercidos por coan. Con 3.2, esta brecha se ha cerrado.

Mi arnés de prueba de Linux para el desarrollo actual de coan procesa aproximadamente 70K archivos de fuentes en una mezcla de casos de prueba de analizador de un archivo, pruebas de estrés que consumen miles de archivos y pruebas de escenarios que consumen <1K archivos. Además de informar los resultados de la prueba, el arnés se acumula y muestra los totales de archivos consumidos y el tiempo de ejecución consumido en coan (solo pasa cada línea de comando de coan al comando de time Linux y captura y suma los números reportados). Los tiempos se ven halagados por el hecho de que cualquier número de pruebas que tomen 0 tiempo medible se sumarán a 0, pero la contribución de tales pruebas es insignificante. Las estadísticas de tiempo se muestran al final de make check esta manera:

coan_test_timer: info: coan processed 70844 input_files. coan_test_timer: info: run time in coan: 16.4 secs. coan_test_timer: info: Average processing time per input file: 0.000231 secs.

Comparé el rendimiento del arnés de prueba entre GCC 4.7.2 y Clang 3.2, todas las cosas son iguales excepto los compiladores. A partir de Clang 3.2, ya no necesito ninguna diferenciación de preprocesador entre los fragmentos de código que GCC compilará y las alternativas de Clang. Construí a la misma biblioteca de C ++ (GCC) en cada caso y ejecuté todas las comparaciones consecutivamente en la misma sesión terminal.

El nivel de optimización predeterminado para mi versión de lanzamiento es -O2. También he probado con éxito compilaciones en -O3. Probé cada configuración 3 veces seguidas y promedié los 3 resultados, con los siguientes resultados. El número en una celda de datos es el número promedio de microsegundos consumidos por el ejecutable coan para procesar cada uno de los archivos de entrada de ~ 70K (lectura, análisis y salida de escritura y diagnósticos).

| -O2 | -O3 |O2/O3| ----------|-----|-----|-----| GCC-4.7.2 | 231 | 237 |0.97 | ----------|-----|-----|-----| Clang-3.2 | 234 | 186 |1.25 | ----------|-----|-----|------ GCC/Clang |0.99 | 1.27|

Es muy probable que cualquier aplicación particular tenga rasgos que jueguen injustamente con las fortalezas o debilidades de un compilador. El riguroso benchmarking emplea diversas aplicaciones. Teniendo esto en cuenta, las características notables de estos datos son:

  1. -O3 optimización fue marginalmente perjudicial para GCC
  2. La optimización de O3 fue muy importante para Clang
  3. En la optimización de -O2, GCC fue más rápido que Clang por solo un bigote
  4. En la optimización de -O3, Clang fue significativamente más rápido que GCC.

Otra comparación interesante de los dos compiladores surgió por accidente poco después de esos hallazgos. Coan emplea generosamente punteros inteligentes y uno de ellos se ejerce en gran medida en el manejo de archivos. Este tipo de puntero inteligente en particular se había tipificado en versiones anteriores por el bien de la diferenciación del compilador, para ser un std::unique_ptr<X> si el compilador configurado tenía un soporte suficientemente maduro para su uso como tal, y por lo demás un std::shared_ptr<X> . El sesgo hacia std::unique_ptr era absurdo, ya que estos punteros en realidad se transfirieron, pero std::unique_ptr parecía la opción más std::unique_ptr para reemplazar std::auto_ptr en un momento en el que las variantes de C ++ 11 eran nuevas para mí.

En el curso de compilaciones experimentales para medir la necesidad continua de Clang 3.2 de esto y una diferenciación similar, construí inadvertidamente std::shared_ptr<X> cuando tenía la intención de construir std::unique_ptr<X> , y me sorprendió observar eso el ejecutable resultante, con la optimización predeterminada de -O2, fue el más rápido que había visto, a veces logrando 184 ms. por archivo de entrada. Con este cambio al código fuente, los resultados correspondientes fueron estos;

| -O2 | -O3 |O2/O3| ----------|-----|-----|-----| GCC-4.7.2 | 234 | 234 |1.00 | ----------|-----|-----|-----| Clang-3.2 | 188 | 187 |1.00 | ----------|-----|-----|------ GCC/Clang |1.24 |1.25 |

Los puntos a destacar aquí son:

  1. Ninguno de los compiladores ahora se beneficia en absoluto de la optimización -O3.
  2. Clang supera a GCC de la misma manera en cada nivel de optimización.
  3. El rendimiento de GCC solo se ve afectado marginalmente por el cambio de tipo de puntero inteligente.
  4. El rendimiento de Clang -O2 se ve afectado de manera importante por el cambio de tipo de puntero inteligente.

Antes y después del cambio de tipo de puntero inteligente, Clang puede generar un ejecutable coan sustancialmente más rápido en la optimización de -O3, y puede construir un ejecutable igualmente más rápido en -O2 y -O3 cuando ese tipo de puntero es el mejor - std::shared_ptr<X> - para el trabajo.

Una pregunta obvia sobre la que no soy competente para comentar es por qué Clang debería poder encontrar una aceleración del 25% -O2 en mi aplicación cuando un tipo de puntero inteligente muy usado se cambia de único a compartido, mientras que GCC es indiferente al mismo cambio. Tampoco sé si debo animar o abuchear el descubrimiento de que la optimización de Clang-O2 alberga una sensibilidad tan enorme a la sabiduría de mis opciones de puntero inteligente.

ACTUALIZACIÓN: GCC 4.8.1 v clang 3.3

Los resultados correspondientes ahora son:

| -O2 | -O3 |O2/O3| ----------|-----|-----|-----| GCC-4.8.1 | 442 | 443 |1.00 | ----------|-----|-----|-----| Clang-3.3 | 374 | 370 |1.01 | ----------|-----|-----|------ GCC/Clang |1.18 |1.20 |

El hecho de que los cuatro ejecutables ahora tomen un tiempo promedio mucho mayor que el procesado previamente para un archivo 1 no refleja el rendimiento de los últimos compiladores. Es debido al hecho de que la rama de desarrollo posterior de la aplicación de prueba ha adquirido una gran cantidad de sofisticación de análisis mientras tanto y la paga en velocidad. Sólo los ratios son significativos.

Los puntos notables ahora no son sorprendentemente nuevos:

  • GCC es indiferente a la optimización -O3
  • clang se beneficia muy marginalmente de la optimización -O3
  • clang supera a GCC por un margen igualmente importante en cada nivel de optimización.

Al comparar estos resultados con los de GCC 4.7.2 y el ángulo 3.2, se destaca que GCC ha recuperado alrededor de una cuarta parte de la ventaja del cuello en cada nivel de optimización. Pero dado que la aplicación de prueba se ha desarrollado en gran medida mientras tanto, uno no puede atribuirlo con seguridad a una actualización en la generación de códigos de GCC. (Esta vez, he notado la instantánea de la aplicación desde la cual se obtuvieron los tiempos y puedo usarla nuevamente).

ACTUALIZACIÓN: GCC 4.8.2 v clang 3.4

Terminé la actualización para GCC 4.8.1 v Clang 3.3 diciendo que me atendría a la misma instantánea de coan para actualizaciones posteriores. Pero decidí probar en esa instantánea (rev. 301) y en la última instantánea de desarrollo que tengo que pasa su conjunto de pruebas (rev. 619). Esto da a los resultados un poco de longitud, y tenía otro motivo:

Mi publicación original notó que no había dedicado ningún esfuerzo a optimizar el ritmo de la velocidad. Este fue todavía el caso a partir de rev. 301. Sin embargo, después de haber incorporado el aparato de sincronización en el arnés de prueba de coan, cada vez que ejecutaba el conjunto de pruebas, el impacto en el rendimiento de los últimos cambios me miró a la cara. Vi que a menudo era sorprendentemente grande y que la tendencia era más marcadamente negativa de lo que creía merecer las mejoras en la funcionalidad.

Por rev. 308 el tiempo promedio de procesamiento por archivo de entrada en el conjunto de pruebas se ha duplicado con creces desde la primera publicación aquí. En ese momento hice una vuelta en U en mi política de 10 años de no preocuparme por el rendimiento. En la serie intensiva de revisiones, hasta el rendimiento de 619 siempre fue una consideración, y una gran cantidad de ellas se dedicó exclusivamente a reescribir portadores de carga clave en líneas fundamentalmente más rápidas (aunque sin utilizar ninguna característica de compilador no estándar para hacerlo). Sería interesante ver la reacción de cada compilador ante este cambio de sentido,

Aquí está la ahora familiar matriz de tiempos para las últimas compilaciones de compiladores de rev.301:

coan - rev.301 resultados

| -O2 | -O3 |O2/O3| ----------|-----|-----|-----| GCC-4.8.2 | 428 | 428 |1.00 | ----------|-----|-----|-----| Clang-3.4 | 390 | 365 |1.07 | ----------|-----|-----|------ GCC/Clang | 1.1 | 1.17|

La historia aquí se cambia solo marginalmente de GCC-4.8.1 y Clang-3.3. La muestra de GCC es un poco mejor. Clang''s es un poco peor. El ruido bien podría explicar esto. Clang aún sale adelante con -O2 de -O2 y -O2 que no importan en la mayoría de las aplicaciones pero que sí importan a unos pocos.

Y aquí está la matriz para rev. 619.

coan - rev.619 resultados

| -O2 | -O3 |O2/O3| ----------|-----|-----|-----| GCC-4.8.2 | 210 | 208 |1.01 | ----------|-----|-----|-----| Clang-3.4 | 252 | 250 |1.01 | ----------|-----|-----|------ GCC/Clang |0.83 | 0.83|

Tomando el 301 y el 619 figuras lado a lado, varios puntos hablan.

  • Mi objetivo era escribir código más rápido, y ambos compiladores reivindican enfáticamente mis esfuerzos. Pero:

  • GCC paga esos esfuerzos mucho más generosamente que Clang. En la optimización de -O2 la construcción 619 de Clang es un 46% más rápida que su versión 301: en la mejora de -O3 Clang es del 31%. Bien, pero en cada nivel de optimización, la versión 619 de GCC es más del doble de rápida que la 301.

  • GCC más que invierte la anterior superioridad de Clang. Y en cada nivel de optimización, GCC ahora supera a Clang en un 17%.

  • La capacidad de Clang en la compilación 301 para obtener más apalancamiento que la optimización GCC de -O3 se ha ido en la compilación 619. Ninguno de los compiladores gana significativamente de -O3 .

Me sorprendió lo suficiente esta inversión de fortuna que sospeché que podría haber hecho accidentalmente una compilación lenta del propio Clang 3.4 (desde que lo construí desde la fuente). Así que volví a ejecutar la prueba 619 con el stock de mi distro Clang 3.3. Los resultados fueron prácticamente los mismos que para 3.4.

Así que en lo que respecta a la reacción al cambio de sentido: en los números aquí, Clang ha hecho mucho mejor que GCC a la velocidad de escurrido de mi código C ++ cuando no le estaba dando ninguna ayuda. Cuando me puse a ayudar, GCC hizo un trabajo mucho mejor que Clang.

No elevo esa observación a un principio, pero tomo la lección de que "¿Qué compilador produce los mejores binarios?" es una pregunta que, incluso si especifica el conjunto de pruebas con el que la respuesta será relativa, aún no es una cuestión clara de solo cronometrar los binarios.

¿Es su mejor binario el binario más rápido, o es el que mejor compensa el código elaborado a bajo costo? ¿O lo mejor es compensar el código caro que prioriza el mantenimiento y la reutilización sobre la velocidad? Depende de la naturaleza y los pesos relativos de sus motivos para producir el binario y de las restricciones bajo las cuales lo hace.

Y, en cualquier caso, si te importa mucho crear "los mejores" binarios, entonces es mejor que sigas comprobando cómo las iteraciones sucesivas de los compiladores entregan tu idea de "lo mejor" sobre las iteraciones sucesivas de tu código.


Básicamente hablando, la respuesta es: depende. Hay muchos puntos de referencia que se centran en diferentes tipos de aplicaciones.

Mi punto de referencia en mi aplicación es: gcc> icc> clang.

Hay IO raros, pero muchas operaciones de estructura de datos y flotación de CPU.

Los indicadores de compilación son -Wall -g -DNDEBUG -O3.

https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark


El hecho de que Clang compile el código más rápido puede no ser tan importante como la velocidad del binario resultante. Sin embargo, aquí hay una serie de puntos de referencia .


Hay una diferencia general muy pequeña entre GCC 4.8 y el ángulo 3.3 en términos de velocidad del binario resultante. En la mayoría de los casos, el código generado por ambos compiladores funciona de manera similar. Ninguno de estos dos compiladores domina al otro.

Los puntos de referencia que indican que existe una brecha de rendimiento significativa entre GCC y el sonido son coincidentes.

El rendimiento del programa se ve afectado por la elección del compilador. Si un desarrollador o un grupo de desarrolladores utiliza exclusivamente GCC, se puede esperar que el programa se ejecute un poco más rápido con GCC que con Clang, y viceversa.

Desde el punto de vista del desarrollador, una diferencia notable entre GCC 4.8+ y el lenguaje lógico 3.3 es que GCC tiene la opción de línea de comando -Og . Esta opción habilita optimizaciones que no interfieren con la depuración, por lo que, por ejemplo, siempre es posible obtener trazas de pila precisas. La ausencia de esta opción en Clang hace que el Clang sea más difícil de usar como compilador de optimización para algunos desarrolladores.


La única manera de determinar esto es probarlo. FWIW He visto algunas mejoras realmente buenas usando LLVM gcc 4.2 de Apple en comparación con el gcc 4.2 normal (para el código x86-64 con bastante SSE), pero YMMV para diferentes bases de código. Suponiendo que está trabajando con x86 / x86-64 y que realmente se preocupa por el último porcentaje, debería probar el ICC de Intel también, ya que a menudo puede superar a gcc. Puede obtener una licencia de evaluación de 30 días de intel.com. y probarlo


Phoronix hizo algunos benchmarks de benchmarks sobre esto, pero se trata de una versión instantánea de Clang / LLVM de hace unos meses. El resultado es que las cosas fueron más o menos un empujón; Ni GCC ni Clang son definitivamente mejores en todos los casos.

Ya que usarías el último Clang, quizás sea un poco menos relevante. Por otra parte, GCC 4.6 está programado para tener algunas optimizaciones importantes para Core 2 e i7, aparentemente.

Me imagino que la velocidad de compilación más rápida de Clang será mejor para los desarrolladores originales, y luego, cuando introduzcas el código en el mundo, Linux distro / BSD / etc. los usuarios finales utilizarán GCC para los binarios más rápidos.


Una diferencia peculiar que he notado en gcc 5.2.1 y clang 3.6.2 es que si tiene un bucle crítico como:

for (;;) { if (!visited) { .... } node++; if (!*node) break; }

Luego, al compilar con -O2 o -O2 , -O2 desenrollará el bucle de forma especulativa ocho veces. Clang no lo desenrollará en absoluto. A través de prueba y error, descubrí que en mi caso específico con los datos de mi programa, la cantidad correcta de desenrollado es de cinco, por lo que gcc se sobrepasa y clang no. Sin embargo, la sobrecarga fue más perjudicial para el rendimiento, por lo que gcc se desempeñó mucho peor aquí.

No tengo idea de si la diferencia de desenrollamiento es una tendencia general o simplemente algo que fue específico para mi escenario.

Hace un tiempo escribí algunos recolectores de basura para enseñarme más sobre la optimización del rendimiento en C. Y los resultados que obtuve están en mi mente lo suficiente como para favorecer ligeramente el ruido. Sobre todo porque la recolección de basura se basa principalmente en perseguir y copiar memoria.

Los resultados son (números en segundos):

+---------------------+-----+-----+ |Type |GCC |Clang| +---------------------+-----+-----+ |Copying GC |22.46|22.55| |Copying GC, optimized|22.01|20.22| |Mark & Sweep | 8.72| 8.38| |Ref Counting/Cycles |15.14|14.49| |Ref Counting/Plain | 9.94| 9.32| +---------------------+-----+-----+

Todo esto es código C puro y no hago ninguna afirmación sobre el rendimiento de los compiladores cuando compilo el código C ++.

En Ubuntu 15.10, x86.64, y un procesador AMD Phenom (tm) II X6 1090T.