为什么使用gccgo构建的二进制文件较小(除了其他差异?)

时间:2014-11-21 17:35:37

标签: go gccgo

我一直在尝试使用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
  4. 构建需要更多时间

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

    这似乎与this answer所述的内容相矛盾:

      

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

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

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

2 个答案:

答案 0 :(得分:7)

存在许多差异 - bradfitz talked about some of them in a May 2014 talk

  • gccgo可以生成一个动态链接在libgo中的二进制文件,这会使输出更小,但意味着要在目标计算机上安装相关的库。在没有cgo的情况下使用二进制文件不具备该要求。
  • gccgo执行更多低级优化,因为它可以使用gcc的代码生成器和优化器。编写一些数据压缩代码时,gccgo的运行速度明显快于gc。这些相同的优化使编译器变慢:它做了更多的工作。
  • gccgo支持gcc所做的目标处理器,因此它是获得某些体系结构(如SPARC,ARMv8(64位)或POWER)的唯一方法。 (Canonical使用它为arm64和ppc64编译他们的Juju服务编排工具。)
  • gccgogc都支持ARMv7(32位),但根据bradfitz的说法,gc无法生成最有效的ARM代码。
  • 只有gc有一些优化。
    • 一个大的是escape analysis,其中编译器确定某些变量永远不会逃脱&#34;它们被分配的功能,因此可以进行堆栈分配。 (所以,令人惊讶的是,如果new(T)的返回值没有逃脱,.s可能不会堆分配。)这会减少垃圾收集需要运行的频率。
    • 另一个原因是标准库中的gc汇编程序文件仅由gccgo链接,因此默认情况下gc未使用英特尔硬件CRC32C等某些内容({1}}您必须专门为gccgo提供实施方案。
  • gccgo首先实现了新的语言功能,并且在最新{{1}}之前通常是一个或两个小版本。

答案 1 :(得分:6)

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

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

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