Reemplazo de ld con oro, ¿alguna experiencia?

81

¿Alguien ha intentado usar en goldlugar de ld?

gold promete ser mucho más rápido que ld, por lo que puede ayudar a acelerar los ciclos de prueba para grandes aplicaciones C ++, pero ¿se puede usar como reemplazo directo de ld?

¿Puedo gcc/ g++llamar directamente gold?

¿Hay errores o problemas conocidos?

Aunque goldes parte de las binutils de GNU desde hace un tiempo, casi no he encontrado "historias de éxito" o incluso "Howtos" en la Web.

( Actualización: enlaces agregados a oro y entrada de blog que lo explica )

IanH
fuente

Respuestas:

53

Por el momento, está compilando proyectos más grandes en Ubuntu 10.04. Aquí puede instalarlo e integrarlo fácilmente con el binutils-goldpaquete (si elimina ese paquete, obtendrá el antiguo ld). Entonces, Gcc usará oro automáticamente.

Algunas experiencias:

  • el oro no busca en /usr/local/lib
  • gold no asume bibliotecas como pthread o rt, tuvo que agregarlas a mano
  • es más rápido y necesita menos memoria (lo último es importante en grandes proyectos de C ++ con mucho impulso, etc.)

Lo que no funciona: No puede compilar cosas del kernel y, por lo tanto, no tiene módulos del kernel. Ubuntu hace esto automáticamente a través de DKMS si actualiza controladores propietarios como fglrx. Esto falla con ld-gold(tienes que quitar el oro, reiniciar DKMS, reinstalar ld-gold.

cabeza
fuente
Gracias, creo que lo intentaré; las restricciones que mencionas no parecen ser un problema en mi caso.
IanH
+1: gracias por compartir la experiencia. ¿Qué pasa con el rendimiento?
neuro
9
es significativamente más rápido, especialmente al vincular grandes bibliotecas estáticas a un binario, pero no hicimos ninguna medición difícil.
Nob
2
@neuro Mis medidas fueron para vincular muchos objetos y archivos .a en un conjunto de ~ 30 archivos .so (uno grande, el resto pequeño) y 1 ejecutable para una aplicación comercial significativa. Midiendo solo el tiempo de enlace y ejecutando make en serie, obtuve un tiempo total de 22,48 segundos con ld frente a 16,24 segundos con oro, para una mejora de 6,24 segundos por compilación. Sin embargo, si ejecuto make en paralelo con 8 procesadores, la diferencia total es de solo 1,42 segundos por compilación. El uso general de la memoria fue una mejora del 42%, independientemente de la paralelización de marcas. YMMV.
metal
@metal: muchas gracias por las cifras. La mejora en el uso de la memoria se ve muy bien, ldes tan codiciosa.
neuro
40

Como me tomó un poco de tiempo descubrir cómo usar oro selectivamente (es decir, no en todo el sistema usando un enlace simbólico), publicaré la solución aquí. Está basado en http://code.google.com/p/chromium/wiki/LinuxFasterBuilds#Linking_using_gold .

  1. Haz un directorio donde puedas poner un guión de pegamento dorado. Estoy usando ~/bin/gold/.
  2. Coloque el siguiente script de pegamento allí y asígnele un nombre ~/bin/gold/ld:

    #!/bin/bash
    gold "$@"
    

    Obviamente, hacerlo ejecutable, chmod a+x ~/bin/gold/ld.

  3. Cambiar sus llamadas a gccque gcc -B$HOME/bin/goldlo que hace mirada gcc en el directorio dado a los programas de ayuda como ldy por lo tanto utiliza la secuencia de comandos de cola en lugar del sistema de forma predeterminada ld.

Tilman Vogel
fuente
1
¿Eso es necesario para qué sistema operativo? Como dijo nob en su respuesta, para Ubuntu simplemente instale el paquete gold binutils y el compilador lo usará de inmediato. Lo mismo para openSuse.
usr1234567
8
Sí, es bastante fácil reemplazar ld en todo el sistema. Mi respuesta se centró especialmente en cómo utilizar el oro de forma selectiva. Y en ese caso, creo que es necesario para cualquier sistema operativo.
Tilman Vogel
1
@vidstige Sí, la ventaja del script es que busca golden el PATH. Para un enlace simbólico, debe apuntar a la ruta completa.
Tilman Vogel
17

¿Puede gcc / g ++ llamar directamente al oro?

Solo para complementar las respuestas: hay una opción de gcc -fuse-ld=gold(ver gcc doc ). Aunque, AFAIK, es posible configurar gcc durante la compilación de manera que la opción no tenga ningún efecto.

usuario2273896
fuente
5
-fuse-ld=goldno está completo. Si tiene que usar -Wl,-fuse-ld=goldcomo se usa en el momento del enlace.
Nawaz
6
@Nawaz No, -Wl,se usa para pasar una opción directamente a ld; para usar otro enlazador, debes decírselo gcc. Consulte el doc .
calandoa
11

Como desarrollador de Samba, he estado usando el enlazador dorado casi exclusivamente en Ubuntu, Debian y Fedora desde hace varios años. Mi valoración:

  • el oro es muchas veces (sentido: 5-10 veces) más rápido que el enlazador clásico.
  • Inicialmente, hubo algunos problemas, pero han desaparecido aproximadamente desde Ubuntu 12.04.
  • El enlazador dorado incluso encontró algunos problemas de dependencia en nuestro código, ya que parece ser más correcto que el clásico con respecto a algunos detalles. Vea, por ejemplo, este compromiso de Samba .

No he usado oro de forma selectiva, pero he estado usando enlaces simbólicos o el mecanismo alternativo si la distribución lo proporciona.

Michael Adam
fuente
9

Se podría vincular lda gold(en un directorio local binaria si ha ldinstalado para evitar la sobreescritura):

ln -s `which gold` ~/bin/ld

o

ln -s `which gold` /usr/local/bin/ld
Delan Azabani
fuente
5

Punto de referencia sintético mínimo: LD vs oro vs LLVM LLD

Salir:

  • el oro fue de 3 a 4 veces más rápido para todos los valores que probé al usar -Wl,--threads -Wl,--thread-count=$(nproc)para habilitar el subproceso múltiple
  • ¡LLD fue aproximadamente 2 veces más rápido que el oro!

Probado en:

  • Ubuntu 20.04, GCC 9.3.0, binutils 2.34, sudo apt install lldLLD 10
  • Computadora portátil Lenovo ThinkPad P51, CPU Intel Core i7-7820HQ (4 núcleos / 8 subprocesos), 2x RAM Samsung M471A2K43BB1-CRC (2x 16GiB), SSD Samsung MZVLB512HAJQ-000L7 (3.000 MB / s).

Descripción simplificada de los parámetros de referencia:

  • 1: número de archivos de objetos que proporcionan símbolos
  • 2: número de símbolos por archivo de objeto de proveedor de símbolos
  • 3: número de archivos de objetos que utilizan todos los símbolos de símbolos proporcionados

Resultados para diferentes parámetros de referencia:

10000 10 10
nogold:  wall=4.35s user=3.45s system=0.88s 876820kB
gold:    wall=1.35s user=1.72s system=0.46s 739760kB
lld:     wall=0.73s user=1.20s system=0.24s 625208kB

1000 100 10
nogold:  wall=5.08s user=4.17s system=0.89s 924040kB
gold:    wall=1.57s user=2.18s system=0.54s 922712kB
lld:     wall=0.75s user=1.28s system=0.27s 664804kB

100 1000 10
nogold:  wall=5.53s user=4.53s system=0.95s 962440kB
gold:    wall=1.65s user=2.39s system=0.61s 987148kB
lld:     wall=0.75s user=1.30s system=0.25s 704820kB

10000 10 100
nogold:  wall=11.45s user=10.14s system=1.28s 1735224kB
gold:    wall=4.88s user=8.21s system=0.95s 2180432kB
lld:     wall=2.41s user=5.58s system=0.74s 2308672kB

1000 100 100
nogold:  wall=13.58s user=12.01s system=1.54s 1767832kB
gold:    wall=5.17s user=8.55s system=1.05s 2333432kB
lld:     wall=2.79s user=6.01s system=0.85s 2347664kB

100 1000 100
nogold:  wall=13.31s user=11.64s system=1.62s 1799664kB
gold:    wall=5.22s user=8.62s system=1.03s 2393516kB
lld:     wall=3.11s user=6.26s system=0.66s 2386392kB

Este es el script que genera todos los objetos para las pruebas de enlace:

generar-objetos

#!/usr/bin/env bash
set -eu

# CLI args.

# Each of those files contains n_ints_per_file ints.
n_int_files="${1:-10}"
n_ints_per_file="${2:-10}"

# Each function adds all ints from all files.
# This leads to n_int_files x n_ints_per_file x n_funcs relocations.
n_funcs="${3:-10}"

# Do a debug build, since it is for debug builds that link time matters the most,
# as the user will be recompiling often.
cflags='-ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic'

# Cleanup previous generated files objects.
./clean

# Generate i_*.c, ints.h and int_sum.h
rm -f ints.h
echo 'return' > int_sum.h
int_file_i=0
while [ "$int_file_i" -lt "$n_int_files" ]; do
  int_i=0
  int_file="${int_file_i}.c"
  rm -f "$int_file"
  while [ "$int_i" -lt "$n_ints_per_file" ]; do
    echo "${int_file_i} ${int_i}"
    int_sym="i_${int_file_i}_${int_i}"
    echo "unsigned int ${int_sym} = ${int_file_i};" >> "$int_file"
    echo "extern unsigned int ${int_sym};" >> ints.h
    echo "${int_sym} +" >> int_sum.h
    int_i=$((int_i + 1))
  done
  int_file_i=$((int_file_i + 1))
done
echo '1;' >> int_sum.h

# Generate funcs.h and main.c.
rm -f funcs.h
cat <<EOF >main.c
#include "funcs.h"

int main(void) {
return
EOF
i=0
while [ "$i" -lt "$n_funcs" ]; do
  func_sym="f_${i}"
  echo "${func_sym}() +" >> main.c
  echo "int ${func_sym}(void);" >> funcs.h
  cat <<EOF >"${func_sym}.c"
#include "ints.h"

int ${func_sym}(void) {
#include "int_sum.h"
}
EOF
  i=$((i + 1))
done
cat <<EOF >>main.c
1;
}
EOF

# Generate *.o
ls | grep -E '\.c$' | parallel --halt now,fail=1 -t --will-cite "gcc $cflags -c -o '{.}.o' '{}'"

GitHub aguas arriba .

Tenga en cuenta que la generación del archivo objeto puede ser bastante lenta, ya que cada archivo C puede ser bastante grande.

Dada una entrada de tipo:

./generate-objects [n_int_files [n_ints_per_file [n_funcs]]]

genera:

C Principal

#include "funcs.h"

int main(void) {
    return f_0() + f_1() + ... + f_<n_funcs>();
}

f_0.c, f_1.c, ..., f_<n_funcs>.c

extern unsigned int i_0_0;
extern unsigned int i_0_1;
...
extern unsigned int i_1_0;
extern unsigned int i_1_1;
...
extern unsigned int i_<n_int_files>_<n_ints_per_file>;

int f_0(void) {
    return
    i_0_0 +
    i_0_1 +
    ...
    i_1_0 +
    i_1_1 +
    ...
    i_<n_int_files>_<n_ints_per_file>
}

0.c, 1.c, ..., <n_int_files>.c

unsigned int i_0_0 = 0;
unsigned int i_0_1 = 0;
...
unsigned int i_0_<n_ints_per_file> = 0;

lo que lleva a:

n_int_files x n_ints_per_file x n_funcs

reubicaciones en el enlace.

Luego comparé:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic               -o main *.o
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -fuse-ld=gold -Wl,--threads -Wl,--thread-count=`nproc` -o main *.o
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -fuse-ld=lld  -o main *.o

Algunos límites que he intentado mitigar al seleccionar los parámetros de prueba:

  • en archivos de 100k C, ambos métodos obtienen mallocs fallidos ocasionalmente
  • GCC no puede compilar una función con adiciones de 1M

También he observado un 2x en la compilación de depuración de gem5: https://gem5.googlesource.com/public/gem5/+/fafe4e80b76e93e3d0d05797904c19928587f5b5

Pregunta similar: /unix/545699/what-is-the-gold-linker

Puntos de referencia de Phoronix

Phoronix realizó algunas evaluaciones comparativas en 2017 para algunos proyectos del mundo real, pero para los proyectos que examinaron, las ganancias de oro no fueron tan significativas: https://www.phoronix.com/scan.php?page=article&item=lld4-linux-tests&num = 2 ( archivo ).

Incompatibilidades conocidas

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente