Ld durch Gold ersetzen - Erfahrung?

81

Hat jemand versucht, goldstatt zu verwenden ld?

gold verspricht viel schneller zu sein als ld, so dass es helfen kann, Testzyklen für große C ++ - Anwendungen zu beschleunigen, aber kann es als Ersatz für ld verwendet werden?

Kann gcc/ g++direkt anrufen gold.?

Gibt es bekannte Fehler oder Probleme?

Obwohl goldes seit einiger Zeit Teil der GNU-Binutils ist, habe ich im Web fast keine "Erfolgsgeschichten" oder gar "Howtos" gefunden.

( Update: Links zu Gold und Blogeintrag hinzugefügt, um dies zu erklären )

IanH
quelle

Antworten:

53

Momentan werden größere Projekte unter Ubuntu 10.04 kompiliert. Hier können Sie es einfach installieren und in das binutils-goldPaket integrieren (wenn Sie dieses Paket entfernen, erhalten Sie Ihr altes ld). Gcc verwendet dann automatisch Gold.

Einige Erfahrungen:

  • Gold sucht nicht ein /usr/local/lib
  • Gold geht nicht davon aus, dass Bibliotheken wie pthread oder rt von Hand hinzugefügt werden mussten
  • es ist schneller und benötigt weniger Speicher (letzteres ist wichtig bei großen C ++ - Projekten mit viel Schub usw.)

