用黄金取代ld - 有经验吗?

Ian*_*anH 79 c c++ migration linker gold-linker

有人试过用gold而不是ld吗?

gold 承诺要快得多ld,所以它可能有助于加快大型C++应用程序的测试周期,但是它可以用作ld的替代品吗?

可以gcc/ g++直接打电话gold.?

有没有知道错误或问题?

虽然gold有一段时间是GNU binutils的一部分,但我发现Web上几乎没有"成功案例"甚至"Howtos".

(更新:添加了黄金和博客条目的链接解释它)

nob*_*nob 52

目前它正在Ubuntu 10.04上编译更大的项目.在这里,您可以轻松地将其与binutils-gold软件包一起安装和集成(如果您删除该软件包,则可以使用旧软件包ld).Gcc会自动使用黄金.

一些经验:

  • 黄金不搜索 /usr/local/lib
  • 黄金不承担像pthread或rt这样的库,不得不手工添加它们
  • 它更快,需要更少的内存(后者对于大型C++项目很重要,并且有很多提升等)

什么不起作用:它无法编译内核的东西,因此没有内核模块.如果它更新像fglrx这样的专有驱动程序,Ubuntu会通过DKMS自动执行此操作.这失败了ld-gold(你必须删除黄金,重启DKMS,重新安装ld-gold.

  • 它明显更快,特别是在将巨大的静态库链接到一个二进制文件时,但我们没有做任何严格的测量. (9认同)
  • @neuro我的测量是将许多对象和.a文件链接到一组约30个.so文件中(一个较大,其余很小)和一个可执行的大型商业应用程序。仅测量链接时间和串行运行时间,使用ld的总时间为22.48秒,使用金色的总时间为16.24秒,每次构建的时间为6.24秒。但是,如果我与8个处理器并行运行make,则每次构建的总差异仅为1.42秒。无论进行并行化如何,总体内存使用量均提高了42%。YMMV。 (2认同)

Til*_*gel 39

由于我花了一些时间来了解如何有选择地使用黄金(即不使用符号链接在系统范围内),我将在此处发布解决方案.它基于http://code.google.com/p/chromium/wiki/LinuxFasterBuilds#Linking_using_gold.

  1. 创建一个可以放置金胶脚本的目录.我在用~/bin/gold/.
  2. 将以下胶水脚本放在那里并命名~/bin/gold/ld:

    #!/bin/bash
    gold "$@"
    
    Run Code Online (Sandbox Code Playgroud)

    显然,让它可执行,chmod a+x ~/bin/gold/ld.

  3. 将您的调用更改gccgcc -B$HOME/bin/gold使gcc在给定目录中查找辅助程序的调用ld,从而使用glue脚本而不是system-default ld.

  • 是的,在系统范围内更换ld非常容易.我的回答特别针对如何有选择地使用黄金.在这种情况下,我认为,任何操作系统都是必要的. (7认同)

use*_*896 16

gcc/g ++可以直接调用gold.

只是为了补充答案:有一个gcc的选项-fuse-ld=gold(参见gcc doc).虽然,AFAIK,可以在构建过程中以一种选项不会产生任何影响的方式配置gcc.

  • @Nawaz 不,“-Wl,”用于将选项直接传递给“ld”;要使用另一个链接器,您需要将其告诉“gcc”。请参阅[文档](https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html)。 (7认同)
  • `-fuse-ld = gold`不完整.如果你必须在链接时使用`-Wl,-fuse-ld = gold`. (5认同)

Mic*_*dam 11

作为一名Samba开发人员,几年来我几乎专门在Ubuntu,Debian和Fedora上使用黄金链接器.我的评估:

  • 金比经典接头快许多倍(感觉:5-10倍).
  • 最初,有一些问题,但大致从Ubuntu 12.04开始.
  • 黄金链接器甚至在我们的代码中发现了一些依赖性问题,因为它在某些细节方面似乎比经典的更正确.请参阅,例如此Samba提交.

我没有选择性地使用黄金,但是如果分发提供它,则一直在使用符号链接或替代机制.


Del*_*ani 9

您可以链接ldgold(在本地二进制目录中,如果已ld安装以避免覆盖):

ln -s `which gold` ~/bin/ld
Run Code Online (Sandbox Code Playgroud)

要么

ln -s `which gold` /usr/local/bin/ld
Run Code Online (Sandbox Code Playgroud)


Cir*_*四事件 9

最小综合基准:LD vs gold vs LLVM LLD

结果:

  • 对于我在-Wl,--threads -Wl,--thread-count=$(nproc)启用多线程时尝试过的所有值,gold大约快 3 到 4 倍
  • LLD大约比黄金快 2 倍!

测试:

  • Ubuntu 20.04、GCC 9.3.0、binutils 2.34、sudo apt install lldLLD 10
  • 联想 ThinkPad P51 笔记本电脑、英特尔酷睿 i7-7820HQ CPU(4 核/8 线程)、2x 三星 M471A2K43BB1-CRC RAM(2x 16GiB)、三星 MZVLB512HAJQ-000L7 SSD(3,000 MB/s)。

基准参数的简化说明:

  • 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
Run Code Online (Sandbox Code Playgroud)

这是为链接测试生成所有对象的脚本:

生成对象

#!/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' '{}'"
Run Code Online (Sandbox Code Playgroud)

GitHub 上游.

请注意,目标文件的生成可能非常慢,因为每个 C 文件都可能非常大。

给定类型的输入:

./generate-objects [n_int_files [n_ints_per_file [n_funcs]]]
Run Code Online (Sandbox Code Playgroud)

它产生:

主文件

#include "funcs.h"

int main(void) {
    return f_0() + f_1() + ... + f_<n_funcs>();
}
Run Code Online (Sandbox Code Playgroud)

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>
}
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

这导致:

n_int_files x n_ints_per_file x n_funcs
Run Code Online (Sandbox Code Playgroud)

链接上的重定位

然后我比较了:

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
Run Code Online (Sandbox Code Playgroud)

在选择测试参数时,我一直试图减轻一些限制:

  • 在 100k C 文件中,这两种方法偶尔都会失败 malloc
  • GCC 无法编译具有 1M 附加值的函数

我还在 gem5 的调试版本中观察到 2x:https ://gem5.googlesource.com/public/gem5/+/fafe4e80b76e93e3d0d05797904c19928587f5b5

类似问题:https : //unix.stackexchange.com/questions/545699/what-is-the-gold-linker

Phoronix 基准测试

Phoronix 在 2017 年为一些现实世界的项目做了一些基准测试,但对于他们检查的项目,金牌收益并不那么显着:https ://www.phoronix.com/scan.php?page=article&item=lld4-linux-tests&num =2存档)。

已知的不兼容性

LLD 基准

https://lld.llvm.org/他们给出了一些知名项目的构建时间。与我的综合基准测试结果相似。不幸的是,没有给出项目/链接器版本。在他们的结果中:

  • 黄金比 LD 快大约 3 倍/4 倍
  • LLD 比黄金快 3 倍/4 倍,因此比我的综合基准测试有更大的加速

他们评论:

这是在带有 SSD 驱动器的 2 插槽 20 核 40 线程 Xeon E5-2680 2.80 GHz 机器上的链接时间比较。我们在有或没有多线程支持的情况下运行 gold 和 lld。为了禁用多线程,我们在命令行中添加了 -no-threads。

结果如下:

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
Run Code Online (Sandbox Code Playgroud)