Заміна 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.