Was nicht funktioniert: Es kann kein Kernel-Zeug kompilieren und daher keine Kernel-Module. Ubuntu führt dies automatisch über DKMS durch, wenn proprietäre Treiber wie fglrx aktualisiert werden. Dies schlägt fehl mit ld-gold(Sie müssen Gold entfernen, DKMS neu starten, neu installieren ld-gold.

nob
quelle
Danke, ich denke, ich werde es versuchen - die Einschränkungen, die Sie erwähnen, scheinen in meinem Fall kein Problem zu sein.
IanH
+1: Danke für den Erfahrungsaustausch. Was ist mit der Leistung?
Neuro
9
Es ist erheblich schneller, insbesondere beim Verknüpfen großer statischer Bibliotheken mit einer Binärdatei, aber wir haben keine Messungen schwierig gemacht.
nob
2
@neuro Meine Messungen betrafen das Verknüpfen vieler Objekte und .a-Dateien zu einem Satz von ~ 30 .so-Dateien (eine größere, die andere kleine) und eine ausführbare Datei für eine bedeutende kommerzielle Anwendung. Ich habe nur die Verbindungszeit gemessen und make in Serie ausgeführt. Ich habe eine Gesamtzeit von 22,48 Sekunden mit ld gegenüber 16,24 Sekunden mit Gold erhalten, was einer Verbesserung von 6,24 Sekunden pro Build entspricht. Wenn ich jedoch make parallel zu 8 Prozessoren ausführe, beträgt der Gesamtunterschied nur 1,42 Sekunden pro Build. Die Gesamtspeicherauslastung verbesserte sich unabhängig von der Parallelisierung um 42%. YMMV.
Metall
@metal: vielen dank für die zahlen. Die Verbesserung der Speichernutzung sieht gut aus, ldist so gierig darauf.
Neuro
40

Da ich eine Weile gebraucht habe, um herauszufinden, wie man Gold selektiv verwendet (dh nicht systemweit über einen Symlink), werde ich die Lösung hier veröffentlichen. Es basiert auf http://code.google.com/p/chromium/wiki/LinuxFasterBuilds#Linking_using_gold .

  1. Erstellen Sie ein Verzeichnis, in das Sie ein Goldleim-Skript einfügen können. Ich benutze ~/bin/gold/.
  2. Legen Sie das folgende Klebeskript dort ab und benennen Sie es ~/bin/gold/ld:

    #!/bin/bash
    gold "$@"
    

    Machen Sie es natürlich ausführbar chmod a+x ~/bin/gold/ld.

  3. Ändern Sie Ihre Aufrufe, gccin gcc -B$HOME/bin/golddie gcc im angegebenen Verzeichnis nach Hilfsprogrammen wie sucht, ldund verwenden Sie daher das Klebeskript anstelle des Systemstandards ld.

Tilman Vogel
quelle
1
Das wird für welches Betriebssystem benötigt? Wie Nob in seiner Antwort sagte, installieren Sie für Ubuntu einfach das goldene binutils-Paket und der Compiler wird es sofort verwenden. Gleiches gilt für openSuse.
usr1234567
7
Ja, es ist ziemlich einfach, ld systemweit zu ersetzen. Meine Antwort war besonders darauf ausgerichtet, wie man Gold selektiv einsetzt. Und in diesem Fall denke ich, ist es für jedes Betriebssystem notwendig.
Tilman Vogel
1
@vidstige Ja, der Vorteil des Skripts ist , dass es für schaut goldauf dem PATH. Für einen Symlink müssen Sie auf den vollständigen Pfad verweisen.
Tilman Vogel
17

Kann gcc / g ++ Gold direkt aufrufen?

Nur um die Antworten zu ergänzen: Es gibt eine gcc-Option -fuse-ld=gold(siehe gcc-Dokument ). AFAIK ist es jedoch möglich, gcc während des Builds so zu konfigurieren, dass die Option keine Auswirkungen hat.

user2273896
quelle
5
-fuse-ld=goldIst nicht vollständig. Wenn Sie verwenden müssen, -Wl,-fuse-ld=goldwie es zur Link-Zeit verwendet wird.
Nawaz
5
@Nawaz Nein, -Wl,wird verwendet, um eine Option direkt an zu übergeben ld. Um einen anderen Linker zu verwenden, müssen Sie dies mitteilen gcc. Bitte beziehen Sie sich auf das Dokument .
Calandoa
11

Als Samba-Entwickler verwende ich den Gold-Linker seit einigen Jahren fast ausschließlich unter Ubuntu, Debian und Fedora. Meine Einschätzung:

  • Gold ist um ein Vielfaches (Filz: 5-10 Mal) schneller als der klassische Linker.
  • Anfangs gab es ein paar Probleme, aber die sind seit ungefähr Ubuntu 12.04 weg.
  • Der Goldlinker hat sogar einige Abhängigkeitsprobleme in unserem Code gefunden, da er in einigen Details korrekter zu sein scheint als der klassische. Siehe zB dieses Samba-Commit .

Ich habe Gold nicht selektiv verwendet, sondern Symlinks oder den alternativen Mechanismus verwendet, wenn die Distribution dies vorsieht.

Michael Adam
quelle
9

Sie könnten einen Link ldzu gold(in einem lokalen Binärverzeichnis, wenn Sie ldinstalliert haben, um ein Überschreiben zu vermeiden):

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

oder

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

Minimaler synthetischer Benchmark: LD vs Gold vs LLVM LLD

Ergebnis:

  • Gold war für alle Werte, die ich bei -Wl,--threads -Wl,--thread-count=$(nproc)der Aktivierung von Multithreading ausprobiert habe, etwa 3x bis 4x schneller
  • LLD war ungefähr 2x schneller als Gold!

Getestet am:

  • Ubuntu 20.04, GCC 9.3.0, binutils 2.34, sudo apt install lldLLD 10
  • Lenovo ThinkPad P51-Laptop, Intel Core i7-7820HQ-CPU (4 Kerne / 8 Threads), 2x Samsung M471A2K43BB1-CRC-RAM (2x 16 GB), Samsung MZVLB512HAJQ-000L7 SSD (3.000 MB / s).

Vereinfachte Beschreibung der Benchmark-Parameter:

  • 1: Anzahl der Objektdateien mit Symbolen
  • 2: Anzahl der Symbole pro Symbolanbieter-Objektdatei
  • 3: Anzahl der Objektdateien unter Verwendung aller bereitgestellten Symbolsymbole

Ergebnisse für verschiedene Benchmark-Parameter:

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

Dies ist das Skript, das alle Objekte für die Verknüpfungstests generiert:

Objekte generieren

#!/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 stromaufwärts .

Beachten Sie, dass die Generierung von Objektdateien sehr langsam sein kann, da jede C-Datei sehr groß sein kann.

Bei einer Eingabe vom Typ:

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

es erzeugt:

Haupt c

#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;

was dazu führt:

n_int_files x n_ints_per_file x n_funcs

Umzüge auf den Link.

Dann habe ich verglichen:

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

Einige Grenzen, die ich bei der Auswahl der Testparameter zu verringern versucht habe:

  • Bei 100k C-Dateien erhalten beide Methoden gelegentlich fehlgeschlagene Mallocs
  • GCC kann keine Funktion mit 1M-Ergänzungen kompilieren

Ich habe auch ein 2x im Debug-Build von gem5 beobachtet: https://gem5.googlesource.com/public/gem5/+/fafe4e80b76e93e3d0d05797904c19928587f5b5

Ähnliche Frage: /unix/545699/what-is-the-gold-linker

Phoronix-Benchmarks

Phoronix führte 2017 einige Benchmarking-Tests für einige Projekte der realen Welt durch, aber für die untersuchten Projekte waren die Goldgewinne nicht so signifikant: https://www.phoronix.com/scan.php?page=article&item=lld4-linux-tests&num = 2 ( Archiv ).

Bekannte Inkompatibilitäten

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