【问题标题】:Why are binaries built with gccgo smaller (among other differences?)为什么使用 gccgo 构建的二进制文件更小(以及其他差异?)
【发布时间】:2014-11-21 17:35:37
【问题描述】:

我一直在试验 gc 和 gccgo,但遇到了一些奇怪的行为。

使用我曾经写过的program 来测试一些定理,我得到了以下结果:(为了可读性,我删除了不必要的信息)

$ time go build -compiler gc -o checkprog_gc checkprog.go (x 3)
go build <...>    0.13s user 0.02s system 100% cpu 0.149 total
go build <...>    0.13s user 0.01s system 99%  cpu 0.148 total
go build <...>    0.14s user 0.03s system 100% cpu 0.162 total
 --> average:     0.13s user 0.02s system 100% cpu 0.153 total


$ time go build -compiler gccgo -o checkprog_gccgo checkprog.go (x 3)
go build <...>    0.10s user 0.03s system 96% cpu 0.135 total
go build <...>    0.12s user 0.01s system 96% cpu 0.131 total
go build <...>    0.10s user 0.01s system 92% cpu 0.123 total
 --> average:     0.11s user 0.02s system 95% cpu 0.130 total


$ strip -s -o checkprog_gc_stripped checkprog_gc
$ strip -s -o checkprog_gccgo_stripped checkprog_gccgo

$ ls -l
 1834504 checkprog_gc*
 1336992 checkprog_gc_stripped*
   35072 checkprog_gccgo*
   24192 checkprog_gccgo_stripped*

$ time ./checkprog_gc
./checkprog_gc  6.68s user 0.01s system 100% cpu 6.674 total
./checkprog_gc  6.75s user 0.01s system 100% cpu 6.741 total
./checkprog_gc  6.66s user 0.00s system 100% cpu 6.643 total
 --> average:   6.70s user 0.01s system 100% cpu 6.686 total

$ time ./checkprog_gccgo
./checkprog_gccgo  10.95s user 0.02s system 100% cpu 10.949 total
./checkprog_gccgo  10.98s user 0.01s system 100% cpu 10.964 total
./checkprog_gccgo  10.94s user 0.01s system 100% cpu 10.929 total
 --> average       10.96s user 0.01s system 100% cpu 10.947 total

我可以看到以下模式:

  1. 使用gccgo 构建的二进制文件的大小要小得多(剥离无助于改变这种差异)
  2. 使用gc 构建的二进制文件执行速度更快
  3. 使用gccgo 构建比使用gc 需要更多时间

我还测试了其他一些 go 程序(虽然没有那么广泛),它们都表现出相同的行为。

这似乎与this answer 所说的相矛盾:

简而言之:gccgo:更多优化,更多处理器。

我认为更多的优化意味着更快的二进制文件,同时需要更多的时间来编译...

这三种模式的原因是什么?

【问题讨论】:

  • 很可能是因为它们链接到libgolddreadelf 会告诉你(如果你在 Linux 系统上)。

标签: go gccgo


【解决方案1】:

有一堆不同--bradfitz talked about some of them in a May 2014 talk:

  • gccgo 可以生成动态链接到libgo 的二进制文件,这使得输出更小,但意味着要在目标机器上安装相关库。没有cgo 的 Go 二进制文件没有这个要求。
  • gccgo 做了更多的低级优化,因为它可以使用gcc 的代码生成器和优化器。编写一些数据压缩代码,gccgo 的运行速度明显快于gc。这些相同的优化使编译器变慢:它正在做更多的工作。
  • gccgo 支持gcc 所支持的目标处理器,因此这是进入某些架构(如 SPARC、ARMv8(64 位)或 POWER)的唯一方法。 (Canonical 使用它为 arm64 和 ppc64 编译 Juju 服务编排工具。)
  • gccgogc 都支持 ARMv7(32 位),但根据 bradfitz 的谈话,gc 不会生成最高效的 ARM 代码。
  • 只有gc 有某些优化。
    • 一个很大的例子是escape analysis,其中编译器确定某些变量永远不会“转义”分配它们的函数,因此可以进行堆栈分配。 (因此,令人惊讶的是,new(T) 如果其返回值没有转义,则可能不会进行堆分配。)这减少了垃圾收集需要运行的频率。
    • 另一个是标准库中的.s 汇编文件仅由gc 链接,因此gccgo 默认情况下不使用英特尔硬件CRC32C 之类的东西(您必须提供实现专门用于 gccgo)。
  • gc 首先实现了新的语言功能,并且通常比最新的 gccgo 领先一个或两个 Go 次要版本。

【讨论】:

  • (制作这个 CW,因为关于 gc/gccgo 的差异可能有很多话要说,我不是真正的专家,我希望知道更多的人来编辑它。)
【解决方案2】:

大小不同,因为 gc 生成静态二进制文件,并且 gccgo 链接到 libgo。这意味着整个运行时(调度程序、垃圾收集器、映射、通道)的代码不在 gccgo 创建的最终二进制文件中。

编译速度当然有利于gc。 GC 的构建考虑了编译速度。它通常还会生成较少优化的代码,并且需要执行的工作较少。

现在谈谈为什么 gc 仍然更快。事实是,他们中的任何一个都不总是比另一个快。例如,尝试 md5 一个文件,GCCGO 会快一个数量级。尝试用很多渠道实现一些东西,gc 肯定会赢。你不能总是提前知道哪个会成功。 GC 往往具有更高效的并发性,而 gccgo 往往更擅长数学。但是,您需要根据具体情况进行测试。最好使用 go test 的基准测试系统,而不是时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-18
    • 2013-01-16
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    相关资源
    最近更新 更多