有没有人尝试使用gold
而不是ld
?
gold
承诺比 快得多ld
,因此它可能有助于加快大型 C++ 应用程序的测试周期,但它可以用作 ld 的替代品吗?
可以gcc
/g++
直接调用gold
.?
是否有任何已知的错误或问题?
虽然gold
一段时间以来它是 GNU binutils 的一部分,但我在 Web 中几乎没有发现“成功故事”甚至“Howtos”。
(更新:添加了指向黄金的链接和解释它的博客条目)
目前它正在 Ubuntu 10.04 上编译更大的项目。在这里,您可以轻松地安装它并将其与binutils-gold
软件包集成(如果您删除该软件包,您将获得旧的ld
. Gcc 将自动使用黄金。
一些经验:
/usr/local/lib
什么不起作用:它不能编译内核的东西,因此没有内核模块。如果 Ubuntu 更新了 fglrx 等专有驱动程序,它会通过 DKMS 自动执行此操作。这失败了ld-gold
(你必须删除黄金,重新启动 DKMS,重新安装ld-gold
.
由于我花了一些时间来找出如何选择性地使用黄金(即不是使用符号链接在系统范围内),我将在此处发布解决方案。它基于http://code.google.com/p/chromium/wiki/LinuxFasterBuilds#Linking_using_gold。
~/bin/gold/
.将以下胶水脚本放在那里并命名~/bin/gold/ld
:
#!/bin/bash
gold "$@"
显然,使其可执行,chmod a+x ~/bin/gold/ld
.
更改gcc
对gcc -B$HOME/bin/gold
which 的调用,使 gcc 在给定目录中查找帮助程序ld
,因此使用胶水脚本而不是 system-default ld
。
gcc/g++可以直接调用gold吗?
只是为了补充答案:有一个 gcc 选项-fuse-ld=gold
(请参阅gcc doc)。虽然,AFAIK,可以在构建过程中配置 gcc,使该选项不会产生任何影响。
最小综合基准:LD vs Gold vs LLVM LLD
结果:
-Wl,--threads -Wl,--thread-count=$(nproc)
启用多线程时尝试过的所有值, gold大约快 3 到 4 倍测试:
sudo apt install lld
LLD 10基准参数的简化说明:
不同基准参数的结果:
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' '{}'"
请注意,目标文件的生成可能非常缓慢,因为每个 C 文件都可能非常大。
给定一个类型的输入:
./generate-objects [n_int_files [n_ints_per_file [n_funcs]]]
它生成:
主程序
#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
在选择测试参数时,我一直试图减轻一些限制:
我还在 gem5 的调试版本中观察到了 2 倍: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/,他们给出了一些知名项目的构建时间。结果与我的综合基准相似。不幸的是,没有给出项目/链接器版本。在他们的结果中:
他们评论说:
这是具有 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
作为一名 Samba 开发人员,从现在开始,我几乎只在 Ubuntu、Debian 和 Fedora 上使用黄金链接器。我的评价:
我没有选择性地使用黄金,但如果发行版提供的话,我一直在使用符号链接或替代机制。
您可以链接ld
到(如果您已安装以避免覆盖gold
,则在本地二进制目录中):ld
ln -s `which gold` ~/bin/ld
或者
ln -s `which gold` /usr/local/bin/ld
一些项目似乎与黄金不兼容,因为 ld 和黄金之间存在一些不兼容的差异。示例:OpenFOAM,参见http://www.openfoam.org/mantisbt/view.php?id=685。
DragonFlyBSD 切换到黄金作为他们的默认链接器。所以它似乎已经为各种工具做好了准备。
更多详情:
http ://phoronix.com/scan.php?page=news_item&px=DragonFlyBSD-Gold-Linker