Manualinux
http://www.nvu.com http://www.gimp.org InicioPresentaciónActualizacionesManualesDescargasNoticiasAgradecimientoEnlaces

Entornos GráficosAplicaciones

DesarrolloEmuladoresInternetJuegosMultimediaSistema

Instalar Binutils desde ceroInstalar CMake desde cero

Instalar Clang desde cero

Página - 1Página - 2




Instalar Clang desde cero




Copyright

Copyright © José Luis Lara Carrascal  2012-2024   http://manualinux.es



Sumario

Introducción
Instalación
Configurar el sistema para el uso de Clang
Optimizaciones de CPU para Clang
Niveles de optimización soportados por Clang
Optimizaciones adicionales para Clang
LLD - El enlazador dinámico de LLVM
Libc++ - La librería estándar de C++ de LLVM
Comparativa de resultados de optimización entre Clang y GCC
Enlaces




LLD - El enlazador dinámico de LLVM  

Inicialmente creado para versiones de 64 bits de la arquitectura X86 en sus respectivos formatos: ELF (Unix) y COFF (Windows), el enlazador dinámico alternativo a GNU ld fue reescrito desde cero en mayo de 2015, añadiendo soporte también, de ahí que lo incluyera en su día en este manual, para sistemas de 32 bits. A continuación explico cómo hacer uso del mismo con los sistemas de compilación más utilizados en nuestro sistema. Desde la versión 9 de GCC, también es compatible con este compilador.

1) Establecer el uso de enlazador dinámico para LLD

1a) GNU Autotools, CMake y sistemas de compilación que acepten la variable de entorno LDFLAGS

Establecemos la correspondiente variable de entorno antes de ejecutar el script de configuración del paquete. 

$ export LDFLAGS+=" -fuse-ld=lld"

En aquellos procesos de compilación donde intervenga Libtool, tendremos que modificar el script incluido en el paquete de código fuente, ltmain.sh, a partir del cual se crea el script libtool, con el siguiente comando, para que Libtool soporte el parámetro fuse-ld=, antes de ejecutar el script de configuración pertinente. Como el script puede estar en el directorio raíz del paquete o en un subdirectorio, con el siguiente comando, solucionamos este inconveniente con la ejecución del mismo en el directorio raíz del paquete a configurar.

$ find . -name 'ltmain.sh' | xargs sed -i 's:|-fuse-linker-plugin:&|-fuse-ld=*:' 

Que automatizamos y simplificamos creando una función de Bash que nos facilitará su ejecución en un proceso de compilación, incluyendo confirmación del proceso realizado. Abrimos con un editor de texto, el archivo de configuración personal, ~/.bashrc, si no existe lo creamos, y añadimos lo siguiente al final del contenido del mismo:

function lld-libtool
{
if find . -name 'ltmain.sh' | xargs grep -q '\-fuse-ld=*' ; then
 echo "el parche ya está aplicado"
else
  find . -name 'ltmain.sh' | xargs sed -i 's:|-fuse-linker-plugin:&|-fuse-ld=*:'
 echo "parche aplicado"
fi
}

Cuando ejecutemos el comando lld-libtool dentro del directorio raíz del paquete a compilar que utilice Libtool para el proceso de compilación, éste modificará el archivo correspondiente para que Libtool soporte el parámetro fuse-ld=, mostrando información de la acción realizada.

La versión 2.4.7 de Libtool ya soporta este parámetro, pero esto sólo es válido para paquetes que no contienen el script de configuración y hay que generarlo, ya sea con el script autogen.sh o con el comando autoreconf -vif. Los paquetes de código fuente nunca suelen tener la versión de Libtool actualizada a la última versión, de ahí que, la modificación antes explicada siga siendo necesaria.

En aquellos paquetes en los que hay que generar el script de configuración, en versiones inferiores a la 2.4.7 de Libtool, lo que haremos será, modificar el script del sistema, ltmain.sh, ubicado en /usr/share/libtool/build-aux, para no tener que volver a hacerlo después de haber generado el correspondiente script de configuración.

$ su
# sed -i 's:linker-plugin|:&-fuse-ld=*|:' /usr/share/libtool/build-aux/ltmain.sh

