Заміна ld золотом - будь-який досвід?


81

Хтось намагався використовувати goldзамість ld?

gold обіцяє бути набагато швидшим, ніж ld, тому це може допомогти прискорити тестові цикли для великих програм C ++, але чи можна використовувати його як заміну для ld?

Можна gcc/ g++безпосередньо зателефонувати gold.?

Чи є якісь відомі помилки чи проблеми?

Незважаючи goldна те, що з певного часу він є частиною Binutils GNU, я майже не знайшов "історій успіху" і навіть "Howtos" в Мережі.

( Оновлення: додано посилання на золото та запис у блозі, що пояснює це )

Відповіді:


53

На даний момент він займається компіляцією більших проектів на Ubuntu 10.04. Тут ви можете легко встановити та інтегрувати його з binutils-goldпакетом (якщо ви видалите цей пакет, ви отримаєте свій старий ld). Тоді Gcc автоматично використовуватиме золото.

Деякі враження:

  • золото не шукає в /usr/local/lib
  • золото не припускає бібліотеки, такі як pthread або rt, доводилося додавати їх вручну
  • він швидший і потребує менше пам'яті (остання важлива для великих проектів на C ++ з великим імпульсом тощо)

Що не працює: він не може компілювати матеріали ядра, а отже, і модулі ядра. Ubuntu робить це автоматично через DKMS, якщо оновлює власні драйвери, такі як fglrx. Це не вдається з ld-gold(вам потрібно видалити золото, перезапустити DKMS, перевстановити ld-gold.


Дякую, я спробую спробувати - обмеження, про які ви згадали, у моєму випадку не становлять жодної проблеми.
IanH

+1: дякую за обмін досвідом. А як щодо продуктивності?
нейро

9
це значно швидше, особливо при з'єднанні величезних статичних бібліотек з одним двійковим файлом, але ми не робили жодних жорстких вимірювань.
nob

2
@neuro Мої вимірювання стосувались об’єднання багатьох об’єктів та .a-файлів у набір із ~ 30 .so-файлів (один великий, решта невеликий) та 1 виконуваний файл для значного комерційного додатка. Вимірюючи лише час зв'язку та запущений серійний, я отримав загальний час 22,48 сек при ld проти 16,24 сек при золоті, для поліпшення 6,24 сек за побудову. Однак, якщо я запускаю make паралельно з 8 процесорами, загальна різниця складає лише 1,42 сек на побудову. Загальне використання пам'яті було поліпшено на 42%, незалежно від паралелізації. YMMV.
метал

@metal: велике спасибі за цифри. Покращення використання пам'яті виглядає чудово, ldтак жадібно до цього.
невро

40

Оскільки мені знадобилося трохи часу, щоб з’ясувати, як вибірково використовувати золото (тобто не загальносистемне за допомогою символічного посилання), я опублікую рішення тут. Він базується на http://code.google.com/p/chromium/wiki/LinuxFasterBuilds#Linking_using_gold .

  1. Складіть каталог, куди можна помістити золотий сценарій клею. Я використовую ~/bin/gold/.
  2. Помістіть наступний сценарій клею і назвіть його ~/bin/gold/ld:

    #!/bin/bash
    gold "$@"
    

    Очевидно, що зробити його виконуваним chmod a+x ~/bin/gold/ld.

  3. Змініть виклики gccна gcc -B$HOME/bin/goldякий вдає GCC в даному каталозі для допоміжних програм , як ldі , таким чином , використовує клей скрипт замість системного замовчуванням ld.


1
Що потрібно для якої операційної системи? Як сказав nob у своїй відповіді, для Ubuntu просто встановіть золотий пакет binutils, і компілятор використає його відразу. Те саме для openSuse.
usr1234567

8
Так, замінити ld загальносистемно досить просто. Моя відповідь була спрямована на те, як вибірково використовувати золото. І в такому випадку, я думаю, це потрібно для будь-якої ОС.
Тілман Фогель

1
@vidstige Так, перевага сценарію полягає в тому, що він шукає goldна PATH. Для символьного посилання потрібно вказати повний шлях.
Тілман Фогель

18

Чи може gcc / g ++ безпосередньо викликати золото.?

Тільки для доповнення відповідей: є варіант gcc-fuse-ld=gold (див. Gcc doc ). Хоча, AFAIK, можна налаштувати gcc під час побудови таким чином, що параметр не матиме жодного ефекту.


5
-fuse-ld=goldне є повною. Якщо вам доведеться використовувати так, -Wl,-fuse-ld=goldяк це використовується під час посилання.
Nawaz

6
@Nawaz No, -Wl,використовується для передачі опції безпосередньо ld; щоб використовувати інший компонувальник, вам потрібно це повідомити gcc. Зверніться до документації .
calandoa

11

Як розробник Samba, я вже кілька років використовую золотий компонувальник майже виключно в Ubuntu, Debian та Fedora. Моя оцінка:

  • золото в рази (відчувається: в 5-10 разів) швидше, ніж класичний лінкер.
  • Спочатку було кілька проблем, але вони пішли приблизно з Ubuntu 12.04.
  • Золотий компонувальник навіть знайшов деякі проблеми залежності в нашому коді, оскільки він здається більш правильним, ніж класичний, щодо деяких деталей. Дивіться, наприклад, цей коміт Samba .

Я не використовував золото вибірково, але використовував символічні посилання або альтернативний механізм, якщо розподіл це забезпечує.


9

Ви можете зробити посилання ldна gold(у локальному двійковому каталозі, якщо ви ldвстановили, щоб уникнути перезапису):

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

або

ln -s `which gold` /usr/local/bin/ld

6

Мінімальний синтетичний орієнтир: LD проти золота проти LLVM LLD

Результат:

  • золото було приблизно в 3 рази до чотирьох швидше для всіх значень, які я намагався використовувати, -Wl,--threads -Wl,--thread-count=$(nproc)щоб увімкнути багатопоточність
  • LLD був приблизно вдвічі швидший за золото!

Перевірено на:

  • Ubuntu 20.04, GCC 9.3.0, binutils 2.34, sudo apt install lldLLD 10
  • Ноутбук Lenovo ThinkPad P51, процесор Intel Core i7-7820HQ (4 ядра / 8 потоків), 2x оперативної пам'яті Samsung M471A2K43BB1-CRC (2x 16GiB), твердотільний диск Samsung MZVLB512HAJQ-000L7 (3000 МБ / с).

Спрощений опис базових параметрів:

  • 1: кількість об'єктних файлів із символами
  • 2: кількість символів у файлі об’єкта постачальника символів
  • 3: кількість об'єктних файлів з використанням усіх наданих символів

Результати для різних параметрів тесту:

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

Це сценарій, який генерує всі об’єкти для тестів посилань:

генерувати об’єкти

#!/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 вгору за течією .

Зверніть увагу, що генерація об’єктного файлу може бути досить повільною, оскільки кожен C-файл може бути досить великим.

Дано введення типу:

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

це генерує:

main.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;

що призводить до:

n_int_files x n_ints_per_file x n_funcs

переїзди за посиланням.

Потім я порівняв:

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

Деякі обмеження, які я намагався зменшити при виборі параметрів тесту:

  • у файлах 100k C обидва методи час від часу отримують невдалі несправності
  • GCC не може скомпілювати функцію з 1M доповнень

Я також спостерігав 2x у збірці налагодження gem5: https://gem5.googlesource.com/public/gem5/+/fafe4e80b76e93e3d0d05797904c19928587f5b5

Подібне запитання: /unix/545699/what-is-the-gold-linker

Тести Phoronix

У 2017 році Phoronix здійснив порівняльний аналіз деяких реальних проектів, але для проектів, які вони досліджували, приріст золота був не таким значним: https://www.phoronix.com/scan.php?page=article&item=lld4-linux-tests&num = 2 ( архів ).

Відома несумісність

Тести LLD

За адресою https://lld.llvm.org/ вони дають розклади для кількох відомих проектів. з результатами, подібними до моїх синтетичних тестів. Версії проекту / компонувальника, на жаль, не наводяться. У їх результатах:

  • золото було приблизно в 3 рази / чотири швидше, ніж ЛД
  • LLD був в 3 рази / чотири швидший за золото, тож більший пришвидшення, ніж у моєму синтетичному тесті

Вони коментують:

Це порівняння часу зв'язку на 2-розетковому 20-ядерному 40-потоковому апараті Xeon E5-2680 2,80 ГГц з накопичувачем SSD. Ми запускали золото та lld з підтримкою багатопоточності або без неї. Щоб вимкнути багатопоточність, ми додали -no-thread до командного рядка.

і результати виглядають так:

Program      | Size     | GNU ld  | gold -j1 | gold    | lld -j1 |    lld
-------------|----------|---------|----------|---------|---------|-------
  ffmpeg dbg |   92 MiB |   1.72s |   1.16s  |   1.01s |   0.60s |  0.35s
  mysqld dbg |  154 MiB |   8.50s |   2.96s  |   2.68s |   1.06s |  0.68s
   clang dbg | 1.67 GiB | 104.03s |  34.18s  |  23.49s |  14.82s |  5.28s
chromium dbg | 1.14 GiB | 209.05s |  64.70s  |  60.82s |  27.60s | 16.70s

1
Я можу підтвердити ваші висновки, я бачу подібний пришвидшення для зв’язування своїх проектів. Дивіться також орієнтири тут lld.llvm.org
ypnos


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.