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

时间:2010-08-13 10:46:12

标签: c++ c linker migration gold-linker

是否有人尝试使用gold代替ld

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

可以gcc / g++直接拨打gold。?

是否有任何已知的错误或问题?

尽管gold已经成为GNU binutils的一部分,但我在网上几乎找不到“成功案例”甚至“Howtos”。

更新:添加了指向黄金和博客条目的链接

8 个答案:

答案 0 :(得分:47)

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

一些经历:

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

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

答案 1 :(得分:38)

由于我花了一些时间来了解如何有选择地使用黄金(即使用符号链接不是系统范围内),我将在此处发布解决方案。它基于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. 将您的调用更改为gccgcc -B$HOME/bin/gold,这使得gcc在给定目录中查找辅助程序,如ld,从而使用粘合脚本而不是系统默认ld

答案 2 :(得分:11)

  

gcc / g ++可以直接调用gold。?

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

答案 3 :(得分:8)

您可以将ld链接到gold(如果您安装了ld,则在本地二进制目录中链接以避免覆盖):

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

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

答案 4 :(得分:7)

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

  • 黄金比经典链接器快多倍(感觉:5-10倍)。
  • 最初,有一些问题,但大概是Ubuntu 12.04已经消失了。
  • 黄金链接器甚至在我们的代码中发现了一些依赖性问题,因为在某些细节方面它看起来比经典的更正确。见,例如, this Samba commit

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

答案 5 :(得分:2)

有些项目似乎与黄金不相容,因为ld和黄金之间存在一些不相容的差异。示例:OpenFOAM,请参阅docs

答案 6 :(得分:2)

DragonFlyBSD切换到黄金作为默认链接器。所以似乎已经为各种工具做好了准备 更多细节: http://phoronix.com/scan.php?page=news_item&px=DragonFlyBSD-Gold-Linker

答案 7 :(得分:2)

最低综合基准

结果:对于我尝试过的所有值,黄金的速度要快2到3倍。

生成对象

#!/usr/bin/env bash
set -eu

# CLI args.

# Each of those files contains n_ints_per_file ints.
n_int_file_is="${1:-10}"
n_ints_per_file="${2:-10}"

# Each function adds all ints from all files.
# This leads to n_int_file_is 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_file_is" ]; 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 upstream

给出类型为

的输入
./generate-objects [n_int_file_is [n_ints_per_file [n_funcs]]]

这将生成一个主要的功能,

return f_0() + f_1() + ... + f_(n_funcs)()

其中每个函数都在单独的f_n.c文件中定义,并添加n_int_file_isn_ints_per_file extern int:

int f_0() { return i_0_0 + i_0_1 + ... + i_(n_int_file_is)_(n_ints_per_file); }

这导致:

n_int_file_is x n_ints_per_file x n_funcs

relocations上的链接。

然后我进行了比较:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic               -o main *.o
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -fuse-ld=gold -o main *.o

对于各种输入三元组,它给出了:

10000 10 10
nogold: wall=3.70s user=2.93s system=0.75s max_mem=556356kB
gold:   wall=1.43s user=1.15s system=0.28s max_mem=703060kB

1000 100 10
nogold: wall=1.23s user=1.07s system=0.16s max_mem=188152kB
gold:   wall=0.60s user=0.52s system=0.07s max_mem=279108kB

100 1000 10
nogold: wall=0.96s user=0.87s system=0.08s max_mem=149636kB
gold:   wall=0.53s user=0.47s system=0.05s max_mem=231596kB

10000 10 100
nogold: wall=11.63s user=10.31s system=1.25s max_mem=1411264kB
gold:   wall=6.31s user=5.77s system=0.53s max_mem=2146992kB

1000 100 100
nogold: wall=7.19s user=6.56s system=0.60s max_mem=1058432kB
gold:   wall=4.15s user=3.81s system=0.34s max_mem=1697796kB

100 1000 100
nogold: wall=6.15s user=5.58s system=0.57s max_mem=1031372kB
gold:   wall=4.06s user=3.76s system=0.29s max_mem=1652548kB

我一直试图缓解的一些限制:

  • 在10万个C文件中,这两种方法偶尔都会导致失败的malloc
  • GCC无法编译具有1M添加项的函数

已在Ubuntu 18.10,GCC 8.2.0,Lenovo ThinkPad P51笔记本电脑,Intel Core i7-7820HQ CPU(4核/ 8线程),2个Samsung M471A2K43BB1-CRC RAM(2个16GiB),Samsung MZVLB512HAJQ-000L7 SSD(3,000)上进行了测试MB / s)。

在gem5的调试版本中,我还观察到了两倍:https://gem5.googlesource.com/public/gem5/+/fafe4e80b76e93e3d0d05797904c19928587f5b5