2) Optimizar el uso de LLD cuando se hace uso de la optimización LTO o ThinLTO en los procesos de compilación con Clang

Con los siguientes parámetros, aplicamos las correspondiente optimizaciones complementarias de la optimización LTO utilizada con Clang. Para no sobrecargar los procesos de compilación, recomiendo personalmente, y así, será actualizado en la información ubicada en los manuales de la web, reducir el número de procesos de enlazado a la mitad de los hilos que posea nuestro procesador.

$ export LDFLAGS+=" -Wl,--lto-partitions=$(expr $(nproc) / 2)"

Si nuestro procesador es mononúcleo de un solo hilo, no es necesario añadir esto. 

Con ThinLTO, la variable de entorno a utilizar es la siguiente:

$ export LDFLAGS+=" -Wl,--thinlto-jobs=$(expr $(nproc) / 2)"

Si nuestro procesador es mononúcleo de un solo hilo, no es necesario añadir esto. 

3) Utilizar un directorio de caché de archivos objeto en los procesos de compilación con la optimización ThinLTO (desde LLVM 4 con GNU gold y desde LLVM 5 con LLD)

En determinados procesos de compilación con una gran cantidad de archivos objeto a procesar por el enlazador dinámico, cuando utilizamos la optimización ThinLTO, es posible el uso de un directorio de caché específico de archivos objeto, en lugar, de utilizar el predefinido del sistema, que es /tmp. Si tenemos montado este directorio con el sistema de archivos tmpfs, la limitación de tamaño del mismo queda siempre establecida en el 50 % de la memoria física disponible en nuestro sistema.

La finalidad última de utilizar un directorio caché de archivos objeto, es siempre la de acelerar el proceso de enlazado de los archivos objeto para generar el archivo binario correspondiente. En procesos de compilación que interviene Libtool, nos ahorra el tener que volver a generar dichos archivos cuando se ejecuta el proceso de instalación de los binarios compilados, ya que éstos ya estarán almacenados en el directorio de caché correspondiente.

El principal inconveniente cuando estamos hablando de caché, es siempre el espacio en disco que ocupa ésta que, a medida que se vaya haciendo grande, hará el acceso a la misma más lento. Afortunadamente, con los parámetros correspondientes a pasarle a LLD, podremos controlar el tamaño de dicho directorio, evitando crear un problema en haras de intentar optimizar más todavía los procesos de compilación. Antes que nada, lo que haremos será crear el directorio de caché, procurando siempre utilizar una partición o disco duro que no sea el principal del sistema, y en la que tengamos instalada otra distribución de linux. Si no hay más remedio que utilizar la partición principal, elegiremos el directorio habitual para este tipo de archivos, /var/cache, en el que crearemos un subdirectorio con el nombre thinlto, y le daremos permisos de escritura para todos los usuarios.

$ su -c "install -dm777 /var/cache/thinlto"

Establecemos la correspondiente variable de entorno LDFLAGS, después de las explicadas anteriormente, antes de ejecutar el script de configuración del paquete:

$ export LDFLAGS+=" -Wl,--thinlto-cache-dir=/var/cache/thinlto"

Establecemos otra variable de entorno para controlar el tamaño del directorio de caché. En el ejemplo, un 20 % del tamaño libre disponible de la partición en la que se encuentre dicho directorio:

$ export LDFLAGS+=" -Wl,--thinlto-cache-policy,cache_size=20%"

Las opciones de control de la caché admiten más parámetros, que se pueden añadir al anterior en color rojo, separados por dos puntos. A continuación explico todas las opciones de configuración posibles.

Opciones de configuración de la política de control del directorio de caché cuando se utiliza la optimización ThinLTO
Parámetro Descripción
prune_interval=nº|s|m|h
Define cada cuanto tiempo en segundos será escaneado el directorio de caché para buscar los archivos objeto con fecha de expiración y candidatos a ser eliminados. Esta opción evita un constante escaneo de disco con la consiguiente carga que supone para el sistema. Un valor de 0, fuerza el escaneo continuo y un valor de Nonedesactiva la política de expiración de archivos objeto basada en este parámetro. El valor predefinido es de 20 minutos. El parámetro admite segundos (s), minutos (m) y horas (h). Un ejemplo:

prune_interval=30s
prune_after=nº|s|m|h
Define el tiempo de expiración de un archivo objeto de la caché. Un valor de 0, desactiva la política de expiración de archivos objeto basada en este parámetro. El parámetro admite segundos (s), minutos (m) y horas (h). El valor predefinido es de una semana. Un ejemplo, estableciendo la fecha de expiración en un mes:

prune_after=720h
cache_size=nº% Define en porcentaje el tamaño máximo del espacio en disco libre de la partición que será destinado al directorio de caché. Un valor de 0, desactiva la política de expiración de archivos objeto basada en este parámetro. Un valor de 100 habilita todo el espacio libre disponible. Como es evidente, valores superiores a 100 no son válidos. Un ejemplo:

cache_size=20%
cache_size_bytes=
Define el tamaño máximo del directorio de caché. El parámetro admite bytes, kilobytes (k), megabytes (m) y gigabytes (g). Cualquier valor superior al real disponible de espacio libre en la partición, será reducido a este último. Un valor de 0, desactiva la política de expiración de archivos objeto basada en este parámetro. Un ejemplo, con un tamaño de directorio de 2 GB:

cache_size_bytes=2g
cache_size_files= Define el número máximo de archivos objeto que contendrá el directorio de caché. Un valor de 0, desactiva la política de expiración de archivos objeto basada en este parámetro. El valor por defecto es 1000000. Un ejemplo:

cache_size_files=500000

Una vez sabemos todas las opciones posibles, elegimos las más interesantes, y configuramos la correspondiente variable de entorno, todo en uno, relacionado con este tema concreto. Tener en cuenta que si establecemos diferentes políticas de expiración, unas terminarán solapando a las otras. Es evidente que la candidata a ser más utilizada es la del tamaño máximo disponible de espacio libre en la partición.

$ export LDFLAGS+=" -Wl,--thinlto-cache-policy,prune_interval=30s:prune_after=720h:cache_size=20%"

Probablemente algunos usuarios, entre los que me encuentro yo, prefieran utilizar un tamaño máximo de directorio, en lugar, de tener que especular con el espacio libre disponible en la partición. Un ejemplo sería éste, que establecería el límite del tamaño máximo de la caché en 2 GB.

$ export LDFLAGS+=" -Wl,--thinlto-cache-policy,prune_after=720h:cache_size_bytes=2g"

Si utilizamos la optimización ThinLTO con GNU gold, también podemos hacer uso de dicho directorio, para almacenar los archivos objeto, pero no podremos controlar el tamaño de la caché ni el límite de caducidad en el tiempo de los archivos objeto contenidos en la misma.

$ export LDFLAGS+=" -Wl,-plugin-opt,cache-dir=/var/cache/thinlto"

4) Incluir pases de análisis y transformación de LLVM en el proceso de optimización LTO de LLD 

Para elevar aún más el nivel de optimización LTO de LLD, también podemos incluir en dicho proceso, los pases de análisis y transformación en tubería utilizados por LLVM (dando por hecho que hemos activado también New Pass Manager con Clang), con los siguientes parámetros, en los que incluyo un ejemplo de pase de análisis y otro de transformación, el uno seguido del otro porque deben de ir siempre en combinación.

$ export LDFLAGS+=" -Wl,--lto-aa-pipeline=basic-aa -Wl,--lto-newpm-passes=loweratomic"

Todos los valores posibles de pases de análisis y transformación los podemos encontrar en este archivo entrecomillados en color rojo. Unos son los de análisis (*_ANALYSIS) y otros son los de transformación (*_PASS). Uno que funciona muy bien en combinación con PGO es el siguiente:

$ export LDFLAGS+=" -Wl,--lto-aa-pipeline=globals-aa -Wl,--lto-newpm-passes=pgo-memop-opt"

Para saber todas las opciones posibles de LLD, ejecutamos el siguiente comando:

$ ld.lld --help

Y como no podía ser de otra forma, los correspondientes alias y funciones de bash para facilitar su uso, el número de núcleos se obtiene con el comando correspondiente, evitando tener que editar los alias cuando cambiemos de CPU:

alias clang-lld="export LDFLAGS+=' -fuse-ld=lld'"

lld-lto () { export LDFLAGS+=" -Wl,--lto-partitions="
$(expr $(nproc) / 2)" ; }

lld--thinlto () { export LDFLAGS+=" -Wl,--thinlto-jobs="
$(expr $(nproc) / 2)" ; }

alias lld--thinlto-cache="export LDFLAGS+=' -Wl,--thinlto-cache-dir=var/cache/thinlto -Wl,--thinlto-cache-policy,prune_after=720h:cache_size_bytes=2g'"

Con clang-lld, activamos el uso de LLD como enlazador dinámico, con lld-lto, activamos las correspondientes optimizaciones complementarias de LTO y con lld--thinlto las correspondientes a ThinLTO. Y por último, con lld-thinlto-cache, activamos el uso del directorio de caché, allí donde su uso sea realmente necesario y acelere el proceso de compilación.

A partir de LLD 11, sólo se admiten opciones de un guión que sean compatibles con GNU ld. Dicho de otro modo más claro, lo que en versiones anteriores es correcto, después del parámetro -Wl,:

$ export LDFLAGS+=" -Wl,-lto-partitions=$(expr $(nproc) / 2)"

Ahora no lo es, y se tienen que añadir dos guiones antes de la opción a pasarle a LLD.

$ export LDFLAGS+=" -Wl,--lto-partitions=$(expr $(nproc) / 2)"

En las que son compatibles con GNU ld, sí se puede seguir utilizando sólo un guión.



Libc++ - La librería estándar de C++ de LLVM

A partir de la versión 11 de Clang, he decidido incluir en el manual y en el paquete de código fuente de descarga, la nueva implementación de la librería estándar C++ proporcionada por LLVM, libc++, con soporte completo de los estándares C++11 y C++14, y un soporte parcial de C++17. También se incluye libc++abi, que proporciona una implementación de bajo nivel para libc++. Para hacer uso de la misma en los procesos de compilación, establecemos la correspondiente variable de entorno antes de ejecutar el comando de configuración.

En lugar de utilizar el nombre de la ruta de instalación, utilizamos el comando llvm-config, para así, no tener que cambiar dichar ruta en los alias que tengamos, cada vez que actualicemos el compilador a otra versión del mismo.

$ export CXXFLAGS+=" -stdlib=libc++ -I$(llvm-config --includedir)/c++/v1"
$ export LDFLAGS+=" -L$(llvm-config --libdir)"

Por norma general, los parámetros con el prefijo '-I' se suelen establecer con la variable de entorno CPPFLAGS, pero en este caso, si queremos que no se produzcan errores en la detección de las dependencias de un paquete, tendremos que incluirlo en la variable de entorno CXXFLAGS, ya que por defecto, Clang buscará las cabeceras de C++ de GCC, que son con las que se ha compilado e instalado el programa.

La variable de entorno LDFLAGS se debe de establecer para que el enlazador dinámico, encuentre la librería correspondiente, ya sea LLD o GNU gold. Si hubiera algún problema específico de enlazado en algún paquete, podemos utilizar también la siguiente variable, más amplia:

$ export LDFLAGS+=" -L$(llvm-config --libdir) -lc++ -lc++abi"

También la podemos utilizar con GCC, estableciendo las siguientes variables de entorno:

$ export CXXFLAGS+=" -nostdinc++ -I$(llvm-config --includedir)/c++/v1"
$ export LDFLAGS+=" -nodefaultlibs -L$(llvm-config --libdir) -lc++ -lc++abi -lm -lc -lgcc_s"

Los parámetros han sido probados en la compilación de DAR y son funcionales con este paquete. Si ejecutamos el comando ldd para comprobar las librerías contra las que está enlazado el binario ejecutable dar, veremos que tanto libc++ como libc++abi, aparecen en primer lugar, y libstdc++, aparece más abajo, como dependencia secundaria a través de las librerías contra las que está enlazado dicho binario. El ejemplo se muestra recortado hasta libstdc++.

[jose@localhost bin]$ ldd dar
        linux-vdso.so.1 (0x00007ffcec7b9000)
        libc++.so.1 => /opt/llvm12/lib64/libc++.so.1 (0x00007f2c6e045000)
        libc++abi.so.1 => /opt/llvm12/lib64/libc++abi.so.1 (0x00007f2c6e005000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f2c6dec0000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f2c6dcca000)
        libgcc_s.so.1 => /opt/gcc10/lib64/libgcc_s.so.1 (0x00007f2c6dcb0000)
        libdar64.so.6000 => /tmp/dar/usr/lib64/libdar64.so.6000 (0x00007f2c6da2c000)
        libcurl.so.4 => /usr/lib64/libcurl.so.4 (0x00007f2c6d9a7000)
        libgpgme.so.11 => /usr/lib64/libgpgme.so.11 (0x00007f2c6d94b000)
        libassuan.so.0 => /usr/lib64/libassuan.so.0 (0x00007f2c6d92b000)
        libthreadar.so.1000 => /usr/lib64/libthreadar.so.1000 (0x00007f2c6d91d000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2c6d8fd000)
        librsync.so.2 => /usr/lib64/librsync.so.2 (0x00007f2c6d8f0000)
        libattr.so.1 => /lib64/libattr.so.1 (0x00007f2c6d8e8000)
        libgcrypt.so.20 => /usr/lib64/libgcrypt.so.20 (0x00007f2c6d784000)
        libgpg-error.so.0 => /usr/lib64/libgpg-error.so.0 (0x00007f2c6d761000)
        liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f2c6d730000)
        liblzo2.so.2 => /usr/lib64/liblzo2.so.2 (0x00007f2c6d6ee000)
        libbz2.so.1.0 => /lib64/libbz2.so.1.0 (0x00007f2c6d6d6000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f2c6d4b6000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f2c6d4b1000)
        libcap.so.2 => /lib64/libcap.so.2 (0x00007f2c6d4aa000)
        libsocket.so => /usr/lib64/libsocket.so (0x00007f2c6d4a5000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f2c6d49c000)
        libatomic.so.1 => /opt/gcc10/lib64/libatomic.so.1 (0x00007f2c6d493000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2c6e186000)
        libstdc++.so.6 => /opt/gcc10/lib/../lib64/libstdc++.so.6 (0x00007f2c6d27f000)

Con PatchELF lo podemos comprobar de una manera más clara:

[jose@localhost bin]$ patchelf --print-needed dar
libdar64.so.6000
libcurl.so.4
libgpgme.so.11
libassuan.so.0
libthreadar.so.1000
libpthread.so.0
librsync.so.2
libattr.so.1
libgcrypt.so.20
libgpg-error.so.0
liblzma.so.5
liblzo2.so.2
libbz2.so.1.0
libz.so.1
libdl.so.2
libcap.so.2
libsocket.so
libc++.so.1
libc++abi.so.1
libm.so.6
libgcc_s.so.1
libc.so.6

Pero vuelvo a repetir, si no nos queremos complicar la vida, utilicemos la librería estándar de C++ del sistema, es decir, la que proporciona GCC, pero por experimentar que no quede. Y como no podía ser de otra forma, los correspondientes alias que en este caso son funciones de bash para facilitar su uso:

optclang-cxx () { export CXXFLAGS+=" -stdlib=libc++ -I$(llvm-config --includedir)/c++/v1" ; \
export LDFLAGS+=" -L$(llvm-config --libdir)" ; }

optgcc-cxx () { export CXXFLAGS+=" -nostdinc++ -I$(llvm-config --includedir)/c++/v1" ; \
export LDFLAGS+=" -nodefaultlibs -L$(llvm-config --libdir) -lc++ -lc++abi -lm -lc -lgcc_s" ; }


En aquellos manuales que sea posible se irán incluyendo estos parámetros como opción de uso de esta librería con Clang, omitiendo el uso con GCC.



Comparativa de resultados de optimización entre Clang y GCC

Tomando como referencia la compilación del programa Openbox, pongo a continuación una tabla de resultados de optimización entre Clang y GCC, utilizando los mismos parámetros de optimización, que son equivalente entre sí. En esta tabla se mide el tiempo de compilación (12 procesos en paralelo) y el tamaño resultante del binario openbox, después de haberse compilado en el directorio y también después de haberlo instalado con el comando make install-strip que elimina los símbolos innecesarios para la ejecución del programa.

Para medir el tiempo de compilación se sustituye el comando de compilación por el siguiente:

$ date &> inicio.log; make; date &> final.log

Y hacemos la correspondiente resta: hora de inicio (inicio.log) - hora final (final.log) = tiempo total de compilación.

En compilaciones cortas, como es el caso de ésta, podemos utilizar este comando (sin volcar nada a ningún archivo) y ver el resultado en la pantalla, eso sí, tendremos que desplazarnos hacia arriba en la ventana de terminal, para buscar la hora de inicio.

$ date; make; date

En paquetes en los que la compilación es en modo silencioso por defecto, añadir el parámetro V=1 o VERBOSE=1 si se han configurado con CMake, al comando make, o -v si utilizamos el comando ninja, para poder ver los parámetros de optimización aplicados al paquete.

Como siempre esto se puede automatizar hasta cierto punto, con los correspondiente alias de bash, un ejemplo con los míos, sustituir 12 por el número de núcleos o núcleos más hilos, que tenga el procesador de cada usuario. Abrimos con un editor de texto, el archivo de configuración personal, ~/.bashrc, si no existe lo creamos, y añadimos lo siguiente al final del contenido del mismo:

alias makej1="date +"%H:%M:%S" &> inicio.log; make V=1; date +"%H:%M:%S" &> final.log"
alias makej="date +"%H:%M:%S" &> inicio.log; make V=1 -j12; date +"%H:%M:%S" &> final.log"
alias cmakej1="date +"%H:%M:%S" &> inicio.log; make VERBOSE=1; date +"%H:%M:%S" &> final.log"
alias cmakej="date +"%H:%M:%S" &> inicio.log; make VERBOSE=1 -j12; date +"%H:%M:%S" &> final.log"
alias ninjaj1="date +"%H:%M:%S" &> inicio.log; ninja -v -j1; date +"%H:%M:%S" &> final.log"
alias ninjaj="date +"%H:%M:%S" &> inicio.log; ninja -v -j12; date +"%H:%M:%S" &> final.log"


Y finalmente creamos un script para poder hacer la correspondiente resta. Necesitaremos el programa datediff, que forma parte del paquete Dateutils. Abrimos un editor de texto y añadimos lo siguiente:

#!/bin/sh

date1=`cat inicio.log`
date2=`cat final.log`

ddiff $date1 $date2 -f '%Hh %Mm %Ss'


Lo guardamos con el nombre tiempo y lo instalamos en /usr/bin.

$ su -c "install -m755 tiempo /usr/bin"

Y comprobamos que funciona bien, probando a ejecutarlo cuando terminemos de compilar un paquete.

[jose@localhost dateutils-0.4.11]$ tiempo
0h 0m 10s

La última comparativa de esta tabla es con las optimizaciones que suelen llevar la mayoría de paquetes por defecto (-O2). Por último, tener en cuenta que un binario más pequeño no tiene por qué equivaler a un binario más rápido. Las comparativas se han hecho con el modo de ahorro de energía de la CPU establecido en "powersave (balance performance)", y con un kernel parcheado con las funcionalidades proporcionadas por el planificador de CPU, BORE. Como enlazador dinámico de Clang, se utiliza LLD, con todas las optimizaciones incluidas en los manuales de esta web.

Comparativa de resultados de optimización entre Clang 18 y GCC 13, con código escrito en C
Parámetros aplicados Tiempo de compilación Tamaño del binario compilado Tamaño del binario instalado
Clang+O3+CPU+Polly+ThinLTO 4" 444 KB. 360 KB.
GCC+O3+CPU+Graphite+LTO 6"
532 KB. 472 KB.

Clang+O3+CPU+Polly+LTO 6"
472 KB. 376 KB.
GCC+O3+CPU+Graphite+LTO 6"
532 KB. 472 KB.

Clang+O3+CPU+Polly+LTO+ULTO 5" 444 KB. 360 KB.
GCC+O3+CPU+Graphite+LTO 6"
532 KB. 472 KB.

Clang+O3+CPU+Polly 4" 436 KB. 376 KB.
GCC+O3+CPU+Graphite 5" 464 KB. 404 KB.

Clang+O3+CPU+LTO 6" 472 KB. 376 KB.
GCC+O3+CPU+LTO 7" 532 KB. 472 KB.

Clang+O3+CPU+LTO+ULTO 5" 444 KB. 360 KB.
GCC+O3+CPU+LTO 7" 532 KB. 472 KB.

Clang+O3+CPU 4" 436 KB. 376 KB.
GCC+O3+CPU 5" 464 KB. 404 KB.

Clang+O3 4" 420 KB. 360 KB.
GCC+O3 5" 460 KB. 400 KB.

Clang 5" 1,5 MB. 352 KB.
GCC 5" 1,7 MB. 364 KB.
De color amarillo las celdas con los mejores resultados.

Esto es con código escrito en C, pero ahora los compararemos con código escrito en C++, tomando como referencia el manual de instalación de Pekwm. El binario utilizado para la comparación es pekwm_wm.

Comparativa de resultados de optimización entre Clang 18 y GCC 13, con código escrito en C++
Parámetros aplicados Tiempo de compilación Tamaño del binario compilado Tamaño del binario instalado
Clang+O3+CPU+Polly+ThinLTO 6" 1,0 MB. 832 KB.
GCC+O3+CPU+Graphite+LTO 8"
952 KB. 792 KB.

Clang+O3+CPU+Polly+LTO 6"
1,1 MB. 860 KB.
GCC+O3+CPU+Graphite+LTO 8"
952 KB. 792 KB.

Clang+O3+CPU+Polly+LTO+ULTO 6" 1,0 MB. 832 KB.
GCC+O3+CPU+Graphite+LTO 8"
952 KB. 792 KB.

Clang+O3+CPU+Polly 6" 1,1 MB. 908 KB.
GCC+O3+CPU+Graphite 7" 1,2 MB. 1,0 MB.

Clang+O3+CPU+LTO 7" 1,1 MB. 860 KB.
GCC+O3+CPU+LTO 7" 952 KB. 792 KB.

Clang+O3+CPU+LTO+ULTO 6" 1,0 MB. 832 KB.
GCC+O3+CPU+LTO 7" 952 KB. 792 KB.

Clang+O3+CPU 6" 1,1 MB. 912 KB.
GCC+O3+CPU 7" 1,2 MB. 1,0 MB.

Clang+O3 6" 1,1 MB. 880 KB.
GCC+O3 7" 1,2 MB. 988 KB.

Clang 7" 7,4 MB. 864 KB.
GCC 9" 17,7 MB. 864 KB.
De color amarillo las celdas con los mejores resultados.

Y en la última comparativa utilizaremos toda la artillería disponible de cada compilador, compilando ImageMagick.

Comparativa de resultados de optimización entre Clang 18 y GCC 13, en la compilación de ImageMagick
Parámetros aplicados Tiempo de compilación Tamaño del directorio de  compilación Tamaño del paquete instalado
Clang+O3+CPU+Polly+OpenMP+LTO+ULTO 29" 103,1 MB. 22,4 MB.
GCC+O3+CPU+Graphite+OpenMP+LTO 42"
115,2 MB. 24,4 MB.
De color amarillo las celdas con los mejores resultados.

Se ha omitido la optimización IPA de GCC, ya que no existe una equivalente en Clang.



Enlaces


http://llvm.org >> La web del proyecto LLVM.

http://clang.llvm.org >> La sección de la web de LLVM dedicada a Clang

http://lld.llvm.org >> La sección de la web de LLVM dedicada a LLD.

http://polly.llvm.org >> La sección de la web de LLVM dedicada a Polly.

http://compiler-rt.llvm.org >> La sección de la web de LLVM dedicada a Compiler-rt.

http://openmp.llvm.org >> La sección de la web de LLVM dedicada a OpenMP.

http://libcxx.llvm.org >> La sección de la web de LLVM dedicada a Libc++.


Foro Galería Blog


Página - 1Página - 2

Actualizado el 20-03-2024

Instalar Clang desde cero

Instalar Binutils desde ceroInstalar CMake desde cero