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 lld
LLD 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
n_int_files="${1:-10}"
n_ints_per_file="${2:-10}"
n_funcs="${3:-10}"
cflags='-ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic'
./clean
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
rm -f funcs.h
cat <<EOF >main.c
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"
int ${func_sym}(void) {
}
EOF
i=$((i + 1))
done
cat <<EOF >>main.c
1;
}
EOF
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